我目前正在opengl中构建一个场景图,并尝试在其子对象上对父对象转换进行建模,但它似乎不起作用(
我的主要问题是孩子的旋转没有正确地跟随父母的旋转。子对象围绕父对象(中心)旋转,这是它应该做的,但是它围绕父对象旋转的速度随着父对象旋转的增加而增加,并且在父对象旋转一整圈后(当父对象的旋转回到其开始的旋转时)会减慢。此外,我确实在正确翻译孩子与父母的关系方面遇到了一些问题,但我设法暂时解决了这些问题(我想)。更多信息在代码中。很抱歉解释得太长了,如果可以的话,我肯定会附上一段视频,说明这个问题。
这是我的transform类,其中设置了转换,特别是 getTransformation()
方法:
public class Transform {
private Vector3f position, lastPosition;
private Vector3f rotation, lastRotation;
private Vector3f scale, lastScale;
private Transform parent;
private Matrix4f parentMatrix;
public Transform() {
this(null, null, null);
}
public Transform(Vector3f position, Vector3f rotation, Vector3f scale) {
this.position = position != null ? position : new Vector3f(0, 0, 0);
this.rotation = rotation != null ? rotation : new Vector3f(0, 0, 0);
this.scale = scale != null ? scale : new Vector3f(1, 1, 1);
this.lastPosition = new Vector3f(0, 0, 0);
this.lastRotation = new Vector3f(0, 0, 0);
this.lastScale = new Vector3f(1, 1, 1);
parentMatrix = new Matrix4f().identity();
}
public boolean requireTMUpdate() { //checks if the matrix has changed and requires an update
if(parent != null) {
return parent.requireTMUpdate();
}
if(!position.equals(lastPosition)) {
lastPosition.set(position);
return true;
}
if(!rotation.equals(lastRotation)) {
lastRotation.set(rotation);
return true;
}
if(!scale.equals(lastScale)) {
lastScale.set(scale);
return true;
}
return false;
}
public Matrix4f getTransformation() {
if((parent != null) && (requireTMUpdate())) {
if(!(getParent().equals(getParent().getParent()))) {
parentMatrix.set(parent.getTransformation());
//The above line sets the updated parentMatrix
setPosition(parentMatrix.transformPosition(position));
//The above line sets the position to where child is supposed to be in
//relation the parent, otherwise once the key is stopped being pressed,
//it will return to the position at the start of the game / program.
}
}else {
parentMatrix.rotationXYZ(0, 0, 0).translation(0, 0, 0).scale(1);
// The above line is supposed to reset the matrix, otherwise the previous
//transformations or rotations add up each frame and the it just gets messed
//up.
}
//System.out.println(parentMatrix.toString());
return parentMatrix.mul(Matrices.transformationMatrix(position, rotation, scale))
// The transformationMatrix() method above from the Matrices class is
//supposed to return a worldMatrix.
}
public Vector3f getPosition() {
return position;
}
public void setPosition(Vector3f position) {
this.position = position;
}
public Vector3f getRotation() {
return rotation;
}
public void setRotation(Vector3f rotation) {
this.rotation = rotation;
}
public Vector3f getScale() {
return scale;
}
public void setScale(Vector3f scale) {
this.scale = scale;
}
public Transform getParent() {
return parent;
}
public void setParent(Transform parent) {
this.parent = parent;
}
}
矩阵类:
public class Matrices {
public static Matrix4f transformationMatrix(Vector3f pos, Vector3f rot, Vector3f scale) {
Matrix4f result = new Matrix4f();
result.identity();
result.translate(pos.x, pos.y, pos.z);
Quaternionf rotation =
new Quaternionf().
identity().
rotateX((float) Math.toRadians(rot.x)).
rotateY((float) Math.toRadians(rot.y)).
rotateZ((float) Math.toRadians(rot.z));
/*result.rotate((float) Math.toRadians(rot.getX()), 1, 0, 0);
result.rotate((float) Math.toRadians(rot.getY()), 0, 1, 0);
result.rotate((float) Math.toRadians(rot.getZ()), 0, 0, 1);*/
result.rotate(rotation);
result.scale(scale.x, scale.y, scale.z);
return result;
}
public static Matrix4f transformationMatrix(Vector3f pos, Quaternionf rotation, Vector3f scale) {
Matrix4f result = new Matrix4f();
result.identity();
result.translate(pos.x, pos.y, pos.z);
/*Quaternionf rotation =
new Quaternionf().
identity().
rotateX((float) Math.toRadians(rot.x)).
rotateY((float) Math.toRadians(rot.y)).
rotateZ((float) Math.toRadians(rot.z));*/
/*result.rotate((float) Math.toRadians(rot.getX()), 1, 0, 0);
result.rotate((float) Math.toRadians(rot.getY()), 0, 1, 0);
result.rotate((float) Math.toRadians(rot.getZ()), 0, 0, 1);*/
result.rotate(rotation);
result.scale(scale.x, scale.y, scale.z);
return result;
}
public static Matrix4f viewMatrix(Vector3f pos, Vector3f rot) {
Matrix4f result = new Matrix4f();
result.identity();
Quaternionf rotation =
new Quaternionf().
identity().
rotateX((float) Math.toRadians(rot.x)).
rotateY((float) Math.toRadians(rot.y)).
rotateZ((float) Math.toRadians(rot.z));
/*result.rotate((float) Math.toRadians(rot.getX()), new org.joml.Vector3f(1, 0, 0));
result.rotate((float) Math.toRadians(rot.getY()), new org.joml.Vector3f(0, 1, 0));*/
result.rotate(rotation);
result.translate(-pos.x, -pos.y, -pos.z);
return result;
}
public static Matrix4f viewMatrix(Vector3f pos, float pitch, float yaw, float roll) {
Matrix4f result = new Matrix4f();
result.identity();
Quaternionf rotation =
new Quaternionf().
identity().
rotateX((float) Math.toRadians(pitch)).
rotateY((float) Math.toRadians(yaw)).
rotateZ((float) Math.toRadians(roll));
/*result.rotate((float) Math.toRadians(rot.getX()), new org.joml.Vector3f(1, 0, 0));
result.rotate((float) Math.toRadians(rot.getY()), new org.joml.Vector3f(0, 1, 0));*/
result.rotate(rotation);
result.translate(-pos.x, -pos.y, -pos.z);
return result;
}
public static Matrix4f projectionMatrix(float FOV, float aspectRatio,
float NearPlaneDis, float FarPlaneDis) {
Matrix4f result = new Matrix4f();
result.identity();
result.perspective(FOV, aspectRatio, NearPlaneDis, FarPlaneDis);
/*float y_scale = (float) ((1f / Math.tan(Math.toRadians(FOV / 2f))) * aspectRatio);
float x_scale = y_scale / aspectRatio;
float frustum_length = FarPlaneDis - NearPlaneDis;
result.m00(x_scale);
result.m11(y_scale);
result.m22(-((FarPlaneDis + NearPlaneDis) / frustum_length));
result.m23(-1);
result.m32(-((2 * NearPlaneDis * FarPlaneDis) / frustum_length));
result.m33(0);*/
return result;
}
public static Matrix4f translate(Vector3f vec, Matrix4f src, Matrix4f dest) {
if (dest == null)
dest = new Matrix4f();
dest.m30(dest.m30() + src.m00() * vec.x + src.m10() * vec.y + src.m20() * vec.z);
dest.m31(dest.m31() + src.m01() * vec.x + src.m11() * vec.y + src.m21() * vec.z);
dest.m32(dest.m32() + src.m02() * vec.x + src.m12() * vec.y + src.m22() * vec.z);
dest.m33(dest.m33() + src.m03() * vec.x + src.m13() * vec.y + src.m23() * vec.z);
return dest;
}
public static Vector4f transform(Matrix4f left, Vector4f right, Vector4f dest) {
if (dest == null)
dest = new Vector4f(0, 0, 0, 0);
float x = left.m00() * right.x + left.m10() * right.y + left.m20() * right.z + left.m30() * right.w;
float y = left.m01() * right.x + left.m11() * right.y + left.m21() * right.z + left.m31() * right.w;
float z = left.m02() * right.x + left.m12() * right.y + left.m22() * right.z + left.m32() * right.w;
float w = left.m03() * right.x + left.m13() * right.y + left.m23() * right.z + left.m33() * right.w;
dest.x = x;
dest.y = y;
dest.z = z;
dest.w = w;
return dest;
}
public static Vector3f scale(Vector3f vector, float scale) {
vector.x *= scale;
vector.y *= scale;
vector.z *= scale;
return vector;
}
public static float[] getAll(Matrix4f matrix) {
float[] f = new float[16];
return matrix.get(f);
}
public static float barryCentric(Vector3f p1, Vector3f p2, Vector3f p3, Vector2f pos) {
float det = (p2.z - p3.z) * (p1.x - p3.x) + (p3.x - p2.x) * (p1.z - p3.z);
float l1 = ((p2.z - p3.z) * (pos.x - p3.x) + (p3.x - p2.x) * (pos.y - p3.z)) / det;
float l2 = ((p3.z - p1.z) * (pos.x - p3.x) + (p1.x - p3.x) * (pos.y - p3.z)) / det;
float l3 = 1.0f - l1 - l2;
return l1 * p1.y + l2 * p2.y + l3 * p3.y;
}
}
最后是渲染器类,在该类中初始化对象:
public class Renderer {
private Model model;
private Model model2;
private GameObject root;
private GameObject child;
public Camera camera;
private float time = 0;
/*private float vertices[] = {
0.5f, 0.5f, 0f, //0 - top right
0.5f, -0.5f, 0f, //1 - bottom right
-0.5f, -0.5f, 0f, //2 - bottom left
-0.5f, 0.5f, 0f //3 - top left
};
private int indices[] = {
0, 1, 3, // first triangle
3, 1, 2 // second triangle
};*/
public Renderer() {
model = new Model("/backpack.obj");
model2 = new Model("/backpack.obj");
camera = new Camera(new Vector3f(0, 0, 0), new Vector3f(0, 0, 0));
root = new GameObject();
child = new GameObject();
root.addComponent(camera);
root.addComponent(model);
child.addComponent(model2);
root.addChild(child);
model.getTransform().setPosition(new Vector3f(0, 0, 0));
model2.getTransform().setPosition(new Vector3f(10, 0, 10));
}
public void render(Shader shader) {
if(Input.isKeyDown(GLFW.GLFW_KEY_RIGHT)) {
model.getTransform().setRotation(new Vector3f(0, time += 1f, 0));
}
//model2.getTransform().setRotation(new Vector3f(0, time += 0.01f, 0));
shader.bind();
root.input();
root.update();
root.render(shader, camera);
shader.unbind();
}
public void cleanUp() {
for(Mesh mesh: model.getMeshes()) {
mesh.cleanUp();
}
}
}
我到底做错了什么?感谢您的帮助!
1条答案
按热度按时间g2ieeal71#
nvm,经过一天的调试,我找到了解决方案:
这一行:
return parentMatrix.mul(Matrices.transformationMatrix(position, rotation, scale));
实际上应该是:return new Matrix4f(parentMatrix).mul(Matrices.transformationMatrix(position, rotation, scale));
.结果是
mul
joml matrix4f类中的方法不返回新的Matrix4f()
应该输出的worldmatrix类将其乘以当前矩阵(parentMatrix
这里)本身,创建一个完全不同的parentMatrix
下一帧。