Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

OpenGL: changing texture coordinates on the fly

I am currently trying to render the value of an integer using a bitmap (think scoreboard for invaders) but I'm having trouble changing texture coordinates while the game is running.

I link the shader and data like so:

GLint texAttrib = glGetAttribLocation(shaderProgram, "texcoord");
glEnableVertexAttribArray(texAttrib);
glVertexAttribPointer(texAttrib, 2, GL_FLOAT, GL_FALSE,
4 * sizeof(float), (void*)(2 * sizeof(float)));

And in my shaders I do the following: Vertex Shader:

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

How would I change this code/implement a function to be able to change the texcoord variable?

like image 436
user3162904 Avatar asked Jan 05 '15 00:01

user3162904


1 Answers

If you need to modify the texture coordinates frequently, but the other vertex attributes remain unchanged, it can be beneficial to keep the texture coordinates in a separate VBO. While it's generally preferable to use interleaved attributes, this is one case where that's not necessarily the most efficient solution.

So you would have two VBOs, one for the positions, and one for the texture coordinates. Your setup code will look something like this:

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

Note the different last argument to glBufferData(), which is a usage hint. GL_STATIC_DRAW suggests to the OpenGL implementation that the data will not be modified on a regular basis, while GL_DYNAMIC_DRAW suggests that it will be modified frequently.

Then, anytime your texture data changes, you can modify it with glBufferSubData():

glBindBuffer(GL_ARRAY_BUFFER, vboIds[1]);
glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(texCoords), texCoords);

Of course if only part of them change, you would only make the call for the part that changes.

You did not specify how exactly the texture coordinates change. If it's just something like a simple transformation, it would be much more efficient to apply that transformation in the shader code, instead of modifying the original texture coordinates.

For example, say you only wanted to shift the texture coordinates. You could have a uniform variable for the shift in your vertex shader, and then add it to the incoming texture coordinate attribute:

uniform vec2 TexCoordShift;
in vec2 TexCoord;
out vec2 FragTexCoord;
...
    FragTexCoord = TexCoord + TexCoordShift;

and then in your C++ code:

// Once during setup, after linking program.
TexCoordShiftLoc = glGetUniformLocation(program, "TexCoordShift");

// To change transformation, after glUseProgram(), before glDraw*().
glUniform2f(TexCoordShiftLoc, xShift, yShift);
like image 56
Reto Koradi Avatar answered Oct 04 '22 12:10

Reto Koradi