0
\$\begingroup\$

How can I rotate a texture inside a quad without rotating the quad? Here's the code but I'm rotating the whole quad here.

glBindTexture(GL_TEXTURE_2D, texName5);
glMatrixMode(GL_TEXTURE);
glLoadIdentity();
glMatrixMode(GL_MODELVIEW);

    glPushMatrix();
            glTranslatef(12.8, 10, 10);
            glRotatef(rotateAd, 1, 0, 0);
            glBegin(GL_QUADS);
                    glNormal3f(1, 0, 0);
                    glTexCoord2f(0.0, 0.0); glVertex3f(0, -3,  -3);
                    glTexCoord2f(0.0, 1.0); glVertex3f(0, -3,  3);
                    glTexCoord2f(1.0, 0.0); glVertex3f(0, 3, 3);
                    glTexCoord2f(1.0, 1.0); glVertex3f(0, 3, -3);
            glEnd();
    glPopMatrix();

Thanks.

\$\endgroup\$
  • 1
    \$\begingroup\$ The UV corners will protrude outside of the quad; will the colored portion of the texture be circular, or is this known/acceptable? \$\endgroup\$ – Jon Apr 20 '15 at 19:56
  • \$\begingroup\$ @Jon that's a good point. I think fxh-.- might be interested in looking into OpenGLs texture wrap parameters (khronos.org/opengles/sdk/docs/man/xhtml/glTexParameter.xml). This will let you get the desired results! \$\endgroup\$ – Jelle van Campen Apr 20 '15 at 20:26
9
\$\begingroup\$

Solution 1: Rotate your UVs in your vertex shader

The vertex shader is where per-vertex attributes can be modified before rendering. These values are then linearly interpolated to generate values for all fragments of your polygons. As a rotation of your your UVs is a linear transformation, you only need to recalculate the values in the vertices, and linear interpolation will take care of all intermediate fragment values. (Note that in case of a non-linear transform such as u_new = sin( u_old ), you'd have to calculate the new UVs for every fragment individually. In this case, the transformation belongs in your fragment shader.)

The UVs are a 2D coordinate pair with values ranging from 0 to 1: [0, 1] x [0, 1]. (These values can sometimes be outside of the 0,1 range, in this case clamping, wrapping or repeating of the texture occurs, depending on how you specified your OpenGL texture hints)

In your vertex shader, you could rotate your UVs prior to the texture sampling to obtain a rotation. I'll assume you want to rotate the texture around its center coordinate (0.5, 0.5) (if the rotation origin varies from texture to texture, you could pass it as a 2f uniform). To enable animation, I'd suggest passing the angle as a 1f uniform.

You can calculate the new UVs using a concatenation of three transforms. You can't just do a single transform (a rotation) because this would rotate the texture around the (0, 0) point. Instead you want to use (0.5 ; 0.5) as your origin of rotation. The image by Jon at the bottom of this answer illustrates this. You can use these transformations:

  1. Translate the UVs to the origin using T[-0.5, -0.5]. This means: UVs = UVs + vec2(-0.5f, -0.5f);
  2. Rotate your UVs by the angle specified in the uniform using R[uniformAngle]. This can be done by multiplying with a 2x2 rotation matrix. This means: *UVs = mat2(cos(uniformAngle), sin(uniformAngle), -sin(uniformAngle), cos(uniformAngle)) * UVs;*
  3. Translate the UVs back to the center of the texture using T[0.5, 0.5]. This means: UVs = UVs + vec2(0.5f, 0.5f);

By sampling your texture using these new UVs, a rotation will have been applied. You can increase your angle uniform over time to apply an animation to the rotation.


Solution 2: Rotate your UVs on the CPU

If the angle of rotation remains constant throughout your program, it might be better to rotate the UVs on the CPU. This means you rotate them before rendering (thus while filling up your buffer objects). The procedure is exactly the same. You could use the GLM library to perform the matrix and vector operations for you. The procedure is the same as described above.


In summary, you will want to rotate your UVs to have the effect of a rotation on your texture. You can do this in two places. If the rotation changes over time, it is best to perform the calculation on your GPU, in the vertex shader. If the angle is constant, you can do the calculation on the CPU while filling up your vertex buffer, to prevent performing the same calculation every frame.

Illustration of a rotation around the (0.5, 0.5) point, as a concatenation of three transformations

\$\endgroup\$
  • \$\begingroup\$ Couldn't submit "can" because you already got it; GG for so much detail; +1! \$\endgroup\$ – Jon Apr 20 '15 at 20:24
  • \$\begingroup\$ You can have my diagram if you don't mind the Dead Or Alive reference :) \$\endgroup\$ – Jon Apr 20 '15 at 20:27
  • \$\begingroup\$ Sounds good, I'll merge your image in for more clarity, thanks! \$\endgroup\$ – Jelle van Campen Apr 20 '15 at 20:28
  • \$\begingroup\$ Dudes thanks for both your answers but I have no idea what the UVs are in my texture and a whole lot of things you mentioned in your answer, I started OpenGL 2.0 two weeks ago... \$\endgroup\$ – fxh-.- Apr 20 '15 at 20:29
  • 1
    \$\begingroup\$ @JibbSmart: right, you're 100% correct. I'll modify the answer to correct this. This isn't even limited to rotations, it applies to all linear transformations of the UVs. Only when non-linear transforms such as u_new = sin( u_old ) are involved, would you need to perform the calculation on a per-fragment level. \$\endgroup\$ – Jelle van Campen Apr 21 '15 at 19:49

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.