OpenGL:动态改变纹理坐标
OpenGL: changing texture coordinates on the fly
我目前正在尝试使用位图渲染整数值(想想入侵者的记分牌),但我在游戏运行时更改纹理坐标时遇到问题。
我link着色器和数据是这样的:
GLint texAttrib = glGetAttribLocation(shaderProgram, "texcoord");
glEnableVertexAttribArray(texAttrib);
glVertexAttribPointer(texAttrib, 2, GL_FLOAT, GL_FALSE,
4 * sizeof(float), (void*)(2 * sizeof(float)));
在我的着色器中,我执行以下操作:
顶点着色器:
#version 150
uniform mat4 mvp;
in vec2 position;
in vec2 texcoord;
out vec2 Texcoord;
void main() {
Texcoord = texcoord;
gl_Position = mvp * vec4(position, 0.0, 1.0) ;
}
片段着色器:
#version 150 core
in vec2 Texcoord;
out vec4 outColor;
uniform sampler2D tex;
void main() {
outColor = texture2D(tex, Texcoord);
}
我该如何更改此 code/implement 函数才能更改 texcoord 变量?
所以我不保证这种技术的效率,但我就是这么做的,如果文本渲染拖慢了我的程序,我会被诅咒的。
我有一个专门的 class 来存储网格,它由一些数据向量和一些 GLuint
来存储指向我上传的数据的指针。我像这样将数据上传到 openGL:
glBindBuffer(GL_ARRAY_BUFFER, position);
glBufferData(GL_ARRAY_BUFFER, sizeof(vec3) * data.position.size(), &data.position[0], GL_DYNAMIC_DRAW);
glBindBuffer(GL_ARRAY_BUFFER, normal);
glBufferData(GL_ARRAY_BUFFER, sizeof(vec3) * data.normal.size(), &data.normal[0], GL_DYNAMIC_DRAW);
glBindBuffer(GL_ARRAY_BUFFER, uv);
glBufferData(GL_ARRAY_BUFFER, sizeof(vec2) * data.uv.size(), &data.uv[0], GL_DYNAMIC_DRAW);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, index);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(unsigned int) * data.index.size(), &data.index[0], GL_DYNAMIC_DRAW);
然后,我是这样画的:
glEnableVertexAttribArray(positionBinding);
glBindBuffer(GL_ARRAY_BUFFER, position);
glVertexAttribPointer(positionBinding, 3, GL_FLOAT, GL_FALSE, 0, NULL);
glEnableVertexAttribArray(normalBinding);
glBindBuffer(GL_ARRAY_BUFFER, normal);
glVertexAttribPointer(normalBinding, 3, GL_FLOAT, GL_TRUE, 0, NULL);
glEnableVertexAttribArray(uvBinding);
glBindBuffer(GL_ARRAY_BUFFER, uv);
glVertexAttribPointer(uvBinding, 2, GL_FLOAT, GL_FALSE, 0, NULL);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, index);
glDrawElements(GL_TRIANGLES, indexCount, GL_UNSIGNED_INT, NULL);
glDisableVertexAttribArray(positionBinding);
glDisableVertexAttribArray(normalBinding);
glDisableVertexAttribArray(uvBinding);
此设置专为成熟的 3D 引擎设计,因此您绝对可以将其调低一点。基本上,我有 4 个缓冲区,position、uv、normal 和 index。您可能只需要前两个,所以请忽略其他。
无论如何,每次我想绘制一些文本时,我都会使用我显示的第一个代码块上传我的数据,然后使用第二个代码块绘制它。它工作得很好,而且非常优雅。这是我使用它绘制文本的代码:
vbo(genTextMesh("some string")).draw(); //vbo is my mesh containing class
希望对您有所帮助,如有任何疑问,请随时提出。
如果您需要经常修改纹理坐标,但其他顶点属性保持不变,将纹理坐标保存在单独的 VBO 中可能会有所帮助。虽然使用交错属性通常更可取,但在这种情况下,这不一定是最有效的解决方案。
因此您将有两个 VBO,一个用于位置,一个用于纹理坐标。您的设置代码将如下所示:
GLuint vboIds[2];
glGenBuffers(2, vboIds);
// Load positions.
glBindBuffer(GL_ARRAY_BUFFER, vboIds[0]);
glBufferData(GL_ARRAY_BUFFER, sizeof(positions), positions, GL_STATIC_DRAW);
// Load texture coordinates.
glBindBuffer(GL_ARRAY_BUFFER, vboIds[1]);
glBufferData(GL_ARRAY_BUFFER, sizeof(texCoords), texCoords, GL_DYNAMIC_DRAW);
请注意 glBufferData()
的最后一个参数不同,这是一个用法提示。 GL_STATIC_DRAW
建议OpenGL实现不要定期修改数据,而GL_DYNAMIC_DRAW
建议会经常修改。
然后,任何时候你的纹理数据改变,你可以用glBufferSubData()
修改它:
glBindBuffer(GL_ARRAY_BUFFER, vboIds[1]);
glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(texCoords), texCoords);
当然,如果只是其中一部分发生变化,您只需调用发生变化的部分即可。
您没有具体说明纹理坐标是如何变化的。如果它只是一个简单的变换,那么在着色器代码中应用该变换会比修改原始纹理坐标更有效。
例如,假设您只想移动纹理坐标。您可以在顶点着色器中为偏移设置一个统一变量,然后将其添加到传入的纹理坐标属性中:
uniform vec2 TexCoordShift;
in vec2 TexCoord;
out vec2 FragTexCoord;
...
FragTexCoord = TexCoord + TexCoordShift;
然后在您的 C++ 代码中:
// Once during setup, after linking program.
TexCoordShiftLoc = glGetUniformLocation(program, "TexCoordShift");
// To change transformation, after glUseProgram(), before glDraw*().
glUniform2f(TexCoordShiftLoc, xShift, yShift);
我使用统一 vec2
将纹理偏移量传递到顶点着色器。
我不确定这有多有效,但如果你的纹理坐标是相同的形状,只是四处移动,那么这是一个选项。
#version 150
uniform mat4 mvp;
uniform vec2 texOffset;
in vec2 position;
in vec2 texcoord;
out vec2 Texcoord;
void main() {
Texcoord = texcoord + texOffset;
gl_Position = mvp * vec4(position, 0.0, 1.0) ;
}
我目前正在尝试使用位图渲染整数值(想想入侵者的记分牌),但我在游戏运行时更改纹理坐标时遇到问题。
我link着色器和数据是这样的:
GLint texAttrib = glGetAttribLocation(shaderProgram, "texcoord");
glEnableVertexAttribArray(texAttrib);
glVertexAttribPointer(texAttrib, 2, GL_FLOAT, GL_FALSE,
4 * sizeof(float), (void*)(2 * sizeof(float)));
在我的着色器中,我执行以下操作: 顶点着色器:
#version 150
uniform mat4 mvp;
in vec2 position;
in vec2 texcoord;
out vec2 Texcoord;
void main() {
Texcoord = texcoord;
gl_Position = mvp * vec4(position, 0.0, 1.0) ;
}
片段着色器:
#version 150 core
in vec2 Texcoord;
out vec4 outColor;
uniform sampler2D tex;
void main() {
outColor = texture2D(tex, Texcoord);
}
我该如何更改此 code/implement 函数才能更改 texcoord 变量?
所以我不保证这种技术的效率,但我就是这么做的,如果文本渲染拖慢了我的程序,我会被诅咒的。
我有一个专门的 class 来存储网格,它由一些数据向量和一些 GLuint
来存储指向我上传的数据的指针。我像这样将数据上传到 openGL:
glBindBuffer(GL_ARRAY_BUFFER, position);
glBufferData(GL_ARRAY_BUFFER, sizeof(vec3) * data.position.size(), &data.position[0], GL_DYNAMIC_DRAW);
glBindBuffer(GL_ARRAY_BUFFER, normal);
glBufferData(GL_ARRAY_BUFFER, sizeof(vec3) * data.normal.size(), &data.normal[0], GL_DYNAMIC_DRAW);
glBindBuffer(GL_ARRAY_BUFFER, uv);
glBufferData(GL_ARRAY_BUFFER, sizeof(vec2) * data.uv.size(), &data.uv[0], GL_DYNAMIC_DRAW);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, index);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(unsigned int) * data.index.size(), &data.index[0], GL_DYNAMIC_DRAW);
然后,我是这样画的:
glEnableVertexAttribArray(positionBinding);
glBindBuffer(GL_ARRAY_BUFFER, position);
glVertexAttribPointer(positionBinding, 3, GL_FLOAT, GL_FALSE, 0, NULL);
glEnableVertexAttribArray(normalBinding);
glBindBuffer(GL_ARRAY_BUFFER, normal);
glVertexAttribPointer(normalBinding, 3, GL_FLOAT, GL_TRUE, 0, NULL);
glEnableVertexAttribArray(uvBinding);
glBindBuffer(GL_ARRAY_BUFFER, uv);
glVertexAttribPointer(uvBinding, 2, GL_FLOAT, GL_FALSE, 0, NULL);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, index);
glDrawElements(GL_TRIANGLES, indexCount, GL_UNSIGNED_INT, NULL);
glDisableVertexAttribArray(positionBinding);
glDisableVertexAttribArray(normalBinding);
glDisableVertexAttribArray(uvBinding);
此设置专为成熟的 3D 引擎设计,因此您绝对可以将其调低一点。基本上,我有 4 个缓冲区,position、uv、normal 和 index。您可能只需要前两个,所以请忽略其他。
无论如何,每次我想绘制一些文本时,我都会使用我显示的第一个代码块上传我的数据,然后使用第二个代码块绘制它。它工作得很好,而且非常优雅。这是我使用它绘制文本的代码:
vbo(genTextMesh("some string")).draw(); //vbo is my mesh containing class
希望对您有所帮助,如有任何疑问,请随时提出。
如果您需要经常修改纹理坐标,但其他顶点属性保持不变,将纹理坐标保存在单独的 VBO 中可能会有所帮助。虽然使用交错属性通常更可取,但在这种情况下,这不一定是最有效的解决方案。
因此您将有两个 VBO,一个用于位置,一个用于纹理坐标。您的设置代码将如下所示:
GLuint vboIds[2];
glGenBuffers(2, vboIds);
// Load positions.
glBindBuffer(GL_ARRAY_BUFFER, vboIds[0]);
glBufferData(GL_ARRAY_BUFFER, sizeof(positions), positions, GL_STATIC_DRAW);
// Load texture coordinates.
glBindBuffer(GL_ARRAY_BUFFER, vboIds[1]);
glBufferData(GL_ARRAY_BUFFER, sizeof(texCoords), texCoords, GL_DYNAMIC_DRAW);
请注意 glBufferData()
的最后一个参数不同,这是一个用法提示。 GL_STATIC_DRAW
建议OpenGL实现不要定期修改数据,而GL_DYNAMIC_DRAW
建议会经常修改。
然后,任何时候你的纹理数据改变,你可以用glBufferSubData()
修改它:
glBindBuffer(GL_ARRAY_BUFFER, vboIds[1]);
glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(texCoords), texCoords);
当然,如果只是其中一部分发生变化,您只需调用发生变化的部分即可。
您没有具体说明纹理坐标是如何变化的。如果它只是一个简单的变换,那么在着色器代码中应用该变换会比修改原始纹理坐标更有效。
例如,假设您只想移动纹理坐标。您可以在顶点着色器中为偏移设置一个统一变量,然后将其添加到传入的纹理坐标属性中:
uniform vec2 TexCoordShift;
in vec2 TexCoord;
out vec2 FragTexCoord;
...
FragTexCoord = TexCoord + TexCoordShift;
然后在您的 C++ 代码中:
// Once during setup, after linking program.
TexCoordShiftLoc = glGetUniformLocation(program, "TexCoordShift");
// To change transformation, after glUseProgram(), before glDraw*().
glUniform2f(TexCoordShiftLoc, xShift, yShift);
我使用统一 vec2
将纹理偏移量传递到顶点着色器。
我不确定这有多有效,但如果你的纹理坐标是相同的形状,只是四处移动,那么这是一个选项。
#version 150
uniform mat4 mvp;
uniform vec2 texOffset;
in vec2 position;
in vec2 texcoord;
out vec2 Texcoord;
void main() {
Texcoord = texcoord + texOffset;
gl_Position = mvp * vec4(position, 0.0, 1.0) ;
}