OpenGL 着色器 - 围绕其原点旋转模型(2D 世界)

Gop*_*gop 2 java opengl rotation vertex-shader

所以我创建了一个顶点着色器,它接收一个角度并计算旋转。尽管模型围绕世界中心而不是它自己的轴/原点旋转,但存在一个问题。

旁注:这是 2D 旋转。

如何让模型通过它自己的轴旋转?

这是我当前的顶点着色器:

#version 150 core

in vec4 in_Position;
in vec4 in_Color;
in vec2 in_TextureCoord;

out vec4 pass_Color;
out vec2 pass_TextureCoord;

void main(void) {


    gl_Position = in_Position;

    pass_Color = in_Color;
    pass_TextureCoord = in_TextureCoord;
}
Run Code Online (Sandbox Code Playgroud)

旋转 CPU 侧:

    Vector3f center = new Vector3f(phyxBody.getPosition().x,phyxBody.getPosition().y,0);
    Matrix4f pos = new Matrix4f();
    pos.m00 = (phyxBody.getPosition().x)-(getWidth()/30f/2f);
    pos.m01 = (phyxBody.getPosition().y)+(getHeight()/30f/2f);
    pos.m10 = (phyxBody.getPosition().x)-(getWidth()/30f/2f);
    pos.m11 = (phyxBody.getPosition().y)-(getHeight()/30f/2f);
    pos.m20 = (phyxBody.getPosition().x)+(getWidth()/30f/2f);
    pos.m21 = (phyxBody.getPosition().y)-(getHeight()/30f/2f);
    pos.m30 = (phyxBody.getPosition().x)+(getWidth()/30f/2f);
    pos.m31 = (phyxBody.getPosition().y)+(getHeight()/30f/2f);

    pos.rotate(phyxBody.getAngle(),center);
Run Code Online (Sandbox Code Playgroud)

结果是物体发生了奇怪的旋转拉伸。你知道为什么吗?不要担心 /30f 部分。

  • phyxBody 是 JBox2D 库中 Body 类的一个实例。phyxBody.getAngle() 在raidians 中。
  • Matrix4f 是 LWJGL 库中的一个类。

编辑:

    Vector3f center = new Vector3f(0,0,0);
    Matrix4f pos = new Matrix4f();
    pos.m00 = -(getWidth()/30f/2f);
    pos.m01 = +(getHeight()/30f/2f);
    pos.m10 = -(getWidth()/30f/2f);
    pos.m11 = -(getHeight()/30f/2f);
    pos.m20 = +(getWidth()/30f/2f);
    pos.m21 = -(getHeight()/30f/2f);
    pos.m30 = +(getWidth()/30f/2f);
    pos.m31 = +(getHeight()/30f/2f);

    pos.rotate(phyxBody.getAngle(),center);

    pos.m00 += phyxBody.getPosition().x;
    pos.m01 += phyxBody.getPosition().y;
    pos.m10 += phyxBody.getPosition().x;
    pos.m11 += phyxBody.getPosition().y;
    pos.m20 += phyxBody.getPosition().x;
    pos.m21 += phyxBody.getPosition().y;
    pos.m30 += phyxBody.getPosition().x;
    pos.m31 += phyxBody.getPosition().y;
Run Code Online (Sandbox Code Playgroud)

这是当前的转换代码,但旋转仍然无法正常工作。

我尝试旋转方法:(我做错了什么?)

    if (phyxBody.getAngle() != 0.0) {
        pos.m00 *= Math.cos(Math.toDegrees(phyxBody.getAngle()));
        pos.m01 *= Math.sin(Math.toDegrees(phyxBody.getAngle()));
        pos.m10 *= -Math.sin(Math.toDegrees(phyxBody.getAngle()));
        pos.m11 *= Math.cos(Math.toDegrees(phyxBody.getAngle()));
        pos.m20 *= Math.cos(Math.toDegrees(phyxBody.getAngle()));
        pos.m21 *= Math.sin(Math.toDegrees(phyxBody.getAngle()));
        pos.m30 *= -Math.sin(Math.toDegrees(phyxBody.getAngle()));
        pos.m31 *= Math.cos(Math.toDegrees(phyxBody.getAngle()));
    }
Run Code Online (Sandbox Code Playgroud)

Gra*_*her 5

顺序是缩放 * 旋转 * 平移 - 请参阅此问题。我猜你已经在你的着色器之外翻译了你的坐标。您必须先旋转,然后再翻译。了解您正在做的事情背后的线性代数是很好的,这样您就知道为什么事情有效或无效。

执行此操作的典型方法是传递一个预先计算的 ModelView 矩阵,该矩阵已经处理了缩放/旋转/平移。如果你已经翻译了你的顶点,你就无法修复着色器中的问题,除非不必要地撤消它,然后再重新做它。发送未翻译的顶点,并随附数据(例如您的角度)以翻译它们。或者您可以事先翻译和旋转两者。这取决于你想做什么。

底线:您必须在翻译之前旋转。

以下是进行顶点变换的典型方式:

OpenGL方面:

  1. 计算 ModelView 矩阵:缩放 * 旋转 * 平移

  2. 作为统一矩阵传递给着色器

GLSL 方面:

  1. 在顶点着色器中通过 ModelView 矩阵乘以顶点

  2. 发给 gl_Position

对编辑的回应:

我倾向于认为您的实施需要完全重做。您有属于模型的点。这些点都围绕原点定向。例如,如果您有一辆汽车,这些点将形成一个三角形网格。

  • 如果您只是不平移这些点然后旋转它们,汽车将围绕其中心旋转。如果您随后平移,汽车将以旋转方式平移到您指定的位置。这里的关键是模型的原点与旋转的原点对齐,因此您最终会“围绕自身”旋转模型。

  • 如果您改为平移到新位置然后旋转,您的模型将像绕原点一样旋转。这可能不是您想要的。

  • 如果您直接修改实际顶点位置而不是使用变换矩阵,那么您就做错了。即使你只有一个正方形,把坐标留在 (-1,-1) (-1,1) (1,1) (1,-1) (注意中心是如何在 (0,0))和将它们翻译到你想去的地方。

  • 您不必重新实现数学功能,也可能不应该(除非您的目标明确这样做)。GLM 是一个流行的数学库,可以做你想做的一切,它是专门为 OpenGL 量身定制的。

最终编辑

这是我为您绘制的精美艺术品,展示了您需要做什么。在此处输入图片说明

  • 注意右下角的模型是如何围绕世界原点扫出大约 45 度的。如果我们再设置 45,它的底边将与 X 轴平行,并与正 Y 轴相交,与左下角的蓝色顶点和右下角的紫色顶点相交。

  • 您可能应该回顾一下如何使用顶点、矩阵和着色器。顶点应指定一次,矩阵应在每次更改对象的缩放、旋转或位置时更新,着色器应将模型中的每个顶点乘以一个统一值(常量)。