Java 在乘以投影矩阵后,如何渲染三角形
我正在尝试用java从头开始制作一个3d游戏,但是在我用投影矩阵乘以每个顶点之后,我在渲染三角形时遇到了一个问题 我已经尝试使用投影顶点x和y,但结果是所有顶点都在同一个x中,因此我尝试旋转三角形x或y或Z轴,但结果相同 渲染结果(在绘制中绘制): 我知道三角形与相机对齐,但我尝试通过更改其X、Y或Z坐标来移动重叠的顶点,但没有成功Java 在乘以投影矩阵后,如何渲染三角形,java,matrix,graphics,3d,render,Java,Matrix,Graphics,3d,Render,我正在尝试用java从头开始制作一个3d游戏,但是在我用投影矩阵乘以每个顶点之后,我在渲染三角形时遇到了一个问题 我已经尝试使用投影顶点x和y,但结果是所有顶点都在同一个x中,因此我尝试旋转三角形x或y或Z轴,但结果相同 渲染结果(在绘制中绘制): 我知道三角形与相机对齐,但我尝试通过更改其X、Y或Z坐标来移动重叠的顶点,但没有成功 import java.awt.Color; import java.awt.Graphics; import measurement.MatrixF; im
import java.awt.Color;
import java.awt.Graphics;
import measurement.MatrixF;
import measurement.Vector3f;
import model.Mesh;
import model.Triangle;
import toolbox.GE;
import toolbox.Matrix;
import toolbox.Vector;
public class MeshRenderer {
private int width, height;
private float fNear, fFar;
private float fov;
private float fAspectRatio;
private float fovRad;
private float theta;
private MatrixF projectionMatrix;
private MatrixF rotXMatrix;
private MatrixF rotYMatrix;
private MatrixF rotZMatrix;
private Vector3f globalTranslation;
public MeshRenderer(float fNear, float fFar, float fov, int width, int height) {
this.fNear = fNear;
this.fFar = fFar;
this.fov = fov;
this.fAspectRatio = height / width;
this.width = width;
this.height = height;
this.fovRad = (float) (1.0f / Math.tan(Math.toRadians(fov / 2)));
projectionMatrix = new MatrixF(4, 4);
rotXMatrix = new MatrixF(4, 4);
rotYMatrix = new MatrixF(4, 4);
rotZMatrix = new MatrixF(4, 4);
projectionMatrix.m[0][0] = fAspectRatio * fovRad;
projectionMatrix.m[1][1] = fovRad;
projectionMatrix.m[2][2] = (-(fFar + fNear)) / (fFar - fNear);
projectionMatrix.m[3][2] = (-2 * fFar * fNear) / (fFar - fNear);
projectionMatrix.m[2][3] = -1.0f;
projectionMatrix.m[3][3] = 0.0f;
rotXMatrix.m[0][0] = 1;
rotXMatrix.m[1][1] = (float) Math.cos(theta);
rotXMatrix.m[2][1] = (float) -Math.sin(theta);
rotXMatrix.m[1][2] = (float) Math.sin(theta);
rotXMatrix.m[2][2] = (float) Math.cos(theta);
rotYMatrix.m[0][0] = (float) Math.cos(theta);
rotYMatrix.m[2][0] = (float) Math.sin(theta);
rotYMatrix.m[1][1] = (float) 1.0;
rotYMatrix.m[0][2] = (float) -Math.sin(theta);
rotYMatrix.m[2][2] = (float) Math.cos(theta);
rotXMatrix.m[2][2] = 1;
rotXMatrix.m[0][0] = (float) Math.cos(theta);
rotXMatrix.m[1][0] = (float) -Math.sin(theta);
rotXMatrix.m[0][1] = (float) Math.sin(theta);
rotXMatrix.m[1][1] = (float) Math.cos(theta);
//projectionMatrix = Matrix.transpose(projectionMatrix);
globalTranslation = new Vector3f(0.0f, 0.0f, 0.0f);
}
public void renderMesh(Mesh mesh, Graphics g) {
for(int i = 0; i < mesh.tris.length; i++) {
Triangle tri = new Triangle(mesh.tris[i].p[0], mesh.tris[i].p[1], mesh.tris[i].p[2]);
Triangle translatedTri = tri;
Triangle projectedTri = new Triangle();
theta += 0.0001;
this.calculateRotationMatrix(theta);
translatedTri.p[0] = Matrix.multiplyMatrixVector(tri.p[0], rotYMatrix);
translatedTri.p[1] = Matrix.multiplyMatrixVector(tri.p[1], rotYMatrix);
translatedTri.p[2] = Matrix.multiplyMatrixVector(tri.p[2], rotYMatrix);
translatedTri.p[0].z = tri.p[0].z + globalTranslation.z;
translatedTri.p[1].z = tri.p[1].z + globalTranslation.z;
translatedTri.p[2].z = tri.p[2].z + globalTranslation.z;
projectedTri.p[0] = Matrix.multiplyMatrixVector(translatedTri.p[0], projectionMatrix);
projectedTri.p[1] = Matrix.multiplyMatrixVector(translatedTri.p[1], projectionMatrix);
projectedTri.p[2] = Matrix.multiplyMatrixVector(translatedTri.p[2], projectionMatrix);
projectedTri.p[0].x += 1.0f; projectedTri.p[0].y += 1.0f;
projectedTri.p[1].x += 1.0f; projectedTri.p[1].y += 1.0f;
projectedTri.p[2].x += 1.0f; projectedTri.p[2].y += 1.0f;
float scale = 0.5f;
projectedTri.p[0].x *= scale * width;
projectedTri.p[0].y *= scale * height;
projectedTri.p[1].x *= scale * width;
projectedTri.p[1].y *= scale * height;
projectedTri.p[2].x *= scale * width;
projectedTri.p[2].y *= scale * height;
GE.drawTriangle(projectedTri.p[0].x, projectedTri.p[0].y, projectedTri.p[1].x, projectedTri.p[1].y, projectedTri.p[2].x, projectedTri.p[2].y, Color.WHITE, g);
for(int j = 0; j < projectedTri.p.length; j++) {
g.setColor(new Color(255, 0, (j * 50)));
g.fillRect((int)projectedTri.p[j].x - 8, (int)projectedTri.p[j].y - 8, 16 - j, 16 - j);
}
translatedTri.p[0].z = tri.p[0].z - globalTranslation.z;
translatedTri.p[1].z = tri.p[1].z - globalTranslation.z;
translatedTri.p[2].z = tri.p[2].z - globalTranslation.z;
}
}
private void calculateRotationMatrix(float theta) {
rotXMatrix.m[0][0] = 1;
rotXMatrix.m[1][1] = (float) Math.cos(theta);
rotXMatrix.m[2][1] = (float) -Math.sin(theta);
rotXMatrix.m[1][2] = (float) Math.sin(theta);
rotXMatrix.m[2][2] = (float) Math.cos(theta);
rotYMatrix.m[0][0] = (float) Math.cos(theta);
rotYMatrix.m[2][0] = (float) Math.sin(theta);
rotYMatrix.m[1][1] = (float) 1.0;
rotYMatrix.m[0][2] = (float) -Math.sin(theta);
rotYMatrix.m[2][2] = (float) Math.cos(theta);
rotXMatrix.m[2][2] = 1;
rotXMatrix.m[0][0] = (float) Math.cos(theta);
rotXMatrix.m[1][0] = (float) -Math.sin(theta);
rotXMatrix.m[0][1] = (float) Math.sin(theta);
rotXMatrix.m[1][1] = (float) Math.cos(theta);
}
public Vector3f getTranslation() {
return globalTranslation;
}
public float getfNear() {
return fNear;
}
public float getfFar() {
return fFar;
}
public float getFov() {
return fov;
}
public float getfAspectRatio() {
return fAspectRatio;
}
public float getFovRad() {
return fovRad;
}
}
如果没有看到这个类是如何被使用的,很难说问题到底是什么,但是FWIW我没有看到数学有太多错误:
- 在一些地方,您可能打算初始化
,而不是重新初始化rotZMatrix
,但代码实际上并没有使用这两种方法rotXMatrix
- 当添加到
中时,您可能只想更新旋转的坐标,而正在使用预旋转的z坐标覆盖旋转的z坐标globaltransation
- MatrixF是初始化为恒等式还是初始化为零并不明显,但如果是后者,则可能应该使用1.0填充旋转矩阵的
元素m[3][3]
- 当然,一旦有多个三角形,您可能希望将增量和旋转计算提升到三角形循环之外
globaltransation
保留为零,并且网格靠近原点,因此变换的几何体位于近平面的错误一侧,位于视锥体的外部。大多数图形引擎都会剔除这样的几何体,因为变换后的结果将位于剪辑空间之外,并且在视点周围和后面看起来越来越不规则
我建议尝试调整globaltransation.z
,以确保所有翻译点的0
(您也可以尝试暂时将透视矩阵与正交投影矩阵交换,以确定问题是在投影/均匀化数学中还是在其他地方。)如果不了解该类是如何使用的,则很难说问题是什么,但是FWIW我认为数学没有太多错误:
- 在一些地方,您可能打算初始化
,而不是重新初始化rotZMatrix
,但代码实际上并没有使用这两种方法rotXMatrix
- 当添加到
中时,您可能只想更新旋转的坐标,而正在使用预旋转的z坐标覆盖旋转的z坐标globaltransation
- MatrixF是初始化为恒等式还是初始化为零并不明显,但如果是后者,则可能应该使用1.0填充旋转矩阵的
元素m[3][3]
- 当然,一旦有多个三角形,您可能希望将增量和旋转计算提升到三角形循环之外
globaltransation
保留为零,并且网格靠近原点,因此变换的几何体位于近平面的错误一侧,位于视锥体的外部。大多数图形引擎都会剔除这样的几何体,因为变换后的结果将位于剪辑空间之外,并且在视点周围和后面看起来越来越不规则
我建议尝试调整globaltransation.z
,以确保所有翻译点的0
(您也可以尝试暂时将透视矩阵与正交投影矩阵交换,以确定问题是在投影/均匀化数学中还是其他方面。)我尝试实现正交投影及其工作,并重新构建系统渲染代码将位于模型上(网格)本身,我使用另一种方法将矩阵和向量相乘。然后我尝试切换到透视投影,但仍然不工作。所以我认为问题在于透视投影矩阵(我将θ移到for循环之外)我试着实现正交投影和它应该做的工作,我重新构建了系统,渲染代码将在模型(网格)上我用另一种方法乘以矩阵和向量。然后我试着换成透视投影,但我仍然不工作。所以我想问题出在透视投影矩阵上(我把θ移到for循环之外)
Vector3f o = new Vector3f(0, 0, 0);
o.x = (i.x * m.m[0][0]) + (i.y * m.m[1][0]) + (i.z * m.m[2][0]) + m.m[3][0];
o.y = (i.x * m.m[0][1]) + (i.y * m.m[1][1]) + (i.z * m.m[2][1]) + m.m[3][1];
o.z = (i.x * m.m[0][2]) + (i.y * m.m[1][2]) + (i.z * m.m[2][2]) + m.m[3][2];
float w = (i.x * m.m[0][3]) + (i.y * m.m[1][3]) + (i.z * m.m[2][3]) + m.m[3][3];
if (w != 0.0f)
{
o.x /= w; o.y /= w; o.z /= w;
}
return o;
}