我一直在尝试制作一个游戏引擎,只是为了学习一些新东西,一切都在工作,但我决定对于照明我会创建自己的矩阵类并将最终矩阵传递给着色器。不幸的是,这最终破坏了整个渲染系统,因为现在所有东西都延伸并且绝对不对。目前我已经搞乱了乘法的顺序,但它仍然不起作用,我已经有一个多月的问题,只是想修复它并继续制作引擎。
首先,这是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;
}
}
这是当前输出的样子:
编辑:我已经尝试在将矩阵提供给着色器之前更改乘法,而不是使用矩阵乘法作为实验。这导致2D看起来正常运行,但旋转似乎使对象变小,然后翻转然后它会再次变大但此时它会被反转。
答案 0 :(得分:1)
有两件事使这种效果发生。