为什么我的 3D 立方体在旋转时会变形?

Why is my 3D cube distorting when rotating?

问题是,当我在多个轴上旋转 3D 立方体时,它会在大约一半的时候奇怪地扭曲。我正在为矩阵使用 JOML 数学库。

// This is the model matrix for the rotation of a textured cube
Matrix4f model = new Matrix4f();
model.identity();
model.rotate((float)(glfwGetTime() * Math.toRadians(50.0f)), new Vector3f(0.5f, 1.0f, 0.0f), model);
// Other matrices for coordinate system
Matrix4f view = new Matrix4f();
view.identity();
view.translate(new Vector3f(0.0f, 0.0f, -3.0f), view);
Matrix4f projection = new Matrix4f();
projection.identity();
projection.perspective((float)Math.toRadians(45.0f), 800.0f / 600.0f, 0.1f, 100.0f); // FOV is 45

这是变形的gif:

您的代码中有 2 个错误:

首先:您尝试一次更新 2 个轴。 这样做会导致模型在旋转时缩放。

第二:在定义要旋转的轴时不使用 1.0f。这也会导致模型缩放。

Matrix4f.rotate(float angleInRadiants, Vector3f(x, y, z)) 的工作方式是它将向量中指定的轴旋转指定的 angleInRadians。

这是旋转两个轴的正确方法:

model
.rotate((float)(glfwGetTime() * Math.toRadians(50.0f)), new Vector3f(0.0f, 1.0f, 0.0f), model)
.rotate(((float)(glfwGetTime() * Math.toRadians(50.0f)) / 2), new Vector3f(0.1f, 0.0f, 0.0f), model);

更好的旋转方式是四元数。

您可以创建一个新的 Quaternionf 对象,设置它的角度并使用它旋转模型矩阵。

float someAngleInRads = (float) Math.toRadians(20f * glfwGetTime());
            
Quaternionf quaternionf = new Quaternionf()
        .rotateAxis(someAngleInRads, new Vector3f(0, 1, 0))
        .rotateAxis(someAngleInRads / 2, new Vector3f(1, 0, 0));
model.rotate(quaternionf);

您也可以这样设置四元数的角度:

Quaternionf quaternionf = new Quaternionf().rotateXYZ(Math.toRadians(someAngleInRads / 2), Math.toRadians(someAngleInRads), Math.toRadians(0f));

主要问题是你的旋转轴(0.5f, 1.0f, 0.0f)不是unit/normalized,(as is also required by its JavaDoc)

Parameters:

axis - the rotation axis (needs to be normalized)

解决问题并且仍然使用矩阵,你只需要normalize旋转轴。

还有(但这与错误无关):

  • JOML 矩阵在实例化后默认为恒等式——您无需对其调用 identity())
  • 您可以省略提供 model 作为 rotate()dest 参数的参数

所以:

// This is the model matrix for the rotation of a textured cube
Matrix4f model = new Matrix4f();
model.rotate((float)(glfwGetTime() * Math.toRadians(50.0f)),
             new Vector3f(0.5f, 1.0f, 0.0f).normalize());