2

So I created a vertex shader that takes in an angle and calculates the rotation. There is a problem though that the model rotates around the world center and not its own axis/origin.

Side note: This is 2D rotation.

How do I make the model rotate through its own axis?

Here is my current vertex shader:

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

Rotating CPU side:

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

Result is a weird rotated stretch of the object.. Do you know why? Don't worry about the /30f part.

  • phyxBody is an instance of the class Body from the JBox2D library. phyxBody.getAngle() is in raidians.
  • Matrix4f is a class from the LWJGL library.

EDIT:

    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;

This is currently the transformation code, yet the rotation still doesn't work correctly.

My try at the rotate method: (What am I doing wrong?)

    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()));
    }
4

2 回答 2

5

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

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

底线:翻译前必须旋转。

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

OpenGL端:

  1. 计算 ModelView 矩阵:Scale * Rotation * Translation

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

GLSL 方面:

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

  2. 发送至gl_Position

对编辑的回应:

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

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

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

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

  • 您不必重新实现数学功能,可能也不应该(除非您的目标是明确这样做)。GLM 是一个流行的数学库,它可以满足您的所有需求,并且专为 OpenGL 量身定制。

最终编辑

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

  • 请注意右下角的模型是如何在世界原点周围以大约 45 度扫过的。如果我们再走 45,它的底边将平行于 X 轴,并与正 Y 轴相交,蓝色顶点位于左下角,紫色顶点位于右下角。

  • 您可能应该查看如何使用顶点、矩阵和着色器。顶点应该被指定一次,矩阵应该在每次你遇到对象的缩放、旋转或位置时更新,并且着色器应该将模型中的每个顶点乘以一个统一的(常数)。

于 2013-07-22T15:22:43.963 回答
2

你的精灵缺乏足够的信息来做你想做的事情。为了计算一个点的旋转,你需要知道那个点是什么。而你没有。

因此,如果您想围绕任意位置旋转,您需要将该位置传递给您的着色器。一旦到了那里,你从你的位置中减去它,旋转位置,然后把它加回去。然而,这需要大量的工作,这就是为什么你应该在 CPU 上计算一个矩阵来完成所有这些工作。您的着色器将获得此矩阵并自行执行转换。

当然,这本身需要其他东西,因为您通过偏移CPU 上的顶点来不断更新这些对象的位置。情况不妙; 你应该保持这些对象相对于它们在缓冲区中的原点。然后,您应该将它们转换为它们的世界位置作为其矩阵的一部分。

因此,您的着色器应该采用对象相对坐标,并且应该传递一个矩阵,该矩阵进行旋转,然后平移到它们的世界空间位置。实际上,从头开始;矩阵应该转换到它们最终的相机空间位置(世界空间总是一个坏主意)。

于 2013-07-22T18:59:13.083 回答