我想通过uniform buffer object
或shader storage buffer object
传递数据并使用glBindBufferRange()
绑定数据。
目前它的编程非常糟糕,因为我更喜欢c ++,而不是c风格,但是我不知道如何将glBindBufferRange()
与c ++风格一起使用。
我有一个结构,其中包含要传递的数据和3个模拟std::vector<>
的变量
struct Uniforms
{
glm::mat4x3 paintMat = glm::mat4x3(1.0f);
Color innerColor = Color(255, 255, 255, 255);
Color outerColor = Color(255, 255, 255, 255);
Vector2<float> extent = 0.0f;
float radius = 0.0f;
float feather = 1.0f;
int type = 0;
};
struct DrawCall
{
//... more stuff that does not affect uniforms
int uniformOffset = 0;
};
struct Context
{
//... more stuff that does not affect uniforms
int AllocUniforms(int n)
{
int ret = 0;
int structSize = fragSize;
if (nuniform + n > cuniform) {
unsigned char* newUniforms;
int newCapacity = Max<int>(nuniform + n, 128) + cuniform / 2;
newUniforms = (unsigned char*)realloc(uniforms, structSize * newCapacity);
if (newUniforms == nullptr)
return -1;
uniforms= newUniforms;
cuniform = newCapacity;
}
ret = nuniform * structSize;
nuniform += n;
return ret;
}
Uniforms* getUnifPtr(int i)
{
return (Uniforms*)&uniforms[i];
}
unsigned char* uniforms = nullptr;
int nuniform = 0;
int cuniform = 0;
int fragSize = 0;
DrawCall drawCall;
};
struct MainStruct
{
void Create()
{
glGenBuffers(1, &ubo);
//Create shaders... it also does not affect unifoms
int align = 4;
glGetIntegerv(GL_UNIFORM_BUFFER, &align);
gl.fragSize = sizeof(Uniforms) + align - sizeof(Uniforms) % align;
}
void SetupUniforms()
{
context.DrawCall.uniformOffset = AllocUniforms(1);
Uniforms* unif = context.getUnifPtr(context.DrawCall.uniformOffset);
unif->innerColor = Color(255, 0, 255, 255);
unif->outerColor = Color(255, 255, 0, 255);
unif->feather = 5.0f;
unif->radius = 2.0f;
unif->type = 1;
// getPaintMat does not affect uniforms
// also paint mat is passed properly to the shader
paintMat = getPaintMat();
}
void Present()
{
glBindBuffer(GL_UNIFORM_BUFFER, ubo);
glBufferData(GL_UNIFORM_BUFFER, context.nuniform * context.fragSize, context.uniforms, GL_DYNAMIC_DRAW);
//it goes through all draw calls and binds suitable uniforms
for(const auto drawCall : context.drawCall) {
glBindBufferRange(GL_UNIFORM_BUFFER, 2, ubo, drawCall.uniformOffset, sizeof(Uniforms));
//Draw call
glDrawArrays(...);
}
context.nuniform = 0;
}
Context context;
GLuint ubo = 0;
};
int main()
{
//Create windows...
//Create gl context...
MainStruct mainS;
Create();
bool quit = true;
while(!quit) {
mainS.SetupUniforms();
mainS.Present();
//Swap buffers...
}
return 0;
}
static const char* fragmentShader = R"(
#version 460 core
layout(location = 0) out vec4 f_color;
layout(std140, binding = 2) uniform Unif
{
mat3 paintMat;
vec4 innerCol;
vec4 outerCol;
vec2 extent;
float radius;
float feather;
int type;
};
void main()
{
vec4 result;
if(radius == 3) {
result = vec4(1.0f, 0.0f, 0.0f, 1.0f);
}
if(feather == 5) {
result = vec4(0.0f, 1.0f, 0.0f, 1.0f);
}
if(type == 8) {
result = vec4(0.0f, 0.0f, 1.0f, 1.0f);
}
f_color = result;
}
)";
当然可以使用vbo等来设置顶点位置,但是在这种情况下没关系。
前四个统一变量与我添加的evey绘制调用配合良好。
问题来自radius
,feather
和type
。他们一直都是0。我希望radius
,feather
和type
是我在SetupUniforms()
方法中设置的变量。
那是为什么?我该如何解决?