几天前,我决定从头开始用Java创建3D引擎。因此,我为向量,矩阵和简单的GUI编写了所有类。
数学是从Youtube视频(javidx9开发)中获得启发的,但是由于我使用的是列向量,而不是相同的坐标系,所以我不得不更改一些东西。
我的问题是最终结果不是我所期望的,并且在搜索我的代码和互联网之后,我既找不到为什么它不起作用,也找不到如何使其起作用。结果应该是旋转的多维数据集,但这是发生了什么:(对不起,我无法直接放置图像)
First image,Second image,Third image,Fourth image
这里是项目的所有类:
主类:
import pckg.GUI;
public class Engine3D{
public static void main(String[] args){
GUI gui = new GUI();
gui.setVisible();
}
}
GUI类:
package pckg;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.event.ComponentEvent;
import java.awt.event.ComponentListener;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingWorker;
import math.Vector;
import pckg.tests.Cube;
public class GUI{
private JFrame main;
private JPanel jpMain;
private SwingWorker<Void,Void> worker;
private int width=500,height=500, minW=100, minH=100;
private Vector viewPoint, viewDir;
private double fov=90,far=1000,near=0.1,time=0;
public GUI(){
viewPoint = new Vector(0,0,0);
viewDir = new Vector(0,0,1);
worker = new SwingWorker<Void,Void>(){
protected Void doInBackground() throws Exception{
while(true){
synchronized(worker){
wait(25);
}
time+=0.025;
jpMain.repaint();
}
}
};
initializeMain();
}
private void initializeMain(){
main = new JFrame();
main.setSize(width, height);
main.setMinimumSize(new Dimension(minW,minH));
main.setLocationRelativeTo(null);
main.setTitle("3D Engine");
main.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
jpMain = new JPanel(){
private static final long serialVersionUID = 1L;
public void paintComponent(Graphics g){
super.paintComponent(g);
for(Triangle t:Cube.cube.get())
t.paint(g, viewPoint, viewDir, width, height, far, near, fov, time);
}
};
jpMain.setBackground(Color.black);
main.setContentPane(jpMain);
}
public void setVisible(){
main.setVisible(true);
main.setSize(width,2*height-jpMain.getHeight());
main.addComponentListener(new SizeListener());
worker.execute();
}
//Listeners
class SizeListener implements ComponentListener{
public void componentMoved(ComponentEvent e){}
public void componentShown(ComponentEvent e){}
public void componentHidden(ComponentEvent e){}
public void componentResized(ComponentEvent e){
width = jpMain.getWidth();
height = jpMain.getHeight();
}
}
}
向量类:
package math;
public class Vector{
private double x,y,z;
public Vector(){
x=0;y=0;z=0;
}
public Vector(double x,double y,double z){
this.x=x;
this.y=y;
this.z=z;
}
public double[] get(){
return new double[]{x,y,z};
}
public double getX(){
return x;
}
public double getY(){
return y;
}
public double getZ(){
return z;
}
public Vector add(Vector arg){
x+=arg.x;
y+=arg.y;
z+=arg.z;
return this;
}
public Vector sub(Vector arg){
x-=arg.x;
y-=arg.y;
z-=arg.z;
return this;
}
public Vector cross(Vector arg){
x = y*arg.z-z*arg.y;
y = z*arg.x-x*arg.z;
z = x*arg.y-y*arg.x;
return this;
}
public Vector multiply(double a){
x*=a;
y*=a;
z*=a;
return this;
}
public Vector divide(double a){
if(a!=0){
x/=a;
y/=a;
z/=a;
}
return this;
}
public Vector apply(Matrix mat){
if(mat.isSquare(3)){
double[][] coef=mat.get();
x = coef[0][0]*x+coef[0][1]*y+coef[0][2]*z;
y = coef[1][0]*x+coef[1][1]*y+coef[1][2]*z;
z = coef[2][0]*x+coef[2][1]*y+coef[2][2]*z;
return this;
}else
throw new ArithmeticException("The size of the matrix must be 3x3");
}
public Vector normalize(){
double norm = norm();
if(norm != 0 && norm !=1)
divide(norm);
return this;
}
public double dot(Vector arg){
return x*arg.x+y*arg.y+z*arg.z;
}
public double norm(){
return Math.sqrt(x*x+y*y+z*z);
}
public Vector clone(){
return new Vector(x,y,z);
}
public String toString(){
return "{"+x+", "+y+", "+z+"}";
}
}
矩阵类:
package math;
import java.util.Arrays;
public class Matrix{
private double[][] coef;
private Matrix(int row,int col){
if(row>0 && col>0)
coef = new double[row][col];
else
throw new IllegalArgumentException("Both the number of rows and columns must be strictly positive");
}
public Matrix(double[][] data){
if(data != null){
int len;
if(data[0]!=null)
if(data.length==0)
throw new IllegalArgumentException("Both the number of rows and columns must be strictly positive");
else
len = data[0].length;
else
throw new NullPointerException();
if(len==0)
throw new IllegalArgumentException("Both the number of rows and columns must be strictly positive");
for(int i=1; i<data.length;i++){
if(data[i]!=null){
if(data[i].length!=len)
throw new IllegalArgumentException("All the elements of the argument must have the same lenght");
}else
throw new NullPointerException();
}
coef = new double[data.length][len];
for(int i=0;i<data.length;i++)
for(int k=0;k<len;k++)
coef[i][k] = data[i][k];
}else
throw new NullPointerException();
}
public static Matrix fill(int row,int col,double value){
Matrix mat = new Matrix(row,col);
for(int i=0;i<row;i++)
for(int k=0;k<col;k++)
mat.coef[i][k]=value;
return mat;
}
public static Matrix identity(int size){
Matrix mat = fill(size,size,0);
for(int i=0;i<size;i++)
mat.coef[i][i]=1;
return mat;
}
public static Matrix diag(double[] data){
Matrix mat = fill(data.length,data.length,0);
for(int i=0;i<data.length;i++)
mat.coef[i][i] = data[i];
return mat;
}
public int[] size(){
return new int[]{coef.length,coef[0].length};
}
public double[][] get(){
double[][] ret = new double[coef.length][coef[0].length];
for(int i=0;i<coef.length;i++)
for(int k=0;k<coef[0].length;k++)
ret[i][k] = coef[i][k];
return ret;
}
public double get(int row,int col){
return coef[row][col];
}
public boolean isSquare(int size){
return coef.length==size && coef[0].length==size;
}
public Matrix add(Matrix mat){
int[] dim = size();
if(Arrays.equals(dim,mat.size())){
for(int i=0;i<dim[0];i++)
for(int k=0;k<dim[1];k++)
coef[i][k]+=mat.coef[i][k];
return this;
}else
throw new ArithmeticException("Both matrices must have the same size");
}
public Matrix multiply(Matrix mat){
int[] dim1=size(), dim2=mat.size();
if(dim1[1]==dim2[0]){
Matrix ret = Matrix.fill(dim1[0],dim2[1],0);
for(int i=0;i<dim1[0];i++)
for(int k=0;k<dim2[1];k++)
for(int j=0;j<dim1[0];j++)
ret.coef[i][k] += coef[i][j]*mat.coef[j][k];
return ret;
}else
throw new ArithmeticException("The sizes of the matrices do not match");
}
public Matrix multiply(double x){
int[] dim = size();
for(int i=0;i<dim[0];i++)
for(int k=0;k<dim[1];k++)
coef[i][k]*=x;
return this;
}
public String toString(){
String str="";
int[] dim = size();
for(int i=0;i<dim[0];i++){
str+="[";
for(int k=0;k<dim[1];k++)
str+=coef[i][k]+",";
str=str.substring(0,str.length()-1);
str+="]\n";
}
return str.substring(0,str.length()-1);
}
}
三角形类:
package pckg;
import java.awt.Color;
import java.awt.Graphics;
import math.Matrix;
import math.Vector;
public class Triangle{
private Vector A,B,C;
public Triangle(Vector a, Vector b, Vector c){
A=a.clone();B=b.clone();C=c.clone();
}
public double[][] get(){
return new double[][]{A.get(),B.get(),C.get()};
}
public Vector[] getVect(){
return new Vector[]{A.clone(),B.clone(),C.clone()};
}
public Triangle clone(){
return new Triangle(A.clone(),B.clone(),C.clone());
}
public String toString(){
return "["+A.toString()+", "+B.toString()+", "+C.toString()+"]";
}
public void paint(Graphics g, Vector vPoint, Vector vDir, int width, int height, double far, double near, double fov, double time){
double F = 1/Math.tan((fov*Math.PI)/360);
Vector vect[] = new Vector[]{A.clone(),B.clone(),C.clone()}/*, mid = new Vector(0,0,0), pos[]=new Vector[3]*/;
Matrix proj = Matrix.diag(new double[]{((double)height/width)*F,F,far/(far-near)}),
scale = Matrix.diag(new double[]{-width/2,-height/2,1}),
rot = (new Matrix(new double[][] {{Math.cos(time),-Math.sin(time),0},{Math.sin(time),Math.cos(time),0},{0,0,1}})).multiply(
new Matrix(new double[][] {{1,0,0},{0,Math.cos(time/2),-Math.sin(time/2)},{0,Math.sin(time/2),Math.cos(time/2)}}));
//Transformation
for(Vector v:vect)
v.apply(rot).add(new Vector(0,0,3));
//Projection
for(Vector v:vect){
double z;
z = v.getZ();
v.apply(proj).sub(new Vector(0,0,near*far/(far-near))).divide(z);
v.sub(new Vector(1,1,0)).apply(scale);
}
g.setColor(Color.white);
g.drawPolygon(new int[]{((Number)(vect[0].getX()+0.5)).intValue(),((Number)(vect[1].getX()+0.5)).intValue(),((Number)(vect[2].getX()+0.5)).intValue()},
new int[]{((Number)(vect[0].getY()+0.5)).intValue(),((Number)(vect[1].getY()+0.5)).intValue(),((Number)(vect[2].getY()+0.5)).intValue()}, 3);
}
}
我为尝试显示的多维数据集做了一个枚举:
package pckg.tests;
import java.util.Arrays;
import math.Vector;
import pckg.Triangle;
public enum Cube{
cube (new Vector(1,0,0),new Vector(1,1,0),new Vector(0,1,0),new Vector(0,0,0),new Vector(0,0,1),new Vector(0,1,1),new Vector(1,1,1),new Vector(1,0,1));
public final Triangle[] faces;
private Cube(Vector a, Vector b, Vector c, Vector d, Vector e, Vector f, Vector g, Vector h){
faces = new Triangle[12];
//South
faces[0] = new Triangle(a,b,c);
faces[1] = new Triangle(c,d,a);
//East
faces[2] = new Triangle(d,c,f);
faces[3] = new Triangle(f,e,d);
//North
faces[4] = new Triangle(e,f,g);
faces[5] = new Triangle(g,h,e);
//West
faces[6] = new Triangle(h,g,b);
faces[7] = new Triangle(b,a,h);
//Up
faces[8] = new Triangle(b,g,f);
faces[9] = new Triangle(f,c,b);
//Down
faces[10] = new Triangle(a,d,e);
faces[11] = new Triangle(e,h,a);
}
public Triangle[] get(){
return Arrays.copyOf(faces, 12);
}
}
如前所述,某些事情并没有达到我想要的状态,但是我找不到位置。任何帮助将不胜感激。