OpenGL:动态改变纹理坐标

时间:2015-01-05 00:27:57

标签: c++ opengl opengl-es rendering shader

我目前正在尝试使用位图渲染整数的值(想想入侵者的记分板),但是在游戏运行时我无法更改纹理坐标。

我像这样链接着色器和数据:

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) ;
}

FragmentShader:

#version 150 core
in vec2 Texcoord;
out vec4 outColor;

uniform sampler2D tex;
void main() {
    outColor = texture2D(tex, Texcoord);
}

如何更改此代码/实现一个能够更改texcoord变量的函数?

3 个答案:

答案 0 :(得分:6)

如果需要经常修改纹理坐标,但其他顶点属性保持不变,将纹理坐标保持在单独的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);

答案 1 :(得分:3)

所以我对这项技术的效率没有做出任何承诺,但它是我的工作,如果文字渲染会减慢我的程序,我会被诅咒。

我有一个专门的类来存储网格,它包含一些数据向量,还有一些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

如果您有任何问题可以随意提问,我希望这会有所帮助。

答案 2 :(得分:2)

我使用制服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) ;
}