PDA

View Full Version : Java Raytracer Problem


appleGuy
07-09-2007, 06:39 AM
Hi,
Im currently trying to make a very simple raytracer. Now ive got this big problem. As shown in the image below the image output is incorrect, however this only happens when I use view plane dimensions that are not the same. (100 x 100 works but 800 x 600 gives the strange output). This has been bugging me for days and I wonder if anyone can spot where ive gone wrong.

Ill include the camera ray spawn code and the render code, minus the intersection code as I know this is correct. Ill also include the tga file creator as that might be the problem.

Thanks for your help
-Alex

render code (inc ray camera spawn):
public void spawnCameraRays(int imageDimX, int imageDimY){
_raySpawnTable = new Vector3f[imageDimX][imageDimY];
_cameraPos = new Vector3f();

//Vars to hold half screen width and height
float halfWidth = (float)imageDimX / 2;
float halfHeight = (float)imageDimY / 2;

//loop through every pixel and generate ray directions

for(int y = 0; y < imageDimY; y++){

for(int x = 0; x < imageDimX; x++){
_raySpawnTable[x][y] = new Vector3f(x - halfWidth, y - halfHeight, 255);
_raySpawnTable[x][y].normalize();
}
}
//Assign member variables the dimensions for memory clean up
_cleanX = imageDimX;
_cleanY = imageDimY;
}

public void cameraRayClean(){
//Drop hint to GC to clean memory
for(int y = 0; y < _cleanY; y++){
for(int x = 0; x < _cleanX; x++)
_raySpawnTable[x][y] = null;
}
_raySpawnTable = null;
}

public boolean traceScene(primitiveObjects.p_sphere obj, viewPlane vPlane, int vpX, int vpY){ // Change when Scene Inc
//Camera Ray;
ray cameraRay = new ray();
cameraRay.setOrigin(new Vector3f(0.0f, 0.0f, -600.0f));

//Loop through all pixels in view plane and trace the cameraRay, based on raySpawnTable;
if (_raySpawnTable == null || vPlane == null)
return false;


for (int iterX = 0; iterX < vpX; iterX++){
int rgb = 0; //Loop Iterator for 3 rgb colours
for(int iterY = 0; iterY < vpY; iterY++, rgb+=3){
cameraRay.setDirection(_raySpawnTable[iterX][iterY]);

rayTraceResult result;
result = obj.calcIntersection(cameraRay);

if(result.getHit() == true){
vPlane._viewPlane[iterX][rgb + 0] = obj._r;
vPlane._viewPlane[iterX][rgb + 1] = obj._g;
vPlane._viewPlane[iterX][rgb + 2] = obj._b;
//System.out.print("111");
}
else{
vPlane._viewPlane[iterX][rgb + 0] = 111;
vPlane._viewPlane[iterX][rgb + 1] = 111; //RGB Black (More Elegant?)
vPlane._viewPlane[iterX][rgb + 2] = 111;
//System.out.print("000");
}
}
//System.out.println("");
}

return true;
}

//Variables
private Vector3f _raySpawnTable[][];
private Vector3f _cameraPos;

Tga out put code:
public boolean writeTGA(String fileName, viewPlane vPlane){
char tgaHeader[] = {0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0};
char header[] = new char [6];
char bits = 24;

int colourMode = 3;

header[0] = (char)(vPlane.getVPlaneX() % 256);
header[1] = (char)(vPlane.getVPlaneX() / 256);
header[2] = (char)(vPlane.getVPlaneY() % 256);
header[3] = (char)(vPlane.getVPlaneY() / 256);
header[4] = bits;
header[5] = 0;

try{
tgaOutFile = new File(fileName);
tgaOutFile.createNewFile();
}
catch(IOException e){
//EXCEPTION HERE
System.out.println("Error Creating File");
}


try{
tgaOutStream = new FileOutputStream(fileName);
}
catch(FileNotFoundException e){
System.out.println("");
System.out.println("Error Opening File");
//EXCEPTION HERE
}

try{
for(int i = 0; i < 12; i++)
tgaOutStream.write(tgaHeader[i]);
for(int i = 0; i < 6; i++)
tgaOutStream.write(header[i]);

//Switch RGB -> BGR
for (int iterX = 0; iterX < vPlane.getVPlaneX(); iterX++){
for(int iterY = 0; iterY < (vPlane.getVPlaneY() * 3); iterY+=colourMode){
char tempColour = vPlane._viewPlane[iterX][iterY];
vPlane._viewPlane[iterX][iterY] = vPlane._viewPlane[iterX][iterY + 2];
vPlane._viewPlane[iterX][iterY + 2] = tempColour;
}
}

//Write Data Image To File

for (int iterX = 0; iterX < vPlane.getVPlaneX(); iterX++){
for(int iterY = 0; iterY < vPlane.getVPlaneY() * 3; iterY++){
tgaOutStream.write(vPlane._viewPlane[iterX][iterY]);
}
}

tgaOutStream.close(); //Give Resource Back to VM
}

catch(IOException e){
//EXCEPTION HERE
System.out.println("Error Closing or writing File");
}

return true;
}

private FileOutputStream tgaOutStream;
private File tgaOutFile;

the strange output as unequal resolutions:
http://img.photobucket.com/albums/v315/blade99261/raytraceError.jpg

Thanks Again!

flux00
07-09-2007, 07:31 AM
Hmm, can you describe the format for the viewPlane class? Are you using an int[width][3*height]? Typically ray tracers use three floats to represent red green and blue, and it may be simpler to use a int[width][height][3], or simply color[width][height]. What color range are you using? 0-255?

I'm not familliar with TGA format, but for debugging purposes you could possibly write to a java.awt.Image via java.awt.image.BufferedImage or something along those lines, then just use ImageIO.save(...). If you try that make sure to negate the yY component.

appleGuy
07-09-2007, 08:00 AM
Hmm, can you describe the format for the viewPlane class? Are you using an int[width][3*height]? Typically ray tracers use three floats to represent red green and blue, and it may be simpler to use a int[width][height][3], or simply color[width][height]. What color range are you using? 0-255?

I'm not familliar with TGA format, but for debugging purposes you could possibly write to a java.awt.Image via java.awt.image.BufferedImage or something along those lines, then just use ImageIO.save(...). If you try that make sure to negate the yY component.

The Code for my viewPlane Class:
package raytracer;

public class viewPlane {

/** Creates a new instance of viewPlane */
public viewPlane(int dimensionX, int dimensionY) {
_dimensionX = dimensionX;
_dimensionY = dimensionY;
}

public void createViewPlane(){
//INSERT EXCEPTION
if(_dimensionX < 1 || _dimensionY < 1){
//THROW Exception
;
}
else{
// _dY * 3 for RGB

_viewPlane = new char [_dimensionX][(_dimensionY * 3)];
}
}

public void deleteViewPlane(){
//Drop Hint to Garbage Collector
_viewPlane = null;
}

public int getVPlaneX(){
return _dimensionX;
}
public int getVPlaneY(){
return _dimensionY;
}

//Variables
private int _dimensionX;
private int _dimensionY;
public char _viewPlane[][];

}

im using a char [image width][image height * 3]. using colour range of 0 -255 hence the type char.

Thanks For Your Help
-Alex

z80
07-09-2007, 09:19 AM
Hmm.. Ok.. When you are generating your TGA header you treat the X-axis as width and the Y-axis as height, but when you actually write the pixels (at your "Write Data Image To File"-comment) you do it the other way round.

When you write pixels you have to start with the bottom scanline and write pixels from left to right (every pixel should be written as 3 bytes for Blue, Green and Red). You are not doing that right now.

You probably need to make your X-axis in the view buffer 3 times wider instead of the Y-axis. Or perhaps skip the viewPlane alltogether and write the pixels as you trace them (but then of course you have to trace pixels in the correct order, so they will come out right in the file -- you will need the Y-axis as the outmost for-statement in the trace loops). I would avoid creating a big buffer if its not really needed, but that is up to you.

appleGuy
07-09-2007, 09:26 AM
Hmm.. Ok.. When you are generating your TGA header you treat the X-axis as width and the Y-axis as height, but when you actually write the pixels (at your "Write Data Image To File"-comment) you do it the other way round.

When you write pixels you have to start with the bottom scanline and write pixels from left to right (every pixel should be written as 3 bytes for Blue, Green and Red). You are not doing that right now.

You probably need to make your X-axis in the view buffer 3 times wider instead of the Y-axis. Or perhaps skip the viewPlane alltogether and write the pixels as you trace them (but then of course you have to trace pixels in the correct order, so they will come out right in the file). I would avoid creating a big buffer if its not really needed, but that is up to you.

Hi,

Im not sure im with your. Why would making the X axis 3 times bigger than the Y axis make any difference? Surely you are just making room for the RGB values....

Im alittle confussed...

Could you explain abit more please?

Sorry about this
-Alex

Edit:
So in a tga file, the standard is the read the file in columns, rather than rows?

z80
07-09-2007, 09:39 AM
No, you have to write rows... the problem is that you are writing columns..

This is writing columns (since you have the X-axis as the outer loop):
//Write Data Image To File
for (int iterX = 0; iterX < vPlane.getVPlaneX(); iterX++){
for(int iterY = 0; iterY < vPlane.getVPlaneY() * 3; iterY++){
tgaOutStream.write(vPlane._viewPlane[iterX][iterY]);
}

That is why I am talking about that is the X-axis thingy you have to make 3 times wider (since the inner axis should have the color dimension hanging on it)..

I would skip the vPlane alltogether and write the pixels directly to the tga-file as you trace them with obj.calcIntersection()..

appleGuy
07-09-2007, 09:52 AM
No, you have to write rows... the problem is that you are writing columns..

This is writing columns (since you have the X-axis as the outer loop):
//Write Data Image To File
for (int iterX = 0; iterX < vPlane.getVPlaneX(); iterX++){
for(int iterY = 0; iterY < vPlane.getVPlaneY() * 3; iterY++){
tgaOutStream.write(vPlane._viewPlane[iterX][iterY]);
}

That is why I am talking about that is the X-axis thingy you have to make 3 times wider (since the inner axis should have the color dimension hanging on it)..

I would skip the vPlane alltogether and write the pixels directly to the tga-file as you trace them with obj.calcIntersection()..

Ahhhhhhh!

Thank you so much!!!!!!

Simple mistake like you said, I wasnt sure how to store the image!!!!
Ive swaped the loops around and changed some arrays, now it works with the vPlane!


Thanks Again!

Cheers
-Alex