rende
05-18-2007, 07:28 PM
I've been trying to code a raytracer on and off over the past few months. Problem is I jumped into the deep end ( basicly started coding on the thing the first time I touched c/c++).. Anyways, managed to get something out of it finally! :bounce:
http://fluentart.com/gallery/albums/scraps/Screenshot.jpg
Havent coded in image output yet, only drawing to screen using pixeltoaster (http://www.pixeltoaster.com/) as it renders so thats why your seeing a cropped render. At the moment all it can do is load OBJ files (with tris only, and a bit broken at the moment) and spit out the ray/tri intersection data (hit, distance, u and v). I decided to skip sphere raytracing alltogether (duno if that was a good idea in hindsight though, might have learnt faster if i did).
Just so you know what your looking at in the image.. I piped the u/v/distance data to the color channels.
outcol.a = 1;
outcol.r = nearU;
outcol.g = nearV;
outcol.b = nearT/2;
So.. the reason why Im posting. I'd like to help other c/c++ newbies by providing my source as i go along and ask questions when i get stuck. The only problem I have at the moment is with the obj loading.. the code im using is from the web, and as far as i can tell doesnt work 100%.. The only way I can get it to work is by adding a false v 0 0 0 entry at the top of the obj, and that fixes the vertex sequence.. if someone can have a look at the obj loading code and help me to fix this bug please...
sourcecode so far (using anjuta on debian, but compiles and runs with devc++ too )
http://fluentart.com/media/fluentray0.1.zip
obj.cpp
#include <stdlib.h>
#include <stdio.h>
#include <memory.h>
#include "obj.h"
ObjModel* ObjLoadModel(char* memory, size_t size)
{
char* p = NULL, * e = NULL;
ObjModel* ret = (ObjModel*) calloc(1, sizeof(ObjModel));
memset(ret, 0, sizeof(ObjModel));
p = memory;
e = memory + size;
while (p != e)
{
if (memcmp(p, "vn", 2) == 0) ret->nNormal++;
else if (memcmp(p, "vt", 2) == 0) ret->nTexCoord++;
else if (memcmp(p, "v", 1) == 0) ret->nVertex++;
else if (memcmp(p, "f", 1) == 0) ret->nTriangle++;
while (*p++ != (char) 0x0A);
}
ret->VertexArray = (ObjVertex*) malloc(sizeof(ObjVertex) * ret->nVertex);
ret->NormalArray = (ObjNormal*) malloc(sizeof(ObjNormal) * ret->nNormal);
ret->TexCoordArray = (ObjTexCoord*) malloc(sizeof(ObjTexCoord) * ret->nTexCoord);
ret->TriangleArray = (ObjTriangle*) malloc(sizeof(ObjTriangle) * ret->nTriangle);
p = memory;
int nV = 0, nN = 0, nT = 0, nF = 0;
while (p != e)
{
if (memcmp(p, "vn", 2) == 0)
{
sscanf(p, "vn %f %f %f", &ret->NormalArray[nN].x,
&ret->NormalArray[nN].y,
&ret->NormalArray[nN].z);
nN++;
}
else if (memcmp(p, "vt", 2) == 0)
{
sscanf(p, "vt %f %f", &ret->TexCoordArray[nT].u,
&ret->TexCoordArray[nT].v);
nT++;
}
else if (memcmp(p, "v", 1) == 0) /* or *p == 'v' */
{
sscanf(p, "v %f %f %f", &ret->VertexArray[nV].x,
&ret->VertexArray[nV].y,
&ret->VertexArray[nV].z);
nV++;
}
else if (memcmp(p, "f", 1) == 0) /* or *p == 'f' */
{
sscanf(p, "f %d/%d/%d %d/%d/%d %d/%d/%d", &ret->TriangleArray[nF].Vertex[0],
&ret->TriangleArray[nF].TexCoord[0],
&ret->TriangleArray[nF].Normal[0],
&ret->TriangleArray[nF].Vertex[1],
&ret->TriangleArray[nF].TexCoord[1],
&ret->TriangleArray[nF].Normal[1],
&ret->TriangleArray[nF].Vertex[2],
&ret->TriangleArray[nF].TexCoord[2],
&ret->TriangleArray[nF].Normal[2]);
nF++;
}
while (*p++ != (char) 0x0A);
}
return ret;
}
size_t ObjLoadFile(char* szFileName, char** memory)
{
size_t bytes = 0;
FILE* file = fopen(szFileName, "rt");
if (file != NULL)
{
fseek(file, 0, SEEK_END);
size_t end = ftell(file);
fseek(file, 0, SEEK_SET);
*memory = (char*) malloc(end);
bytes = fread(*memory, sizeof(char), end, file);
fclose(file);
}
return bytes;
}
obj.h
#ifndef OBJ_H
#define OBJ_H
struct ObjVertex
{
float x, y, z;
};
typedef ObjVertex ObjNormal;
struct ObjTexCoord
{
float u, v;
};
struct ObjTriangle
{
int Vertex[3];
int Normal[3];
int TexCoord[3];
};
struct ObjModel
{
int nVertex, nNormal, nTexCoord, nTriangle;
ObjVertex* VertexArray;
ObjNormal* NormalArray;
ObjTexCoord* TexCoordArray;
ObjTriangle* TriangleArray;
};
ObjModel* ObjLoadModel(char*, size_t);
size_t ObjLoadFile(char*, char**);
#endif
and the main.cc parts..
char* memory = NULL;
size_t bytes = ObjLoadFile("cornell.obj", &memory);
ObjModel* model = ObjLoadModel(memory, bytes);
*snip*
for (int i = 0; i < model->nTriangle; i++) {
vert0[0] = (double) model->VertexArray[ model->TriangleArray[i].Vertex[0] ].x;
vert0[1] = (double) model->VertexArray[ model->TriangleArray[i].Vertex[0] ].y;
vert0[2] = (double) model->VertexArray[ model->TriangleArray[i].Vertex[0] ].z;
vert1[0] = (double) model->VertexArray[ model->TriangleArray[i].Vertex[1] ].x;
vert1[1] = (double) model->VertexArray[ model->TriangleArray[i].Vertex[1] ].y;
vert1[2] = (double) model->VertexArray[ model->TriangleArray[i].Vertex[1] ].z;
vert2[0] = (double) model->VertexArray[ model->TriangleArray[i].Vertex[2] ].x;
vert2[1] = (double) model->VertexArray[ model->TriangleArray[i].Vertex[2] ].y;
vert2[2] = (double) model->VertexArray[ model->TriangleArray[i].Vertex[2] ].z;
result = intersect_triangle(orig, dir, vert0, vert1, vert2, &t, &u, &v);
... *snip*
http://fluentart.com/gallery/albums/scraps/Screenshot.jpg
Havent coded in image output yet, only drawing to screen using pixeltoaster (http://www.pixeltoaster.com/) as it renders so thats why your seeing a cropped render. At the moment all it can do is load OBJ files (with tris only, and a bit broken at the moment) and spit out the ray/tri intersection data (hit, distance, u and v). I decided to skip sphere raytracing alltogether (duno if that was a good idea in hindsight though, might have learnt faster if i did).
Just so you know what your looking at in the image.. I piped the u/v/distance data to the color channels.
outcol.a = 1;
outcol.r = nearU;
outcol.g = nearV;
outcol.b = nearT/2;
So.. the reason why Im posting. I'd like to help other c/c++ newbies by providing my source as i go along and ask questions when i get stuck. The only problem I have at the moment is with the obj loading.. the code im using is from the web, and as far as i can tell doesnt work 100%.. The only way I can get it to work is by adding a false v 0 0 0 entry at the top of the obj, and that fixes the vertex sequence.. if someone can have a look at the obj loading code and help me to fix this bug please...
sourcecode so far (using anjuta on debian, but compiles and runs with devc++ too )
http://fluentart.com/media/fluentray0.1.zip
obj.cpp
#include <stdlib.h>
#include <stdio.h>
#include <memory.h>
#include "obj.h"
ObjModel* ObjLoadModel(char* memory, size_t size)
{
char* p = NULL, * e = NULL;
ObjModel* ret = (ObjModel*) calloc(1, sizeof(ObjModel));
memset(ret, 0, sizeof(ObjModel));
p = memory;
e = memory + size;
while (p != e)
{
if (memcmp(p, "vn", 2) == 0) ret->nNormal++;
else if (memcmp(p, "vt", 2) == 0) ret->nTexCoord++;
else if (memcmp(p, "v", 1) == 0) ret->nVertex++;
else if (memcmp(p, "f", 1) == 0) ret->nTriangle++;
while (*p++ != (char) 0x0A);
}
ret->VertexArray = (ObjVertex*) malloc(sizeof(ObjVertex) * ret->nVertex);
ret->NormalArray = (ObjNormal*) malloc(sizeof(ObjNormal) * ret->nNormal);
ret->TexCoordArray = (ObjTexCoord*) malloc(sizeof(ObjTexCoord) * ret->nTexCoord);
ret->TriangleArray = (ObjTriangle*) malloc(sizeof(ObjTriangle) * ret->nTriangle);
p = memory;
int nV = 0, nN = 0, nT = 0, nF = 0;
while (p != e)
{
if (memcmp(p, "vn", 2) == 0)
{
sscanf(p, "vn %f %f %f", &ret->NormalArray[nN].x,
&ret->NormalArray[nN].y,
&ret->NormalArray[nN].z);
nN++;
}
else if (memcmp(p, "vt", 2) == 0)
{
sscanf(p, "vt %f %f", &ret->TexCoordArray[nT].u,
&ret->TexCoordArray[nT].v);
nT++;
}
else if (memcmp(p, "v", 1) == 0) /* or *p == 'v' */
{
sscanf(p, "v %f %f %f", &ret->VertexArray[nV].x,
&ret->VertexArray[nV].y,
&ret->VertexArray[nV].z);
nV++;
}
else if (memcmp(p, "f", 1) == 0) /* or *p == 'f' */
{
sscanf(p, "f %d/%d/%d %d/%d/%d %d/%d/%d", &ret->TriangleArray[nF].Vertex[0],
&ret->TriangleArray[nF].TexCoord[0],
&ret->TriangleArray[nF].Normal[0],
&ret->TriangleArray[nF].Vertex[1],
&ret->TriangleArray[nF].TexCoord[1],
&ret->TriangleArray[nF].Normal[1],
&ret->TriangleArray[nF].Vertex[2],
&ret->TriangleArray[nF].TexCoord[2],
&ret->TriangleArray[nF].Normal[2]);
nF++;
}
while (*p++ != (char) 0x0A);
}
return ret;
}
size_t ObjLoadFile(char* szFileName, char** memory)
{
size_t bytes = 0;
FILE* file = fopen(szFileName, "rt");
if (file != NULL)
{
fseek(file, 0, SEEK_END);
size_t end = ftell(file);
fseek(file, 0, SEEK_SET);
*memory = (char*) malloc(end);
bytes = fread(*memory, sizeof(char), end, file);
fclose(file);
}
return bytes;
}
obj.h
#ifndef OBJ_H
#define OBJ_H
struct ObjVertex
{
float x, y, z;
};
typedef ObjVertex ObjNormal;
struct ObjTexCoord
{
float u, v;
};
struct ObjTriangle
{
int Vertex[3];
int Normal[3];
int TexCoord[3];
};
struct ObjModel
{
int nVertex, nNormal, nTexCoord, nTriangle;
ObjVertex* VertexArray;
ObjNormal* NormalArray;
ObjTexCoord* TexCoordArray;
ObjTriangle* TriangleArray;
};
ObjModel* ObjLoadModel(char*, size_t);
size_t ObjLoadFile(char*, char**);
#endif
and the main.cc parts..
char* memory = NULL;
size_t bytes = ObjLoadFile("cornell.obj", &memory);
ObjModel* model = ObjLoadModel(memory, bytes);
*snip*
for (int i = 0; i < model->nTriangle; i++) {
vert0[0] = (double) model->VertexArray[ model->TriangleArray[i].Vertex[0] ].x;
vert0[1] = (double) model->VertexArray[ model->TriangleArray[i].Vertex[0] ].y;
vert0[2] = (double) model->VertexArray[ model->TriangleArray[i].Vertex[0] ].z;
vert1[0] = (double) model->VertexArray[ model->TriangleArray[i].Vertex[1] ].x;
vert1[1] = (double) model->VertexArray[ model->TriangleArray[i].Vertex[1] ].y;
vert1[2] = (double) model->VertexArray[ model->TriangleArray[i].Vertex[1] ].z;
vert2[0] = (double) model->VertexArray[ model->TriangleArray[i].Vertex[2] ].x;
vert2[1] = (double) model->VertexArray[ model->TriangleArray[i].Vertex[2] ].y;
vert2[2] = (double) model->VertexArray[ model->TriangleArray[i].Vertex[2] ].z;
result = intersect_triangle(orig, dir, vert0, vert1, vert2, &t, &u, &v);
... *snip*
