【问题标题】:OpenGL Shader - Rotating a model around its origin (2D World)OpenGL Shader - 围绕其原点旋转模型(2D 世界)
【发布时间】:2013-07-22 14:31:56
【问题描述】:

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

旁注:这是 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;
}

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

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

  • phyxBody 是 JBox2D 库中 Body 类的一个实例。 phyxBody.getAngle() 在突袭者中。
  • 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;

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

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

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

【问题讨论】:

  • 现在不清楚你在说什么,因为你没有说这些东西实际上是什么。什么是phyxBody,这个rotate 函数是如何工作的,等等。不是每个人都知道你在使用什么库。
  • phyxBody 是来自 JBox2D 库的 Body 类的 instanceof。它的角度以弧度为单位。 Rotate 函数来自 LWJGL 库中名为 Matrix4f 的类。

标签: java opengl rotation vertex-shader


【解决方案1】:

顺序是缩放 * 旋转 * 平移 - 请参阅 this question。我猜你已经在你的着色器之外翻译了你的坐标。你必须先旋转,然后翻译。很高兴了解您所做工作背后的线性代数,以便您了解为什么事情有效或无效。

执行此操作的典型方法是传递一个预先计算的 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 轴相交,左下角的蓝色顶点和右下角的紫色顶点。

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

【讨论】:

  • 我将如何先旋转?我正在做的是给他们一个 X 和 Y 并将其传递给着色器(in_Position)
  • 翻译。它从 (0,0,0) 到 (X,Y,Z)。您的旋转围绕原点旋转。因此,将它留在原点,旋转,然后平移到它的位置。
【解决方案2】:

您的精灵缺少足够的信息来执行您想要执行的操作。为了计算一个点的旋转,你需要知道那个点是什么。而你不知道。

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

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

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

【讨论】:

    猜你喜欢
    • 2015-04-11
    • 1970-01-01
    • 1970-01-01
    • 2019-10-18
    • 2010-12-30
    • 2015-07-23
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多