为什么我的 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());
问题是,当我在多个轴上旋转 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());