Matrix math in Java

Started by
14 comments, last by jbviklund 13 years, 4 months ago
Hey!

I'm trying to do some matrix transformations & projections in Java for a applet that is going to animate some lines in 3D.
Does this seem ok? I would also like to get some tips about how to do the perspective projection.

public class matrix3D{    private double[][] matrix;    public matrix3D(){        matrix = new double[4][4];        matrix = setIdentity();    }    private double[][] setIdentity(){        double[][] temp = {{1.0, 0.0, 0.0, 0.0},                           {0.0, 1.0, 0.0, 0.0},                           {0.0, 0.0, 1.0, 0.0},                           {0.0, 0.0, 0.0, 1.0}};                return temp;    }    public void resetMatrix(){        matrix = setIdentity();    }    public void setXRotation(double x){        double cos = Math.cos(x);        double sin = Math.sin(x);        double[][] temp = {{1.0,  0.0,  0.0,  0.0},                           {0.0,  cos, -sin,  0.0},                           {0.0,  sin,  cos,  0.0},                           {0.0,  0.0,  0.0,  1.0}};        matrix = multiply(matrix, temp);    }    public void setYRotation(double y){        double cos = Math.cos(y);        double sin = Math.sin(y);        double[][] temp = {{cos,  0.0,  sin,  0.0},                           {0.0,  1.0,  0.0,  0.0},                           {-sin, 0.0,  cos,  0.0},                           {0.0,  0.0,  0.0,  1.0}};        matrix = multiply(matrix, temp);    }    public void setZRotation(double z){        double cos = Math.cos(z);        double sin = Math.sin(z);        double[][] temp = {{cos, -sin,  0.0,  0.0},                           {sin,  cos,  0.0,  0.0},                           {0.0,  0.0,  1.0,  0.0},                           {0.0,  0.0,  0.0,  1.0}};        matrix = multiply(matrix, temp);    }        public void setTranslation(double x, double y, double z){        double[][] temp = {{1.0,  0.0,  0.0,  x  },                           {0.0,  1.0,  0.0,  y  },                           {0.0,  0.0,  1.0,  z  },                           {0.0,  0.0,  0.0,  1.0}};        matrix = multiply(matrix, temp);    }    public void  setScaling(double x, double y, double z){        double[][] temp = {{x,    0.0,  0.0,  0.0},                           {0.0,  y,    0.0,  0.0},                           {0.0,  0.0,  z,    0.0},                           {0.0,  0.0,  0.0,  1.0}};        matrix = multiply(matrix, temp);    }    private double[][] multiply(double[][] a, double[][] b){        double[][] result = new double[4][4];        result = setIdentity();        for(int i = 0; i < 4; i++)            for(int j = 0; j < 4; j++)                for(int k = 0; k < 4; k++)                    result[j] += a[k] * b[k][j];        return result;    }    public matrix3D multiply(matrix3D a, matrix3D b){        matrix3D result = new matrix3D();        for(int i = 0; i < 4; i++)            for(int j = 0; j < 4; j++)                for(int k = 0; k < 4; k++)                    result.matrix[j] += a.matrix[k] * b.matrix[k][j];                return result;    }    public vertex transformVertex(vertex v){        vertex result = new vertex();        result.setX(v.getX() * matrix[0][0] +                    v.getY() * matrix[0][1] +                    v.getZ() * matrix[0][2] +                    v.getW() * matrix[0][3]);        result.setY(v.getX() * matrix[1][0] +                    v.getY() * matrix[1][1] +                    v.getZ() * matrix[1][2] +                    v.getW() * matrix[1][3]);        result.setZ(v.getX() * matrix[2][0] +                    v.getY() * matrix[2][1] +                    v.getZ() * matrix[2][2] +                    v.getW() * matrix[2][3]);                result.setW(v.getX() * matrix[3][0] +                    v.getY() * matrix[3][1] +                    v.getZ() * matrix[3][2] +                    v.getW() * matrix[3][3]);                return result;    }}
Advertisement
I didn't read carefully for errors, but it basically looks okay.
Graham Rhodes Moderator, Math & Physics forum @ gamedev.net
Ok thanks! It's a bit hard to test the transformations without the perspective projection :)
Write some unit tests.
Fixed an error in the multiplication and then I made a function that prints the matrix:
No transformations:1,00        0,00        0,00        0,000,00        1,00        0,00        0,000,00        0,00        1,00        0,000,00        0,00        0,00        1,00X rotation (0.78 rad):1,00        0,00        0,00        0,000,00        0,71        -0,70       0,000,00        0,70        0,71        0,000,00        0,00        0,00        1,00Y rotation (0.78 rad):0,71        0,00        0,70        0,000,00        1,00        0,00        0,00-0,70       0,00        0,71        0,000,00        0,00        0,00        1,00Z rotation (0.78 rad):0,71        -0,70       0,00        0,000,70        0,71        0,00        0,000,00        0,00        1,00        0,000,00        0,00        0,00        1,00Translation (10.0, 0, 0):1,00        0,00        0,00        10,000,00        1,00        0,00        0,000,00        0,00        1,00        0,000,00        0,00        0,00        1,00Scaling (2.0, 1.0, 1.0):2,00        0,00        0,00        0,000,00        1,00        0,00        0,000,00        0,00        1,00        0,000,00        0,00        0,00        1,00X rotation + translation:1,00        0,00        0,00        10,000,00        0,71        -0,70       0,000,00        0,70        0,71        0,000,00        0,00        0,00        1,00Y rotation + translation:0,71        0,00        0,70        7,110,00        1,00        0,00        0,00-0,70       0,00        0,71        -7,030,00        0,00        0,00        1,00Z rotation + translation:0,71        -0,70       0,00        7,110,70        0,71        0,00        7,030,00        0,00        1,00        0,000,00        0,00        0,00        1,00X + Y + Z rotation:0,51        -0,50       0,70        0,000,85        0,16        -0,50       0,000,14        0,85        0,51        0,000,00        0,00        0,00        1,00X + Y + Z rotation + translation:0,51        -0,50        0,70       5,050,85        0,16        -0,50       8,520,14        0,85        0,51        1,390,00        0,00        0,00        1,00X + Y + Z rotation + translation + scaling:1,01        -0,50       0,70        5,051,70        0,16        -0,50       8,520,28        0,85        0,51        1,390,00        0,00        0,00        1,00

It seems more resonable now!
I'm totally stuck on the perspective projection!
Take this for example:
The "canonical space mapping for perspective projections" at the bottom of the page.

http://www.cs.unc.edu/~mcmillan/comp136/Lecture16/projection.html

What is right, left bottom & top?
I did this a little while ago but don't have the source handy. I'll try to explain by my memory's fuzzy. Here goes.

Observe this here:

http://www.codeguru.com/dbfiles/get_image.php?id=10123&lbl=3DPROJ22_GIF&ds=20061023

You're defining that square floating in front of the viewer.

You can conjure up the figures in question from the aspect ratio.

For example, a 640x480 screen has an aspect ratio of 4:3.

We might pull a near plane distance figure out of our rear, like 1, and then base the rest on 1 multiplied with our aspect ratio.

Right might be 4/3, left might be -4/3, top and bottom are 1 and -1, respectively.

I'm gonna go dig up that code and then come back and post.
Here it is!

In my program I had condensed those figures into just width & height. Like so:

public static Matrix getProjectionMatrix(double focus, double near, double width, double height){	double matrix[][] = {			{ (2 * near) / width , 0, 0, 0 },			{ 0, (2 * near) / height, 0, 0 },			{ 0, 0, focus / (focus - near), -(focus / (focus - near))},			{ 0, 0, 1, 0 }	};			return new Matrix(4, 4, matrix);}


I called this like so:

Matrix projection = Main.getProjectionMatrix(50, 3, 1, 0.75);


The 1 & 0.75 figure comes from the aspect ratio of 4:3.

For every vertex, which contains 4 elemenents (x,y,z,w), we multiply it by the 4x4 matrix to yield a vector4 result, then divide the x and the y each by w.

(In my code I also divide z and w by w, and I can't think of why at the moment.)

Taking the x and y yields a point we can use to rasterize.

I don't see anything in here about multiplying the result by the pixel size of the viewport, so disregard that.

I don't know where the figures 3 and 50 came from, I presume I pulled them from my rear and decided they looked about right. Tweaking them will adjust how zoomed things look. You should be able to conjure up such figures from a given viewing angle and viewport size. I think.
Starting to look better but still strange!
It's supposed to be a cube! :P



public void setProjection(int width, int height, double zNear, double zFar){    fov = Math.toRadians(fov);    double right = (width / height);    double left = -(width / height);    double top = 1.0;    double bottom = -1.0;    double a_a = (2.0 * zNear) / (right - left);    double a_c = -(right + left) / (right - left);    double a_d = width / 2.0;    double b_c = -(bottom + top) / (bottom - top);    double b_b = (2.0 * zNear) / (bottom - top);    double b_d = height / 2.0;    double c_c = (zFar + zNear) / (zFar - zNear);    double d_c = -(2.0 * zFar * zNear) / (zFar - zNear);    double[][] temp = {{a_a,  0.0,  a_c,  a_d},                       {0.0,  b_b,  b_c,  b_d},                       {0.0,  0.0,  c_c,  d_c},                       {0.0,  0.0,  1.0,  0.0}};    matrix = multiply(matrix, temp);}
lol, I have no idea. My cube correctly shows up a cube, but your projection matrix looks like it might be a tad different from mine.

This topic is closed to new replies.

Advertisement