2个方向的3D旋转?
3D rotation in 2 directions?
背景
我正在尝试使用 LWJGL 3.0 在 Java 中创建 FPS 游戏。我设置了一个摄像头 class,它具有俯仰和偏航(未使用滚动)。相机本身扩展了实体,因为它有一个模型。我希望这个模型始终是相机的 "in front",无论相机指向何处。每个实体都有一个方法 getTransformationMatrix()
其中 returns 一个 Matrix4f
,然后传递给实体着色器。
问题
模型需要指向相机的方向,并围绕相机旋转,使其始终在前方。这种情况下的对象是拿着枪的手,如下图。
我的尝试
我知道基本的三角函数,所以我让对象分别正确旋转俯仰和偏航。这是我当前的实现:
偏航
@Override
public Matrix4f getTransformationMatrix() {
modelX = getPosition().x + (radius * (float)Math.sin(Math.toRadians(getYaw())));
modelZ = getPosition().z + (radius * (float)Math.cos(Math.toRadians(getYaw())));
return Transform.createTransformationMatrix(new Vector3f(modelX, getPosition().y - 5, modelZ), new Vector3f(0, getYaw(), 0), getScale());
}
音高
@Override
public Matrix4f getTransformationMatrix() {
modelZ = getPosition().z + (radius * (float)Math.sin(Math.toRadians(getPitch())));
modelY = (getPosition().y - 5) + (radius * (float)Math.cos(Math.toRadians(getPitch())));
return Transform.createTransformationMatrix(new Vector3f(getPosition().x, modelY, modelZ), new Vector3f(getPitch(), 0, 0), getScale());
}
我做了一些研究,但我担心我在这方面停留的时间太长了,需要一些新的眼光。当我尝试结合这两个计算时,模型似乎在观察任何非 0 的偏航角时以图形的形式移动。下面是我结合这些的尝试:
@Override
public Matrix4f getTransformationMatrix() {
float zAxis = (radius * (float)Math.sin(Math.toRadians(getPitch())));
modelY = (getPosition().y - 5) + (radius * (float)Math.cos(Math.toRadians(getPitch())));
modelZ = getPosition().z + (zAxis * (float)Math.cos(Math.toRadians(getYaw())));
modelX = getPosition().x + (radius * (float)Math.sin(Math.toRadians(getYaw())));
return Transform.createTransformationMatrix(new Vector3f(modelX, modelY, modelZ), new Vector3f(getPitch(), getYaw(), 0), getScale());
}
Transform.createTransformationMatrix()
如下所示:
public static Matrix4f createTransformationMatrix(Vector3f translation, Vector3f rotation, Vector3f scale) {
transform3d = new Matrix4f();
transform3d.setIdentity();
Matrix4f.translate(translation, transform3d, transform3d);
Matrix4f.rotate((float) Math.toRadians(rotation.x), new Vector3f(1, 0, 0), transform3d, transform3d);
Matrix4f.rotate((float) Math.toRadians(rotation.y), new Vector3f(0, 1, 0), transform3d, transform3d);
Matrix4f.rotate((float) Math.toRadians(rotation.z), new Vector3f(0, 0, 1), transform3d, transform3d);
Matrix4f.scale(scale, transform3d, transform3d);
return transform3d;
}
想法
有朋友建议创建一个指向向上方向的单位向量,(即new Vector3f(0, 1, 0)
)将Vector旋转pitch和yaw,然后将Vector乘以半径并将其添加到相机的位置。我试过了,但是我不知道如何将一个Vector旋转一个角度,slick-utils Vector3f class中好像没有Vector3f.rotate()
方法。非常感谢任何帮助,因为在过去的几天里这一直让我很头疼。谢谢!
我们通常做的是,是的,取一个单位长度的向量并将其用作我们的"axis"。在 2D 旋转中,我们始终使用一个轴 - Z 轴。
3D rotation
如果你要看轴,就像在 2D 中,你会看到这样的东西
2D rotation
因此,要在 3D 中旋转一个点,您可以使用矩阵或向量。我首先推荐矢量,这样您就可以了解 3D 旋转的工作原理。它让你大吃一惊!
我将从 theBennyBox 的 Vector3f class 中删除代码。如果您对此数学感兴趣,请查看 Youtube 上的 BennyBox。
Vector3f
public Vector3F rotate(float angle, Vector3F axis) {
double a = Math.toRadians(angle / 2f);
float hs = (float) Math.sin(a);
float hc = (float) Math.cos(a);
Vector4F r = new Vector4F(axis.getX() * hs, axis.getY() * hs, axis.getZ() * hs, hc);
Vector4F rc = r.conjugate();
r = r.multiplyAsQuat(this).multiplyAsQuat(rc);
return new Vector3F(r.getX(), r.getY(), r.getZ());
}
矢量 4f
public Vector4F multiplyAsQuat(Vector3F v) {
float o = -x * v.getX() - y * v.getY() - z * v.getZ();
float a = w * v.getX() + y * v.getZ() - z * v.getY();
float b = w * v.getY() + z * v.getX() - x * v.getZ();
float c = w * v.getZ() + x * v.getY() - y * v.getX();
return new Vector4F(a, b, c, o);
}
public Vector4F conjugate() {
return new Vector4F(-x, -y, -z, w);
}
public Vector4F multiplyAsQuat(Vector4F qt) {
float o = w * qt.getW() - x * qt.getX() - y * qt.getY() - z * qt.getZ();
float a = x * qt.getW() + w * qt.getX() + y * qt.getZ() - z * qt.getY();
float b = y * qt.getW() + w * qt.getY() + z * qt.getX() - x * qt.getZ();
float c = z * qt.getW() + w * qt.getZ() + x * qt.getY() - y * qt.getX();
return new Vector4F(a, b, c, o);
}
背景
我正在尝试使用 LWJGL 3.0 在 Java 中创建 FPS 游戏。我设置了一个摄像头 class,它具有俯仰和偏航(未使用滚动)。相机本身扩展了实体,因为它有一个模型。我希望这个模型始终是相机的 "in front",无论相机指向何处。每个实体都有一个方法 getTransformationMatrix()
其中 returns 一个 Matrix4f
,然后传递给实体着色器。
问题
模型需要指向相机的方向,并围绕相机旋转,使其始终在前方。这种情况下的对象是拿着枪的手,如下图。
我的尝试
我知道基本的三角函数,所以我让对象分别正确旋转俯仰和偏航。这是我当前的实现:
偏航
@Override
public Matrix4f getTransformationMatrix() {
modelX = getPosition().x + (radius * (float)Math.sin(Math.toRadians(getYaw())));
modelZ = getPosition().z + (radius * (float)Math.cos(Math.toRadians(getYaw())));
return Transform.createTransformationMatrix(new Vector3f(modelX, getPosition().y - 5, modelZ), new Vector3f(0, getYaw(), 0), getScale());
}
音高
@Override
public Matrix4f getTransformationMatrix() {
modelZ = getPosition().z + (radius * (float)Math.sin(Math.toRadians(getPitch())));
modelY = (getPosition().y - 5) + (radius * (float)Math.cos(Math.toRadians(getPitch())));
return Transform.createTransformationMatrix(new Vector3f(getPosition().x, modelY, modelZ), new Vector3f(getPitch(), 0, 0), getScale());
}
我做了一些研究,但我担心我在这方面停留的时间太长了,需要一些新的眼光。当我尝试结合这两个计算时,模型似乎在观察任何非 0 的偏航角时以图形的形式移动。下面是我结合这些的尝试:
@Override
public Matrix4f getTransformationMatrix() {
float zAxis = (radius * (float)Math.sin(Math.toRadians(getPitch())));
modelY = (getPosition().y - 5) + (radius * (float)Math.cos(Math.toRadians(getPitch())));
modelZ = getPosition().z + (zAxis * (float)Math.cos(Math.toRadians(getYaw())));
modelX = getPosition().x + (radius * (float)Math.sin(Math.toRadians(getYaw())));
return Transform.createTransformationMatrix(new Vector3f(modelX, modelY, modelZ), new Vector3f(getPitch(), getYaw(), 0), getScale());
}
Transform.createTransformationMatrix()
如下所示:
public static Matrix4f createTransformationMatrix(Vector3f translation, Vector3f rotation, Vector3f scale) {
transform3d = new Matrix4f();
transform3d.setIdentity();
Matrix4f.translate(translation, transform3d, transform3d);
Matrix4f.rotate((float) Math.toRadians(rotation.x), new Vector3f(1, 0, 0), transform3d, transform3d);
Matrix4f.rotate((float) Math.toRadians(rotation.y), new Vector3f(0, 1, 0), transform3d, transform3d);
Matrix4f.rotate((float) Math.toRadians(rotation.z), new Vector3f(0, 0, 1), transform3d, transform3d);
Matrix4f.scale(scale, transform3d, transform3d);
return transform3d;
}
想法
有朋友建议创建一个指向向上方向的单位向量,(即new Vector3f(0, 1, 0)
)将Vector旋转pitch和yaw,然后将Vector乘以半径并将其添加到相机的位置。我试过了,但是我不知道如何将一个Vector旋转一个角度,slick-utils Vector3f class中好像没有Vector3f.rotate()
方法。非常感谢任何帮助,因为在过去的几天里这一直让我很头疼。谢谢!
我们通常做的是,是的,取一个单位长度的向量并将其用作我们的"axis"。在 2D 旋转中,我们始终使用一个轴 - Z 轴。
3D rotation
如果你要看轴,就像在 2D 中,你会看到这样的东西
2D rotation
因此,要在 3D 中旋转一个点,您可以使用矩阵或向量。我首先推荐矢量,这样您就可以了解 3D 旋转的工作原理。它让你大吃一惊!
我将从 theBennyBox 的 Vector3f class 中删除代码。如果您对此数学感兴趣,请查看 Youtube 上的 BennyBox。
Vector3f
public Vector3F rotate(float angle, Vector3F axis) {
double a = Math.toRadians(angle / 2f);
float hs = (float) Math.sin(a);
float hc = (float) Math.cos(a);
Vector4F r = new Vector4F(axis.getX() * hs, axis.getY() * hs, axis.getZ() * hs, hc);
Vector4F rc = r.conjugate();
r = r.multiplyAsQuat(this).multiplyAsQuat(rc);
return new Vector3F(r.getX(), r.getY(), r.getZ());
}
矢量 4f
public Vector4F multiplyAsQuat(Vector3F v) {
float o = -x * v.getX() - y * v.getY() - z * v.getZ();
float a = w * v.getX() + y * v.getZ() - z * v.getY();
float b = w * v.getY() + z * v.getX() - x * v.getZ();
float c = w * v.getZ() + x * v.getY() - y * v.getX();
return new Vector4F(a, b, c, o);
}
public Vector4F conjugate() {
return new Vector4F(-x, -y, -z, w);
}
public Vector4F multiplyAsQuat(Vector4F qt) {
float o = w * qt.getW() - x * qt.getX() - y * qt.getY() - z * qt.getZ();
float a = x * qt.getW() + w * qt.getX() + y * qt.getZ() - z * qt.getY();
float b = y * qt.getW() + w * qt.getY() + z * qt.getX() - x * qt.getZ();
float c = z * qt.getW() + w * qt.getZ() + x * qt.getY() - y * qt.getX();
return new Vector4F(a, b, c, o);
}