转换层次结构(在子级上建模父级转换的问题),opengl,LWJGL3

mznpcxlj  于 2021-09-13  发布在  Java
关注(0)|答案(1)|浏览(252)

我目前正在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();
        }
    }
}

我到底做错了什么?感谢您的帮助!

g2ieeal7

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 下一帧。

相关问题