OpenGL点精灵在片段着色器中的旋转

问题描述:

我跟随this tutorial来学习更多关于OpenGL和特别是点精灵的东西。但我被困在页面末尾的一个练习中:OpenGL点精灵在片段着色器中的旋转

尝试通过更改片段着色器来旋转45度角点。

本章没有提及这类事情,也没有提到过这些。而且我没有找到任何有关如何去做的文档。这是我的顶点和片段着色器:

的Vertex Shader

#version 140 

attribute vec2 coord2d; 

varying vec4 f_color; 

uniform float offset_x; 
uniform float scale_x; 
uniform float point_size; 

void main(void) { 
    gl_Position = vec4((coord2d.x + offset_x) * scale_x, coord2d.y, 0.0, 1.0); 
    f_color = vec4(coord2d.xy/2.0 + 0.5, 1.0, 1.0); 
    gl_PointSize = point_size; 
} 

片段着色器

#version 140 

varying vec4 f_color; 

uniform sampler2D texture; 

void main(void) { 
    gl_FragColor = texture2D(texture, gl_PointCoord) * f_color; 
} 

我想到在FS采用2×2矩阵旋转gl_PointCoord,但我不知道如何填充矩阵来完成它。我是否应该将其作为制服直接传递给FS?

传统方法是将矩阵传递给着色器,无论是顶点还是片段。如果你不知道如何填写旋转矩阵,Google和Wikipedia可以提供帮助。

最主要的是,你会遇到的是一个简单的事实,即2D旋转是不够的。 gl_PointCoord从[0,1]开始。纯旋转矩阵围绕原点旋转,原点是点坐标空间中的左下角。所以你需要的不仅仅是一个纯粹的旋转矩阵。

您需要一个3x3矩阵,它具有部分旋转和部分平移。这个矩阵应该如下(使用GLM的数学东西)来生成:

glm::mat4 currMat(1.0f); 
currMat = glm::translate(currMat, glm::vec3(0.5f, 0.5f, 0.0f)); 
currMat = glm::rotate(currMat, angle, glm::vec3(0.0f, 0.0f, 1.0f)); 
currMat = glm::translate(currMat, glm::vec3(-0.5f, -0.5f, 0.0f)); 

然后,您可以通过currMat到着色器作为一个4x4矩阵。你的shader做到这一点:

vec2 texCoord = (rotMatrix * vec4(gl_PointCoord, 0, 1)).xy 
gl_FragColor = texture2D(texture, texCoord) * f_color; 

我会离开它作为一个练习,你就如何翻译从第四栏移动到第三,以及如何将它传递一个3x3矩阵。当然,在这种情况下,你会为​​矩阵乘法做vec3(gl_PointCoord, 1)

+0

谢谢你的例子,它的工作。 – 2012-01-30 16:35:35

你是对的 - 一个2x2的旋转矩阵将做你想要的。

此页面:http://www.cg.info.hiroshima-cu.ac.jp/~miyazaki/knowledge/teche31.html显示如何计算元素。请注意,您将旋转纹理坐标,而不是顶点位置 - 结果可能不会是您期望的结果 - 例如,它将围绕0,0纹理坐标旋转。

您可能还需要将point_size乘以2并将gl_PointCoord缩小2以确保整个纹理在旋转时适合点精灵。但是,这样做是第二次改变。请注意,纹理坐标的直线比例将其移向纹理坐标原点,而不是精灵的中间。

如果您使用更高维矩阵(3x3),那么您将能够将偏移,比例和旋转合并为一个操作。

+0

谢谢,但正如你所说,结果不是我所期望的,因为我在错误的位置上旋转。 – 2012-01-30 16:35:02

我也陷入了同样的问题,但我找到了一个教程,解释如何在同一片段着色器中执行2d纹理旋转,仅传递旋转值(vRotation)。

#version 130 

uniform sampler2D tex; 
varying float vRotation; 
void main(void) 
{ 

    float mid = 0.5; 
    vec2 rotated = vec2(cos(vRotation) * (gl_PointCoord.x - mid) + sin(vRotation) * (gl_PointCoord.y - mid) + mid, 
         cos(vRotation) * (gl_PointCoord.y - mid) - sin(vRotation) * (gl_PointCoord.x - mid) + mid); 

    vec4 rotatedTexture=texture2D(tex, rotated); 
    gl_FragColor = gl_Color * rotatedTexture; 
} 

也许这方法是缓慢的,但仅是为了证明/显示您有一个替代以执行片段着色器内的纹理2D旋转而不是传递矩阵的。

注意:vRotation应该在Radians中。

干杯,