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

5

我正在跟随这个教程来了解OpenGL和点精灵。但是我卡在页面末尾的一个练习上:

尝试通过更改片段着色器将点精灵旋转45度。

在本章和之前的章节中都没有关于这种事情的提示。我也没有找到任何如何操作的文档。这是我的顶点着色器和片段着色器:

顶点着色器

#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中使用2x2矩阵来旋转gl_PointCoord,但我不知道如何填充矩阵以完成它。我应该将其直接作为uniform传递到FS中吗?

3个回答

9
传统的方法是将矩阵传递给着色器,无论是顶点还是片元。如果您不知道如何填写旋转矩阵,可以使用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矩阵传递给着色器。您的着色器执行以下操作:

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

我会把如何将第四列的翻译移动到第三列,并将其传递为3x3矩阵的练习留给你。当然,在这种情况下,您需要执行vec3(gl_PointCoord, 1)进行矩阵乘法。


4

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

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

也许这种方法比较慢,但只是为了证明你在片元着色器内执行纹理二维旋转的替代方法而已,而不是传递一个矩阵。

注意:vRotation 应该是弧度制。

祝好!


1

你是对的 - 一个2x2的旋转矩阵可以实现你想要的效果。

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

你可能还需要将point_size乘以2,并将gl_PointCoord缩小2倍,以确保整个纹理在旋转时适合于点精灵。但这是第二次更改。请注意,纹理坐标的直接缩放会将它们移向纹理坐标原点,而不是精灵的中心。

如果使用更高维度的矩阵(3x3),则可以将偏移、缩放和旋转组合成一个操作。


谢谢,但正如你所说,结果并不是我期望的,因为我围绕错误的点旋转了。 - Pietro Lorefice

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接