Created
November 9, 2010 17:01
-
-
Save wasabili/669389 to your computer and use it in GitHub Desktop.
DIY 3D Library
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import java.awt.*; | |
import java.awt.event.*; | |
import javax.swing.*; | |
import javax.swing.event.*; | |
import java.io.*; | |
import java.util.*; | |
import static java.lang.Math.*; | |
public class Test extends JPanel { | |
private ArrayList<Vertex> vertices = null; | |
private ArrayList<Face> faces = null; | |
private Point center = null; | |
private Point mousePos = null; | |
private double scale; | |
private double phi; // x axis | |
private double theta; // y axis | |
private int WIDTH; | |
private int HEIGHT; | |
public Test(int width, int height) { | |
super(true); | |
this.WIDTH = width; | |
this.HEIGHT = height; | |
this.center = new Point(WIDTH/2, HEIGHT/2); | |
this.scale = WIDTH * 0.8 / 2; | |
setSize(width, height); | |
setPreferredSize(new Dimension(WIDTH,HEIGHT)); | |
this.vertices = new ArrayList<Vertex>(); | |
this.faces = new ArrayList<Face>(); | |
this.mousePos = new Point(0,0); | |
// Angles of rotation | |
this.phi = 0.0; | |
this.theta = 0.0; | |
MouseInputListener adapter = new MouseInputAdapter() { | |
public void mouseDragged(MouseEvent e){ | |
theta += (e.getX() - mousePos.x) * 0.01; | |
phi += (e.getY() - mousePos.y) * 0.01; | |
phi = min(phi, PI/2); | |
phi = max(phi, -PI/2); | |
mousePos.setLocation(e.getX(), e.getY()); | |
refreshScreenPosition(); | |
repaint(); | |
} | |
public void mousePressed(MouseEvent e){ | |
mousePos.setLocation(e.getX(), e.getY()); | |
} | |
}; | |
addMouseMotionListener(adapter); | |
addMouseListener(adapter); | |
setModelData(); | |
} | |
public void paintComponent(Graphics g) { | |
drawModel(g); | |
} | |
private void refreshScreenPosition() { | |
for(Vertex v:vertices){ | |
v.rx = v.x * cos(theta) + v.z * sin(theta); | |
v.ry = v.x * sin(phi) * sin(theta) + v.y * cos(phi) - v.z * sin(phi) * cos(theta); | |
v.rz = -v.x * cos(phi) * sin(theta) + v.y * sin(phi) + v.z * cos(phi) * cos(theta); | |
} | |
for(Face face:faces){ | |
// refresh a depth | |
face.z = 0.0; | |
for(int i=0;i<3;i++) face.z += face.v[i].rz; | |
face.z /= 3.0; | |
double ax = face.v[1].rx - face.v[0].rx; | |
double ay = face.v[1].ry - face.v[0].ry; | |
double az = face.v[1].rz - face.v[0].rz; | |
double bx = face.v[2].rx - face.v[0].rx; | |
double by = face.v[2].ry - face.v[0].ry; | |
double bz = face.v[2].rz - face.v[0].rz; | |
face.nx = ay * bz - az * by; | |
face.ny = az * bx - ax * bz; | |
face.nz = ax * by - ay * bx; | |
double l = sqrt(face.nx * face.nx + face.ny * face.ny + face.nz * face.nz); | |
face.nx /= l; | |
face.ny /= l; | |
face.nz /= l; | |
} | |
Collections.sort(faces, new Comparator<Face>() { | |
public int compare(Face f1, Face f2) { | |
return (f1.z > f2.z)? 1:-1; | |
} | |
}); | |
} | |
public void setModelData() { | |
double modelSize = 0.0; | |
try{ | |
Scanner scn = new Scanner(new FileInputStream("file.obj")); | |
while(scn.hasNext("[vf]")){ | |
String cmd = scn.next("[vf]"); | |
if(cmd.equals("v")){ | |
double x = scn.nextDouble(); | |
double y = scn.nextDouble(); | |
double z = scn.nextDouble(); | |
modelSize = max(modelSize, x, y, z); | |
vertices.add(new Vertex(x, y, z)); | |
}else if(cmd.equals("f")){ | |
int v0 = scn.nextInt(); | |
int v1 = scn.nextInt(); | |
int v2 = scn.nextInt(); | |
faces.add(new Face(vertices.get(v0-1), | |
vertices.get(v1-1), | |
vertices.get(v2-1))); | |
} | |
} | |
}catch(Exception e){ | |
e.printStackTrace(); | |
System.exit(1); | |
} | |
System.out.println("V:"+vertices.size()+"F:"+faces.size()); | |
for(Vertex v:vertices){ | |
v.x /= modelSize; | |
v.y /= modelSize; | |
v.z /= modelSize; | |
} | |
} | |
private void drawModel(Graphics g) { | |
g.setColor(Color.WHITE); | |
g.fillRect(0,0,WIDTH,HEIGHT); | |
for(Face face:faces){ | |
int[] px = new int[3]; | |
int[] py = new int[3]; | |
for(int i=0;i<3;i++){ | |
px[i] = (int)(center.x + face.v[i].rx * scale); | |
py[i] = (int)(center.y - face.v[i].ry * scale); | |
} | |
g.setColor(Color.getHSBColor((float)0.4, (float)0.5, (float)face.nz)); | |
g.fillPolygon(px, py, 3); | |
g.setColor(Color.BLACK); | |
g.drawPolygon(px, py, 3); | |
} | |
} | |
private double max(double... args){ | |
double result = args[0]; | |
for(int i=1;i<args.length;i++){ | |
result = (result < args[i])? args[i]:result; | |
} | |
return result; | |
} | |
} | |
class Vertex { | |
public double x,y,z; | |
public double rx,ry,rz; | |
public Vertex(double x,double y,double z){ | |
this.x = x; | |
this.y = y; | |
this.z = z; | |
} | |
} | |
class Face { | |
public Vertex[] v = new Vertex[3]; | |
public double nx,ny,nz; | |
public double z; // depth | |
public Face(Vertex v0,Vertex v1,Vertex v2){ | |
v[0] = v0; | |
v[1] = v1; | |
v[2] = v2; | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment