OpenGL 2.0矩阵无法正常工作

时间:2014-09-06 13:24:57

标签: java opengl matrix lwjgl

我正在使用Java和OpenGL(LWJGL)来设置一些矩阵,我不想使用内置方法,因为我也希望这在Android上运行,因此使用LWJGL的Matrix类是不合适的。目前我正在设置透视图,使用70,znear 0.1,zfar 1000的fov。使用当前设置进行旋转只会导致奇怪的结果,而不是以正确的方式旋转,并且对象奇怪地缩放并且经常消失。

这是Matrix4D类:

public class Matrix4D {

/* The values within this matrix */
public float[] values;

/* The default constructor */
public Matrix4D() {
    //Create the values
    this.values = new float[16];
}

/* The constructor with the values given */
public Matrix4D(float[] values) {
    //Create the values
    this.values = values;
}

/* The constructor with the values given */
public Matrix4D(float[][] values) {
    //Load the values
    load(values);
}

/* The method used to set the values given a 2 dimensional array */
public void load(float[][] values) {
    this.values = new float[] {
            values[0][0], values[0][1], values[0][2], values[0][3],
            values[1][0], values[1][1], values[1][2], values[1][3],
            values[2][0], values[2][1], values[2][2], values[2][3],
            values[3][0], values[3][1], values[3][2], values[3][3]
    };
}

/* The method used to get a value using the coordinate within this matrix */
public float get(int x, int y) {
    //Get the position
    int position = x + (y * 4);
    //Return the value
    return this.values[position];
}

/* The method used to return a string representation of this matrix */
public String toString() {
    //Return the string
    return "[ " + this.values[0] + " " + this.values[1] + " " + + this.values[2] + " " + + this.values[3] + " ]" + "\n" +
           "[ " + this.values[4] + " " + this.values[5] + " " + + this.values[6] + " " + + this.values[7] + " ]" + "\n" +
           "[ " + this.values[8] + " " + this.values[9] + " " + + this.values[10] + " " + + this.values[11] + " ]" + "\n" +
           "[ " + this.values[12] + " " + this.values[13] + " " + + this.values[14] + " " + + this.values[15] + " ]";
}

/* The method used to get the values */
public float[] getValues() { return this.values; }

/* The method used to get the values in a 2D array */
public float[][] getValues2DArray() {
    //The array
    float[][] array = new float[4][4];
    //Go through each value
    int column = 0;
    int row = 0;
    while (column * row < array.length) {
        row ++;
        if (row >= 4) {
            column++;
            row = 0;
        }
        array[column][row] = this.values[column * row];
    }
    //Return the array
    return array;
}

}

这是Matrix类(用于在矩阵上设置和执行计算):

public class Matrix {

/* The different matrices */
public static Matrix4D modelMatrix = new Matrix4D();
public static Matrix4D viewMatrix = new Matrix4D();
public static Matrix4D projectionMatrix = new Matrix4D();
public static Matrix4D modelViewProjectionMatrix = new Matrix4D();

/* The static method used to load an identity matrix */
public static void loadIdentity(Matrix4D matrix) {
    //Load the identity matrix
    matrix.load(new float[][] {
            new float[] { 1, 0, 0, 0 },
            new float[] { 0, 1, 0, 0 },
            new float[] { 0, 0, 1, 0 },
            new float[] { 0, 0, 0, 1 },
    });
}

/* The static method used to add two matrices together */
public static Matrix4D add(Matrix4D matrixA, Matrix4D matrixB) {
    //Create a new matrix
    Matrix4D matrix = new Matrix4D();
    //Go through each value
    for (int a = 0; a < matrix.values.length; a++)
        //Assign the current value
        matrix.values[a] = matrixA.values[a] + matrixB.values[a];
    //Return the matrix
    return matrix;
}

/* The static method used to subtract a matrix (B) from another (A) */
public static Matrix4D subtract(Matrix4D matrixA, Matrix4D matrixB) {
    //Create a new matrix
    Matrix4D matrix = new Matrix4D();
    //Go through each value
    for (int a = 0; a < matrix.values.length; a++)
        //Assign the current value
        matrix.values[a] = matrixB.values[a] - matrixA.values[a];
    //Return the matrix
    return matrix;
}

/* The static method used to multiply two matrices together */
public static Matrix4D multiply(Matrix4D matrixA, Matrix4D matrixB) {
    //Create a new matrix
    Matrix4D matrix = new Matrix4D(new float[][] {
            new float[] {
                    (matrixA.values[0] * matrixB.values[0]) + (matrixA.values[1] * matrixB.values[4]) + (matrixA.values[2] * matrixB.values[8]) + (matrixA.values[3] * matrixB.values[12]),
                    (matrixA.values[0] * matrixB.values[1]) + (matrixA.values[1] * matrixB.values[5]) + (matrixA.values[2] * matrixB.values[9]) + (matrixA.values[3] * matrixB.values[13]),
                    (matrixA.values[0] * matrixB.values[2]) + (matrixA.values[1] * matrixB.values[6]) + (matrixA.values[2] * matrixB.values[10]) + (matrixA.values[3] * matrixB.values[14]),
                    (matrixA.values[0] * matrixB.values[3]) + (matrixA.values[1] * matrixB.values[7]) + (matrixA.values[2] * matrixB.values[11]) + (matrixA.values[3] * matrixB.values[15])
            },
            new float[] {
                    (matrixA.values[4] * matrixB.values[0]) + (matrixA.values[5] * matrixB.values[4]) + (matrixA.values[6] * matrixB.values[8]) + (matrixA.values[7] * matrixB.values[12]),
                    (matrixA.values[4] * matrixB.values[1]) + (matrixA.values[5] * matrixB.values[5]) + (matrixA.values[6] * matrixB.values[9]) + (matrixA.values[7] * matrixB.values[13]),
                    (matrixA.values[4] * matrixB.values[2]) + (matrixA.values[5] * matrixB.values[6]) + (matrixA.values[6] * matrixB.values[10]) + (matrixA.values[7] * matrixB.values[14]),
                    (matrixA.values[4] * matrixB.values[3]) + (matrixA.values[5] * matrixB.values[7]) + (matrixA.values[6] * matrixB.values[11]) + (matrixA.values[7] * matrixB.values[15])
            },
            new float[] {
                    (matrixA.values[8] * matrixB.values[0]) + (matrixA.values[9] * matrixB.values[4]) + (matrixA.values[10] * matrixB.values[8]) + (matrixA.values[11] * matrixB.values[12]),
                    (matrixA.values[8] * matrixB.values[1]) + (matrixA.values[9] * matrixB.values[5]) + (matrixA.values[10] * matrixB.values[9]) + (matrixA.values[11] * matrixB.values[13]),
                    (matrixA.values[8] * matrixB.values[2]) + (matrixA.values[9] * matrixB.values[6]) + (matrixA.values[10] * matrixB.values[10]) + (matrixA.values[11] * matrixB.values[14]),
                    (matrixA.values[8] * matrixB.values[3]) + (matrixA.values[9] * matrixB.values[7]) + (matrixA.values[10] * matrixB.values[11]) + (matrixA.values[11] * matrixB.values[15])
            },
            new float[] {
                    (matrixA.values[12] * matrixB.values[0]) + (matrixA.values[13] * matrixB.values[4]) + (matrixA.values[14] * matrixB.values[8]) + (matrixA.values[15] * matrixB.values[12]),
                    (matrixA.values[12] * matrixB.values[1]) + (matrixA.values[13] * matrixB.values[5]) + (matrixA.values[14] * matrixB.values[9]) + (matrixA.values[15] * matrixB.values[13]),
                    (matrixA.values[12] * matrixB.values[2]) + (matrixA.values[13] * matrixB.values[6]) + (matrixA.values[14] * matrixB.values[10]) + (matrixA.values[15] * matrixB.values[14]),
                    (matrixA.values[12] * matrixB.values[3]) + (matrixA.values[13] * matrixB.values[7]) + (matrixA.values[14] * matrixB.values[11]) + (matrixA.values[15] * matrixB.values[15])
            }
    });
    //Return the matrix
    return matrix;
}

/* The static method used to transpose a matrix */
public static Matrix4D transpose(Matrix4D matrix) {
    //Get the values from the matrix
    float[][] values = matrix.getValues2DArray();
    //The new values
    float[][] newValues = new float[4][4];
    //Go through the array
    for (int y = 0; y < values.length; y++) {
        for (int x = 0; x < values[y].length; x++) {
            //Assign the new value
            newValues[x][y] = values[y][x];
        }
    }
    //Return the matrix
    return new Matrix4D(newValues);
}

/* The static method used to translate a matrix */
public static Matrix4D translate(Matrix4D matrix, Vector3D vector) {
    //The transform matrix
    Matrix4D transform = new Matrix4D(new float[][] {
            new float[] { 0, 0, 0, vector.x },
            new float[] { 0, 0, 0, vector.y },
            new float[] { 0, 0, 0, vector.z },
            new float[] { 0, 0, 0, 0 },
    });
    //Add onto the matrix and return the result
    return add(matrix, transform);
}

/* The static method used to rotate a matrix */
public static Matrix4D rotate(Matrix4D matrix, float angle, int x, int y, int z) {
    //The transform matrix
    Matrix4D transform = new Matrix4D();
    //Calculate the values needed
    float cos = (float) Math.cos(angle);
    float sin = (float) Math.sin(angle);
    //Check the x y and z values
    if (x == 1) {
        transform.load(new float[][] {
                new float[] { 0, 0, 0, 0 },
                new float[] { 0, cos, -sin, 0 },
                new float[] { 0, sin, cos, 0 },
                new float[] { 0, 0, 0, 0 },
        });
    } else if (y == 1) {
        transform.load(new float[][] {
                new float[] { cos, 0, sin, 0 },
                new float[] { 0, 0, 0, 0 },
                new float[] { -sin, 0, cos, 0 },
                new float[] { 0, 0, 0, 0 },
        });
    } else if (z == 1) {
        transform.load(new float[][] {
                new float[] { cos, -sin, 0, 0 },
                new float[] { sin, cos, 0, 0 },
                new float[] { 0, 0, 0, 0 },
                new float[] { 0, 0, 0, 0 },
        });
    }
    //Add onto the matrix and return the result
    return add(matrix, transform);
}

/* The static method used to scale a matrix */
public static Matrix4D scale(Matrix4D matrix, Vector3D vector) {
    //The transform matrix
    Matrix4D transform = new Matrix4D(new float[][] {
            new float[] { vector.x, 0, 0, 0 },
            new float[] { 0, vector.y, 0, 0 },
            new float[] { 0, 0, vector.z, 0 },
            new float[] { 0, 0, 0, 0 },
    });
    //Add onto the matrix and return the result
    return add(matrix, transform);
}

/* The static method used to return an orthographic projection matrix */
public static Matrix4D ortho(float left, float right, float top, float bottom, float zfar, float znear) {
    return new Matrix4D(new float[][] {
            new float[] { 2 / (right - left), 0, 0, -((right + left) / (right - left)) },
            new float[] { 0, 2 / (top - bottom), 0, -((top + bottom) / (top - bottom)) },
            new float[] { 0, 0, -2 / (zfar - znear), -((zfar + znear) / (zfar - znear)) },
            new float[] { 0, 0, 0, 1 },
    });
}

/* The static method used to return a perspective projection matrix */
public static Matrix4D perspective(float fov, float aspect, float zNear, float zFar) {
    float f = (float) (1f / Math.tan(fov / 2f));
    return new Matrix4D(new float[][] {
            new float[] { f / aspect, 0, 0, 0 },
            new float[] { 0, f, 0, 0 },
            new float[] { 0, 0, (zFar + zNear) / (zFar - zNear), (2 * zFar * zNear) / (zNear - zFar) },
            new float[] { 0, 0, -1, 0 },
    });
}

}

最后,用于设置透视/正交投影的方法是:

/* The static method to setup an orthographic view given the width, height
 * znear and zfar values */
public static void setupOrtho(float width, float height, float znear , float zfar) {
    Matrix.loadIdentity(Matrix.modelMatrix);
    Matrix.loadIdentity(Matrix.viewMatrix);
    Matrix.projectionMatrix = Matrix.ortho(0, width, 0, height, znear, zfar);
}

/* The static method used to setup a perspective view given the
 * fov, z near and z far value */
public static void setupPerspective(float fov, float zNear, float zFar) {
    setupPerspective(fov, (float) (Settings.Window.Width / Settings.Window.Height), zNear, zFar);
}

/* The static method used to setup a perspective view given the
 * fov, aspect ratio, z near and z far values */
public static void setupPerspective(float fov, float aspect, float zNear, float zFar) {
    Matrix.loadIdentity(Matrix.modelMatrix);
    Matrix.loadIdentity(Matrix.viewMatrix);
    Matrix.projectionMatrix = Matrix.perspective(fov, aspect, zNear, zFar);
}

要渲染所有这些并将矩阵传递给我正在使用的着色器

    //Multiply the matrices together
    Matrix4D modelViewMatrix = Matrix.multiply(Matrix.modelMatrix, Matrix.viewMatrix);
    Matrix.modelViewProjectionMatrix = (Matrix.multiply(modelViewMatrix, Matrix.projectionMatrix));
    System.out.println(Matrix.modelViewProjectionMatrix.toString() + "\n");

在着色器中,我将当前顶点位置乘以模型视图投影marix。

以下是目前的情况。

What the output currently looks like

1 个答案:

答案 0 :(得分:1)

您似乎以错误的顺序乘以矩阵。当组合矩阵变换时,等式右边的变换将是第一次变换。

您将矩阵计算为模型×视图×投影。将此乘以矢量时,首先执行投影,然后执行视图变换,最后执行模型变换。显然这不是你想要的。

你的最终矩阵应该像Projection×View×Model一样计算,以正确的顺序进行转换。