2014-10-11 47 views
-1

我一直在试图制作一个游戏引擎,只是为了学习一些新的东西,一切都在工作,但我决定照明,我会做我自己的矩阵类并将最终矩阵传递给着色器。不幸的是,这最终导致整个渲染系统崩溃,因为现在所有东西都已经延伸并且绝对不对。目前我已经搞乱了乘法的顺序,但它仍然不起作用,我有这个问题超过一个月,只是想解决它,并继续制作引擎。OpenGL矩阵奇怪的转换

首先,这里是在PC上使用的默认着色器:

public static final String[] pcVertexShaderCode = new String[] { 
    "attribute vec4 andor_vertexPosition;", 
    "attribute vec3 andor_normal;", 
    "attribute vec2 andor_vtextureCoord;", 
    "attribute vec4 andor_vcolour;", 
    "uniform mat4 andor_modelmatrix;", 
    "uniform mat4 andor_viewmatrix;", 
    "uniform mat4 andor_projectionmatrix;", 
    "uniform mat4 andor_modelviewprojectionmatrix;", 
    "varying vec4 andor_colour;", 
    "varying vec2 andor_textureCoord;", 
    "void andor_main();", 
    "void main() {", 
    " andor_colour = andor_vcolour;", 
    " andor_textureCoord = andor_vtextureCoord;", 
    // " andor_modelviewprojectionmatrix = andor_modelmatrix * andor_viewmatrix * andor_projectionmatrix;", 
    " gl_Position = andor_modelviewprojectionmatrix * andor_vertexPosition;", 
    " andor_main();", 
    "}" }; 

public static final String[] pcFragmentShaderCode = new String[] { 
    "uniform sampler2D andor_texture;", 
    "uniform float andor_hasTexture;", 
    "varying vec4 andor_colour;", 
    "varying vec2 andor_textureCoord;", 
    "void andor_main();", 
    "void main() {", 
    " if (andor_hasTexture > 0.5) {", 
    " gl_FragColor = andor_colour * texture2D(andor_texture, andor_textureCoord);", 
    " } else {", 
    " gl_FragColor = andor_colour;", 
    " }", 
    " andor_main();", 
    "}" }; 

这渲染方法,该方法是由每个对象在场景中称为:用于

/* The method used to draw the object */ 
    public void render() { 
     //Multiply the matrices together 
     Matrix4D projectionViewMatrix = Matrix.multiply(Matrix.projectionMatrix, Matrix.viewMatrix); 
     Matrix.modelViewProjectionMatrix = (Matrix.multiply(projectionViewMatrix, Matrix.modelMatrix)); 

     //Sky box in relatively the right place 
//  Matrix4D modelViewMatrix = Matrix.multiply(Matrix.modelMatrix, Matrix.viewMatrix); 
//  Matrix.modelViewProjectionMatrix = (Matrix.multiply(modelViewMatrix, Matrix.projectionMatrix)); 

//  Matrix4D modelProjectionMatrix = Matrix.multiply(Matrix.modelMatrix, Matrix.projectionMatrix); 
//  Matrix.modelViewProjectionMatrix = (Matrix.multiply(Matrix.viewMatrix, modelProjectionMatrix)); 

//  Matrix4D modelViewMatrix = Matrix.multiply(Matrix.modelMatrix, Matrix.viewMatrix); 
//  Matrix.modelViewProjectionMatrix = (modelViewMatrix); 

//  //TEST 
//  for (int a = 0; a < 16; a++) { 
//   //2D WORKS!!!!! Kind of... 
//   Matrix.modelViewProjectionMatrix.values[a] = Matrix.modelMatrix.values[a] * Matrix.projectionMatrix.values[a] * Matrix.viewMatrix.values[a]; 
//  } 
     System.out.println(Matrix.modelViewProjectionMatrix.toString() + "\n"); 
     //Set the correct android shader 
     Shader shader = defaultShader; 
     if (currentShader != null) 
      shader = currentShader; 
     //Use the shader program 
     GL20.glUseProgram(shader.program); 
     //Enable the arrays as needed 
     int vertexPositionAttribute = shader.getAttributeLocation("andor_vertexPosition"); 
     int normalAttribute = 0; 
     int colourAttribute = 0; 
     int texturesAttribute = 0; 
     int modelMatrixAttribute = shader.getUniformLocation("andor_modelmatrix"); 
     int viewMatrixAttribute = shader.getUniformLocation("andor_viewmatrix"); 
     int projectionMatrixAttribute = shader.getUniformLocation("andor_projectionmatrix"); 
     int matrixAttribute = shader.getUniformLocation("andor_modelviewprojectionmatrix"); 
     GL20.glUniformMatrix4(modelMatrixAttribute, false, BufferUtils.createFlippedBuffer(Matrix.modelMatrix.getValues())); 
     GL20.glUniformMatrix4(viewMatrixAttribute, false, BufferUtils.createFlippedBuffer(Matrix.viewMatrix.getValues())); 
     GL20.glUniformMatrix4(projectionMatrixAttribute, false, BufferUtils.createFlippedBuffer(Matrix.projectionMatrix.getValues())); 
     GL20.glUniformMatrix4(matrixAttribute, false, BufferUtils.createFlippedBuffer(Matrix.modelViewProjectionMatrix.getValues())); 
     GL20.glEnableVertexAttribArray(vertexPositionAttribute); 
     GL15.glBindBuffer(GL15.GL_ARRAY_BUFFER, this.verticesHandle); 
     GL20.glVertexAttribPointer(vertexPositionAttribute, this.vertexValuesCount, GL11.GL_FLOAT, false, 0, 0); 
     if (this.normalsData != null) { 
      normalAttribute = shader.getAttributeLocation("andor_normal"); 
      GL20.glEnableVertexAttribArray(normalAttribute); 
      GL15.glBindBuffer(GL15.GL_ARRAY_BUFFER, this.normalsHandle); 
      GL20.glVertexAttribPointer(normalAttribute, this.vertexValuesCount, GL11.GL_FLOAT, false, 0, 0); 
     } 
     if (this.colourData != null) { 
      colourAttribute = shader.getAttributeLocation("andor_vcolour"); 
      GL20.glEnableVertexAttribArray(colourAttribute); 
      GL15.glBindBuffer(GL15.GL_ARRAY_BUFFER, this.coloursHandle); 
      GL20.glVertexAttribPointer(colourAttribute, this.colourValuesCount, GL11.GL_FLOAT, false, 0, 0); 
     } 
     if (this.textureData != null) { 
      texturesAttribute = shader.getAttributeLocation("andor_vtextureCoord"); 
      GL15.glBindBuffer(GL15.GL_ARRAY_BUFFER, this.texturesHandle); 
      GL20.glEnableVertexAttribArray(texturesAttribute); 
      GL20.glVertexAttribPointer(texturesAttribute, this.textureValuesCount, GL11.GL_FLOAT, false, 0, 0); 
      GL20.glUniform1i(shader.getUniformLocation("andor_texture"), 0); 
      if (texture != null) 
       GL20.glUniform1f(shader.getUniformLocation("andor_hasTexture"), 1f); 
     } 
     if (this.drawOrder != null) { 
      GL15.glBindBuffer(GL15.GL_ELEMENT_ARRAY_BUFFER, this.drawOrderHandle); 
      GL11.glDrawElements(this.renderMode, this.drawOrder.length, GL11.GL_UNSIGNED_SHORT, 0); 
      GL15.glBindBuffer(GL15.GL_ELEMENT_ARRAY_BUFFER, 0); 
     } else { 
      //Draw the arrays 
      GL11.glDrawArrays(this.renderMode, 0, this.verticesData.length/this.vertexValuesCount); 
     } 
     //Disable the arrays as needed 
     if (this.normalsData != null) 
      GL20.glDisableVertexAttribArray(normalAttribute); 
     if (this.textureData != null) 
      GL20.glDisableVertexAttribArray(texturesAttribute); 
     if (this.colourData != null) 
      GL20.glDisableVertexAttribArray(colourAttribute); 
     GL20.glDisableVertexAttribArray(vertexPositionAttribute); 
     //Stop using the shader program 
     GL20.glUseProgram(0); 
    } 

然后这里的方法在渲染之前将翻译应用于场景中的物体:

/* The method used to update the current view matrix */ 
public void updateViewMatrix() { 
    //Get the position 
    Vector3D p = this.getPosition(); 
    //Get the rotation 
    Vector3D r = this.getRotation(); 
    //Get the scale 
    Vector3D s = this.getScale(); 
    //Save the current matrix 
    clone = Arrays.copyOf(Matrix.modelMatrix.getValues(), 16); 
    //Scale by the specified amount 
    Matrix.modelMatrix = Matrix.scale(Matrix.modelMatrix, s); 
    //Rotate by the specified amount 
    Matrix.modelMatrix = Matrix.rotate(Matrix.modelMatrix, r.x, 1, 0, 0); 
    Matrix.modelMatrix = Matrix.rotate(Matrix.modelMatrix, r.y, 0, 1, 0); 
    Matrix.modelMatrix = Matrix.rotate(Matrix.modelMatrix, r.z, 0, 0, 1); 
    //Move to the correct position 
    Matrix.modelMatrix = Matrix.translate(Matrix.modelMatrix, p); 
} 

/* The method used to restore the current view matrix */ 
public void restoreViewMatrix() { 
    //Restore the current matrix 
    Matrix.modelMatrix.values = clone; 
} 

在摄像机类中,这是用于移动玩家查看:

//Get the rotation 
    Vector3D r = this.getRotation(); 
    //Get the position 
    Vector3D p = this.getPosition(); 
    //Get the scale 
    Vector3D s = this.getScale(); 
    //Rotate by the specified amount 
    Matrix.viewMatrix = Matrix.rotate(Matrix.viewMatrix, r.x, 1, 0, 0); 
    Matrix.viewMatrix = Matrix.rotate(Matrix.viewMatrix, r.y, 0, 1, 0); 
    Matrix.viewMatrix = Matrix.rotate(Matrix.viewMatrix, r.z, 0, 0, 1); 

    //Move to the correct position 
    Matrix.viewMatrix = Matrix.translate(Matrix.viewMatrix, p); 

    //Scale by the correct amount 
    Matrix.viewMatrix = Matrix.scale(Matrix.viewMatrix, s); 

这里是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类:

package org.andor.core; 

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[] { 1, 0, 0, vector.x }, 
       new float[] { 0, 1, 0, vector.y }, 
       new float[] { 0, 0, 1, vector.z }, 
       new float[] { 0, 0, 0, 1 }, 
     }); 
     //Add onto the matrix and return the result 
     return multiply(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[] { 1, 0, 0, 0 }, 
        new float[] { 0, cos, -sin, 0 }, 
        new float[] { 0, sin, cos, 0 }, 
        new float[] { 0, 0, 0, 1 }, 
      }); 
     } else if (y == 1) { 
      transform.load(new float[][] { 
        new float[] { cos, 0, sin, 0 }, 
        new float[] { 0, 1, 0, 0 }, 
        new float[] { -sin, 0, cos, 0 }, 
        new float[] { 0, 0, 0, 1 }, 
      }); 
     } else if (z == 1) { 
      transform.load(new float[][] { 
        new float[] { cos, -sin, 0, 0 }, 
        new float[] { sin, cos, 0, 0 }, 
        new float[] { 0, 0, 1, 0 }, 
        new float[] { 0, 0, 0, 1 }, 
      }); 
     } 
     //Add onto the matrix and return the result 
     return multiply(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, 1 }, 
     }); 
     //Add onto the matrix and return the result 
     return multiply(matrix, transform); 
    } 

    /* The static method used to return an orthographic projection matrix */ 
    public static Matrix4D ortho(float left, float right, float bottom, float top, float zfar, float znear) { 
//  Matrix4D mat = new Matrix4D(); 
//  mat.values[0] = 2/(right - left); 
//  mat.values[5] = 2/(top - bottom); 
//  mat.values[10] = - 2/(zfar - znear); 
//  mat.values[12] = - (right + left)/(right - left); 
//  mat.values[13] = -(top + bottom)/(top - bottom); 
//  mat.values[14] = -(zfar + znear)/(zfar - znear); 
//  return mat; 
     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) { 
     //Calculate the values that need to be calculated the most frequently 
     float f = 1.0f/(float) Math.tan(fov/2 * (Math.PI/360.0)); 
     float rangeReciprocal = 1.0f/(zNear - zFar); 

     Matrix4D matrix = new Matrix4D(); 

     //Set the matrix values 
     matrix.values[0] = f/aspect; 
     matrix.values[1] = 0.0f; 
     matrix.values[2] = 0.0f; 
     matrix.values[3] = 0.0f; 

     matrix.values[4] = 0.0f; 
     matrix.values[5] = f; 
     matrix.values[6] = 0.0f; 
     matrix.values[7] = 0.0f; 

     matrix.values[8] = 0.0f; 
     matrix.values[9] = 0.0f; 
     matrix.values[10] = (zFar + zNear) * rangeReciprocal; 
     matrix.values[11] = -1.0f; 

     matrix.values[12] = 0.0f; 
     matrix.values[13] = 0.0f; 
     matrix.values[14] = 2.0f * zFar * zNear * rangeReciprocal; 
     matrix.values[15] = 0.0f; 
     return matrix; 
    } 
} 

这是电流输出的样子:

enter image description here

编辑:我自从尝试改变乘法之前给矩阵着色器不使用矩阵乘法作为实验。这导致2D显示为正确的炒锅,但旋转看起来会使对象变小,然后翻转然后它会再次变大,但此时它会翻转。

+0

不幸的是我仍然不知道是什么问题。 : – 2851999 2014-10-26 10:59:42

回答

1

发生这种情况有两件事。

  1. 所需的矩阵在着色器
  2. 使用矩阵前被调换的投影矩阵不会工作,除非znear值为1以上
+0

'znear> = 1'不是视角矩阵的必要条件,但通常它必须是正数 – derhass 2014-11-09 13:38:25

+0

奇怪的是它是如何发生的,我想在矩阵乘法中,其中一个值减少而不是减少,因为它是乘以一个小于1的值。 – 2851999 2014-11-09 18:19:45

+0

将nearVal设置为1固定了一个透视翘曲问题,谢谢。 – rsethc 2015-02-17 16:38:49