Sign in to follow this  
yaazz

Need help with rotating 3d objects (java)

Recommended Posts

Hello all, I got the 2d stuff working fantastic, now I am trying to rotate 3d objects. The code seems to work, but the objects always warp over time, can you tell me what I am doing wrong? PS this is java code
import javax.swing.*;
import java.awt.*;


class rotation extends JPanel
{
	 double[][] rotX;
	 double[][] rotY;
	 double[][] rotZ;
	 
	 double[] p1 = {225,225,100,0};
	 double[] p2 = {250,250,100,0};
	 double[] p3 = {225,250,100,0};
	 double[] p4 = {250,225,100,0};
	 
	 double[] p5 = {225,225,125,0};
	 double[] p6 = {250,250,125,0};
	 double[] p7 = {225,250,125,0};
	 double[] p8 = {250,225,125,0};
public rotation()
{

	setPreferredSize(new Dimension(640,480));
	setVisible(true);
	 rotX = new double[4][4];
	 rotY = new double[4][4];
	 rotZ = new double[4][4];

}

public void paintComponent(Graphics page)
{

	page.setColor(Color.black);
	page.fillRect(0,0,getSize().width,getSize().height);

	page.setColor(Color.red);
	page.drawLine((int)p1[0],(int)p1[1],(int)p3[0],(int)p3[1]);
	page.setColor(Color.yellow);
	page.drawLine((int)p3[0],(int)p3[1],(int)p2[0],(int)p2[1]);
	page.setColor(Color.green);
	page.drawLine((int)p2[0],(int)p2[1],(int)p4[0],(int)p4[1]);
	page.setColor(Color.blue);
	page.drawLine((int)p4[0],(int)p4[1],(int)p1[0],(int)p1[1]);
	
	
	page.setColor(Color.red);
	page.drawLine((int)p5[0],(int)p5[1],(int)p7[0],(int)p7[1]);
	page.setColor(Color.yellow);
	page.drawLine((int)p7[0],(int)p7[1],(int)p6[0],(int)p6[1]);
	page.setColor(Color.green);
	page.drawLine((int)p6[0],(int)p6[1],(int)p8[0],(int)p8[1]);
	page.setColor(Color.blue);
	page.drawLine((int)p8[0],(int)p8[1],(int)p5[0],(int)p5[1]);
	
	page.setColor(Color.red);
	page.drawLine((int)p1[0],(int)p1[1],(int)p5[0],(int)p5[1]);
	page.setColor(Color.yellow);
	page.drawLine((int)p3[0],(int)p3[1],(int)p7[0],(int)p7[1]);
	page.setColor(Color.green);
	page.drawLine((int)p4[0],(int)p4[1],(int)p8[0],(int)p8[1]);
	page.setColor(Color.blue);
	page.drawLine((int)p2[0],(int)p2[1],(int)p6[0],(int)p6[1]);	
	page.drawString("p1[0]="+(int)p1[0]+" p1[1]="+(int)p1[1],30,100);
	page.drawString("p2[0]="+(int)p2[0]+" p2[1]="+(int)p1[1],30,150);
	page.drawString("p3[0]="+(int)p3[0]+" p3[1]="+(int)p1[1],30,200);
	page.drawString("p4[0]="+(int)p4[0]+" p4[1]="+(int)p1[1],30,250);
	

}

public double[] rotate(double[] vector, double originX, double originY, double originZ)
{
	
	System.out.println("rotate" );
	double[] temp;
	vector[0] -= originX;
    vector[1] -= originY;
	vector[2] -= originZ;
	
	temp=matMult(rotZ,vector);
	
	
	temp[0] += originX;
	temp[1] += originY;
	temp[2] += originZ;
	
	return temp;
}

public double[] scale(double x, double y,double scale, double originX, double originY)
{
	System.out.println("rotate" );
	double[] temp=new double[2];
	
	x -= originX;
	y -= originY;
	
	temp[0]= x * scale;
	temp[1]= y * scale;
	
	temp[0] += originX;
	temp[1] += originY;
	
	return temp;
}

public void loop()
{
	while (true)
	{
		createMatricies(10.0);
		p1=rotate(p1,(p1[0]+p2[0])/2,(p1[1]+p2[1])/2,(p1[2]+p5[2])/2);
		p3=rotate(p3,(p1[0]+p2[0])/2,(p1[1]+p2[1])/2,(p1[2]+p5[2])/2);
		p2=rotate(p2,(p1[0]+p2[0])/2,(p1[1]+p2[1])/2,(p1[2]+p5[2])/2);
		p4=rotate(p4,(p1[0]+p2[0])/2,(p1[1]+p2[1])/2,(p1[2]+p5[2])/2);
		p5=rotate(p5,(p1[0]+p2[0]+p3[0]+p4[0]+p5[0]+p6[0]+p7[0]+p8[0])/8,(p1[1]+p2[1]+p3[1]+p4[1]+p5[1]+p6[1]+p7[1]+p8[1])/8,(p1[2]+p2[2]+p3[2]+p4[2]+p5[2]+p6[2]+p7[2]+p8[2])/8);	
		p6=rotate(p6,(p1[0]+p2[0]+p3[0]+p4[0]+p5[0]+p6[0]+p7[0]+p8[0])/8,(p1[1]+p2[1]+p3[1]+p4[1]+p5[1]+p6[1]+p7[1]+p8[1])/8,(p1[2]+p2[2]+p3[2]+p4[2]+p5[2]+p6[2]+p7[2]+p8[2])/8);	
		p7=rotate(p7,(p1[0]+p2[0]+p3[0]+p4[0]+p5[0]+p6[0]+p7[0]+p8[0])/8,(p1[1]+p2[1]+p3[1]+p4[1]+p5[1]+p6[1]+p7[1]+p8[1])/8,(p1[2]+p2[2]+p3[2]+p4[2]+p5[2]+p6[2]+p7[2]+p8[2])/8);	
		p8=rotate(p8,(p1[0]+p2[0]+p3[0]+p4[0]+p5[0]+p6[0]+p7[0]+p8[0])/8,(p1[1]+p2[1]+p3[1]+p4[1]+p5[1]+p6[1]+p7[1]+p8[1])/8,(p1[2]+p2[2]+p3[2]+p4[2]+p5[2]+p6[2]+p7[2]+p8[2])/8);	
		
		repaint();
		try
		{
			Thread.sleep(100);
		}
		catch(Exception e){}
	}
}






public double[] matMult (double[][] matrix,double[] vector)
{
	double[] temp = new double[4];
	
	temp[0]=(matrix[0][0]*vector[0])+(matrix[1][0]*vector[1])+(matrix[2][0]*vector[2])+(matrix[3][0]*vector[3]);
	temp[1]=(matrix[0][1]*vector[0])+(matrix[1][1]*vector[1])+(matrix[2][1]*vector[2])+(matrix[3][1]*vector[3]);
	temp[2]=(matrix[0][2]*vector[0])+(matrix[1][2]*vector[1])+(matrix[2][2]*vector[2])+(matrix[3][2]*vector[3]);
	temp[3]=(matrix[0][3]*vector[0])+(matrix[1][3]*vector[1])+(matrix[2][3]*vector[2])+(matrix[3][3]*vector[3]);
	return temp;
}


public void createMatricies(double angle)
{
	 angle=(angle/180)*(Math.PI); //get angle in radians 
	
	 //Create the X Axis matrix
	 rotX[0][0]=1;		rotX[1][0]=0;		rotX[2][0]=0;	;	rotX[3][0]=0;
	 rotX[0][1]=0;		rotX[1][1]=Math.cos(angle);		rotX[2][1]=-1*Math.sin(angle);	rotX[3][1]=0;
	 rotX[0][2]=0;		rotX[1][2]=Math.sin(angle);		rotX[2][2]=Math.cos(angle);		rotX[3][2]=0;
	 rotX[0][3]=0;		rotX[1][3]=0;		rotX[2][3]=0;	 	rotX[3][3]=1;				
	 
	 //Create the Y Axis matrix
	 rotY[0][0]=Math.cos(angle);		rotY[1][0]=0;		rotY[2][0]=Math.sin(angle);		rotY[3][0]=0;
	 rotY[0][1]=0;			rotY[1][1]=1;		rotY[2][1]=0;		rotY[3][1]=0;
	 rotY[0][2]=-1*Math.sin(angle);		rotY[1][2]=0;		rotY[2][2]=Math.cos(angle);		rotY[3][2]=0;
	 rotY[0][3]=0;		rotY[1][3]=0;		rotY[2][3]=0;	 	rotY[3][3]=1;
	 
	 //Create the Z Axis matrix
	 rotZ[0][0]=Math.cos(angle);		rotZ[1][0]=-1*Math.sin(angle);		rotZ[2][0]=0;		rotZ[3][0]=0;
	 rotZ[0][1]=Math.sin(angle);		rotZ[1][1]=Math.cos(angle);		rotZ[2][1]=0;		rotZ[3][1]=0;
	 rotZ[0][2]=0;		rotZ[1][2]=0;		rotZ[2][2]=1;		rotZ[3][2]=0;
	 rotZ[0][3]=0;		rotZ[1][3]=0;		rotZ[2][3]=0;	 	rotZ[3][3]=1;
	 
}

}

Share this post


Link to post
Share on other sites
Quote:
Original post by yaazz
The code seems to work, but the objects always warp over time, can you tell me what I am doing wrong?
I would guess persistent loss of precision. Look at your loop() method, for example, when you call rotate. You're dividing doubles by 2 and 8 when you pass those origin coordinates in, which Java demotes to integers. You should be using 2.0 and 8.0 to maintain double precision. Same thing in your createMatricies() method; you have -1*Math.sin(angle) in a few spots which gets seen as an integer because of the -1; change that to -1.0*Math.sin(angle).

Those two spots seem to be the only ones giving you trouble. You may have more code, though, not sure. Just be watchful for that, since Java will demote to the simplest primitive it can in these cases.

Share this post


Link to post
Share on other sites
Incremental rotation will almost always distort the shapes over time, due to floating point error. Fortunately, the solution is simple:

Rather than changing the shape's coordinates to their transformed versions each frame, we store the original coordinates along with the cumulative transformation data. Then, when the shape needs to be rendered, we perform the entire transformation in one go and render the temporary.

This means you'll have to maintain extra variables for scale, orientation and position, but it won't cost you any performance and will entirely eliminate deformations.

Admiral

Share this post


Link to post
Share on other sites
Quote:

Incremental rotation will almost always distort the shapes over time, due to floating point error. Fortunately, the solution is simple:

Rather than changing the shape's coordinates to their transformed versions each frame, we store the original coordinates along with the cumulative transformation data. Then, when the shape needs to be rendered, we perform the entire transformation in one go and render the temporary.

This means you'll have to maintain extra variables for scale, orientation and position, but it won't cost you any performance and will entirely eliminate deformations.

Admiral


I don't quite understand what you mean by "preform the entire transformation in one go", would you be able to explain that a bit better?

Share this post


Link to post
Share on other sites
Yes, I can explain a bit better. Perhaps a simplified example would help.

Imagine we are rotating a point about the origin. Here's the 'incremental' version, analogous to your current situation:

float x = 1;
float y = 0;
const float theta = 0.01f;

while (is_running) {
// Create rotation parameters
float cos_theta = cos(theta);
float sin_theta = sin(theta);

// Perform rotation
float new_x = cos_theta * x - sin_theta * y;
float new_y = sin_theta * x + cos_theta * y;

DrawPoint(new_x, new_y);

// Update the coordinates
x = new_x;
y = new_y;
}



Notice that when calculating new_x and new_y, floating-point roundoff occurs. This rounding error is then passed along to x and y when you update the coordinates. Leave this running long enough and the point will go astray.

So here's what we do:

float x = 1;
float y = 0;
float cumulative_rotation = 0;
const float theta = 0.01f;

while (is_running) {
// Set cumulative angle
cumulative_rotation += theta;
// This isn't necessary, but we'd like to keep the angle within range
if (cumulative_rotation > 2 * Pi) cumulative_rotation = fmodf(cumulative_rotation, 2 * PI);

// Create rotation parameters
cos_cumulative = cos(cumulative_rotation);
sin_cumulative = sin(cumulative_rotation);

// Perform rotation
float new_x = cos_cumulative * x - sin_cumulative * y;
float new_y = sin_cumulative * x + cos_cumulative * y;

DrawPoint(new_x, new_y);

// Don't update the coordinates
}



This time, x and y never change after initialisation. They serve as an 'identity' object from which we calculate the transformed object each frame. Rather than rotating a little bit each frame, we keep track of the overall rotation (cumulative_theta) and transform the uncontaminated copies each frame. Floating roundoff still occurs, but it only lasts for one frame before being reset. Now you can leave your program run for as long as you like, and the point will keep on the same circle.

Admiral

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this