Jump to content
  • Advertisement

Archived

This topic is now archived and is closed to further replies.

Riviera Kid

[java] 3d Java program

This topic is 5277 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

Okay, your probably all gonna laugh your balls of at what i have made. Im a first year university computer science student. Java is the main module atm. This isnt a part of my module, just something i did off the side. I have taken the 2d swing api from java and i have made a 3d program. Atm i have global polygons, camera polygons. All stored in linked lists. LinkedList Meshes; contains linked lists for all the 3d shapes. Vector3D class Polygon3D class I made a sphere. To make my sphere i make a circle in 3d space and rotated it 180 degrees. Stored all the vectors in an array. The vectors in the array are stored nicely so i can join the vectors and fill the sphere. I use the FillPolygon(Polygon p) method to fill my polygons. It has a back buffer. I write everything to an off screen graphics contex. Using a buffer strategy i flip it over. Im not really sure what is going on here i used an example of back buffering. To sort my polygons i used the Collectors.sort() method which java has. I removed the back faces from my sphere by removing the first half of the array for that sphere. And from this 3d program i made a blocky 3d man with a bazooka on his shoulder. Multiple spheres for legs and arms, a Cuboid for torso and another sphere for head. Thousands of polygons. About 20 fps. No clipping yet. If 1 point on a polygon is out of the screen or behind me i dont draw it. No normals either. Here is the main part of my program public Graphics3D() { Vector3D.cosSin(); meshes.add(buildCuboid(new Vector3D(-1500,0,0),3000,4000,1000, Color.blue)); meshes.add(buildCuboid(new Vector3D(-400,-1000,100),800,1000,500, Color.blue)); meshes.add(buildCylinder(new Vector3D(1750,-250,4000),1000,500,false, Color.blue)); meshes.add(buildCylinder(new Vector3D(1750,-250,3000),1000,500,false, Color.blue)); meshes.add(buildCylinder(new Vector3D(1750,-250,2000),1000,500,false, Color.blue)); meshes.add(buildCylinder(new Vector3D(1750,-250,1000),1000,500,false, Color.blue)); meshes.add(buildCylinder(new Vector3D(1750,-250,0),1000,500,false, Color.blue)); meshes.add(buildCylinder(new Vector3D(1750,-250,-1000),1000,500,false, Color.blue)); meshes.add(buildCylinder(new Vector3D(1750,-250,-2000),1000,500,false, Color.blue)); meshes.add(buildCylinder(new Vector3D(1750,-250,-3000),1000,500,false, Color.blue)); meshes.add(buildSphere(1800,350,350, 700,3, Color.cyan)); meshes.add(buildSphere(-2000,350,350, 700,3, Color.cyan)); meshes.add(buildSphere(2700,350,350, 700,3, Color.cyan)); meshes.add(buildSphere(-1900,350,-500, 700,3, Color.cyan)); meshes.add(buildSphere(3600,0,350, 600,3, Color.cyan)); meshes.add(buildSphere(-1050,0,-800, 700,3, Color.cyan)); meshes.add(buildSphere(3400,-800,350, 600,3, Color.cyan)); meshes.add(buildSphere(-150,-300,-1000, 700,3, Color.cyan)); meshes.add(buildSphere(3200,-1600,350, 600,3, Color.cyan)); meshes.add(buildSphere(700,-400,-1200, 700,3, Color.cyan)); LinkedList rocket = buildCylinder(new Vector3D(1800,-400,-3000),1500,400,true ,Color.red); meshes.add(rocket); meshes.add(buildSphere(1000,4000,350, 700,3, Color.cyan)); meshes.add(buildSphere(-1000,4000,350, 700,3, Color.cyan)); meshes.add(buildSphere(1000,5000,350, 700,3, Color.cyan)); meshes.add(buildSphere(-1000,5000,350, 700,3, Color.cyan)); meshes.add(buildSphere(1000,6000,350, 700,3, Color.cyan)); meshes.add(buildSphere(-1000,6000,350, 700,3, Color.cyan)); meshes.add(buildSphere(1000,7000,350, 700,3, Color.cyan)); meshes.add(buildSphere(-1000,7000,350, 700,3, Color.cyan)); meshes.add(buildSphere(1000,8000,350, 700,3, Color.cyan)); meshes.add(buildSphere(-1000,8000,350, 700,3, Color.cyan)); LinkedList head = buildSphere(0,-2000,300, 1400,6, Color.cyan); meshes.add(head); addKeyListener(this); addMouseListener(this); setUpGraphics(); while(true) { update(); } } [edited by - Riviera Kid on May 29, 2004 8:40:43 AM]

Share this post


Link to post
Share on other sites
Advertisement
Way cool dude!
Wirting software engines is probably the coolest programming project you can do, because it allows you to do so much with your computer. Java is fun, too

--------------------------------------------------------
Life would be so much easier if we could just get the source code.

Share this post


Link to post
Share on other sites
Yes software rendering in Java can be especially challenging/rewarding. You can easily get by with drawPolygon() until you write your own triangle rasterizer. If you want to see a feature complete java software renderer google for ''idx3d''.

Share this post


Link to post
Share on other sites
Cool, I''ve also written a 3D engine in pure Java and it''s a pretty fun project .

By the way, if you want to take this further, definitely don''t use fillPolygon. Even for polygons of one single color with no z-buffer testing or blending or anything, writing to an int[] obtained by using BufferedImage.getDataSource got me about 10x faster performance than Graphics.fillPolygon. The Graphics class uses GDI, and it''s ridiculously slow.

Share this post


Link to post
Share on other sites
Guest Anonymous Poster
yeah ive seen demos of MemeorySourceImage use which takes an int[] parameter for the pixels.

How exactly are the pixels aranged in the array?

are they in order of horizontal lines or vertical lines?

eg

int[] = (x0,y0),(x1,y0),(x2,y0),(x3,y0),(x0,y1),(x1,y1),(x2,y1),(x3,y1) and so on.

or is it the other way around?

Share this post


Link to post
Share on other sites
yeah ive seen demos of MemeorySourceImage use which takes an int[] parameter for the pixels.

How exactly are the pixels aranged in the array?

are they in order of horizontal lines or vertical lines?

eg

int[] = (x0,y0),(x1,y0),(x2,y0),(x3,y0),(x0,y1),(x1,y1),(x2,y1),(x3,y1) and so on.

or is it the other way around?

edit:: feck!! look what i did, oops.

[edited by - Riviera Kid on May 30, 2004 7:42:22 AM]

Share this post


Link to post
Share on other sites
Heh, I''ve recently a similar simple 3D java app as a university assignment (although the 3D wasn''t a requirement, it was a class of software design and UML crap and we had to do a game). Used Graphics.fillPolygon as well

I''d like to ask you about the polygon sorting. I tried to do it based on the average of the transformed Z coordinates, W coordinates, the average of the greatest and lowest transformed Z, but none of them seemed to work for my triangles, they were either z-fighting or incorrectly ordered when one of them stretched far off into the screen''s axis. I''m pretty sure I was screwing up something fundamental but I couldn''t find what was wrong.

So my question would be, how were you sorting your triangles?

Share this post


Link to post
Share on other sites
being mr lazy and mr new at this at first just for the time being i used Bubble Sort (stupid me). I only sorted per polygon and not per pixel so every now and then some polygons were not sorted properly but it was minor problem. I sorted from the center of the polygon.

Now i use the built in java sort Collections.sort(list).

The polygons furthest away go at the bottom of the list and the ones closest to me go at the top of the list. Thats all i know about polygon sorting.

Now i have a question.

How are you filling your polygons?

All this active edge list and scanline stuff gives me and head ache. Using fillpolygon doesnt allow texturing (afaik) so i recently made my own fill method.

I take 2 opposing lines on a polygon and traverse them both. As i do this i draw lines of pixels between them. It fills perfectly as far as i can see but it is extreemily slow.

My program isnt running fast at all. Any pointers on how to speed things up wud rule.




Share this post


Link to post
Share on other sites
You have to use a MemoryImageSource or BufferedImage (I haven't yet found out for sure which is faster) and write to an int array instead of to pixels. Also, using edge lists and interpolating accross each scanline is the way to go, it's really not that bad once you get down to it (probably very similar to what you've been doing). Here's an early (but therefore much easier to read ) version of my method, copied from a post on the java.sun.com forums:


private int [] pixels;
private MemoryImageSource imageSource;
private Image backBuffer;
private int [] left = new int [2000]; // store the x value of the pixel on the left side of the triangle at a given y value.
private int [] right = new int [2000]; // ditto for the right side

private void createMemoryImage() { // should be called after you set/change your window size
this .pixels = new int [displayWidth*displayHeight];
this .imageSource = new MemoryImageSource(displayWidth, displayHeight, pixels, 0, displayWidth);
imageSource.setAnimated(true );
this .backBuffer = Toolkit.getDefaultToolkit().createImage(imageSource);
}

/*
Given a line, calculate its x coordinates for each y value and place them into dest.
My example uses some fixed-point math, which is not the best way; you can make it use doubles
or use a true integer line-scanning algorithm; I'll post a real one when I implement it myself - right
now this was just needed to get things working, and it does work fairly well.
*/

private void getLineXVals(int x1, int y1, int x2, int y2, int [] dest) {
if (y1 > y2) { // swap so y1 is on top
int t = x1; x1 = x2; x2 = t;
t = y1; y1 = y2; y2 = t;
}
else if (y1 == y2) { // horizontal
return ;
}
int dx, dy;
dy = y2 - y1;
dx = x2 - x1;
int gi = (dx*2048) / dy; // multiplies and divides by 2048 should get optimized to shifts by the compiler.
int xi = (x1*2048);
for (int y = y1; y < y2; y++) {
dest[y] = (xi/2048);
xi += gi;
}
}

private void rasterizeTriangle(ProcessedPrimitive p) {
// p is just a class that contains the vertices of the triangle in *counterclockwise* order (important!)
// they are stored as doubles, so we cast them here; if you're really adventurous you can look for a moe
// precise line-drawing algorithm that actually uses doubles rather than ints and make the
// appropriate changes.

int x0 = (int ) p.x[0];
int x1 = (int ) p.x[1];
int x2 = (int ) p.x[2];
int y0 = (int ) p.y[0];
int y1 = (int ) p.y[1];
int y2 = (int ) p.y[2];

int yMin = y0;
int yMax = y0;
if (y1 < yMin) yMin = y1;
else if (y1 > yMax) yMax = y1;
if (y2 < yMin) yMin = y2;
else if (y2 > yMax) yMax = y2;

// use the fact that the vertices are in counterclockwise order to determine whether
// the edges are left or right edges.
getLineXVals(x0, y0, x1, y1, (y0>y1 ? left : right));
getLineXVals(x1, y1, x2, y2, (y1>y2 ? left : right));
getLineXVals(x0, y0, x2, y2, (y2>y0 ? left : right));

int col = p.color.getRGB();

for (int y = yMin; y < yMax; y++) {
int l = left[y];
int r = right[y];
int w = r - l;
if (w<0) continue ;
int from = y*displayWidth + l;
int to = from+w;
Arrays.fill(pixels, from, to, col); // fast way to fill a continuous segment;

// if you want to do other calculations for each pixel (maybe Gouraud shading or texturing?), use
// a manual fill as follows:
// int pos = y*displayWidth + l;
// for(int i=0; i<w; i++) {
// pixels[pos] = col;
// pos++;
// }
}
}

public void paint(Graphics g) {
// clear background to black:
int max = displayWidth*displayHeight;
for (int p=0; p<max; p++) {
pixels[p] = 0xff000000; // alpha=255, r=0, g=0, b=0
}

// for each triangle, rasterizeTriangle(t);

// now draw the raster image onto the screen
imageSource.newPixels();
g.drawImage(backBuffer, 0, 0, null);
}


[edited by - Matei on May 31, 2004 12:58:51 PM]

Share this post


Link to post
Share on other sites

  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

We are the game development community.

Whether you are an indie, hobbyist, AAA developer, or just trying to learn, GameDev.net is the place for you to learn, share, and connect with the games industry. Learn more About Us or sign up!

Sign me up!