Ray tracing troubles

Started by
2 comments, last by Zipster 18 years, 3 months ago
I'm currently trying to do local illumination in my ray tracer before I go on to do global illumination. All I'm getting are flat colours with my code below. Here is the output I'm getting. ray trace After putting in some printfs I can see that my IsLightVisible() function which tests to see if the view to the light is clear from the intersection point seems to think the light is always visible. I'm going to post the whole source since its all related. I'm using GLUT. Bear in mind that there are some things in the RayTrace() function that are not going to be used until I do global illumination (Iindirect etc.). Can anyone who is more experienced with Ray Tracing help?

#include <GL/glut.h>
#include <stdio.h>
#include <math.h>

//View plane window size
#define XMAX 1.0
#define XMIN -1.0
#define YMAX 1.0
#define YMIN -1.0
#define WIDTH 600
#define HEIGHT 600

//Number of spheres
#define NUMSPHERE 3
//Maximum number of relections
#define MAX 5
#define BOOL int

// Data Structures
//3D points data structure 
typedef struct
{ 
	float x;
	float y;
	float z;
}Point3D, Vector3D;

//Colour data structure 
typedef struct
{
	float r;
	float g;
	float b;
}Colour3f;

//Sphere data structure
typedef struct
{
	float x, y, z;//location
	float r, g, b;//colour
	float radius;
	float KDr, KDg, KDb;//Diffuse reflect
	float KAr, KAg, KAb;//Ambient reflect
	float KS;			//Specular
}Sphere;

//Light data structure
typedef struct
{
	float x, y, z;//location
	float r, g, b;//light colour
}Light;

//Global variables
//array to hold three sphere objects
Sphere sphere [3];
//The light
Light light; 
//Centre of camera projection co-ordinates
Point3D COP = {0, 0, 3 };
//Pixel array for our viewing plane 
Colour3f pixels[WIDTH][HEIGHT];
//Ambient light intensity
Colour3f ambient = { 0.2, 0.2, 0.2 };

// Functions prototypes
//Display function
void display(void);
//Keyboard function
void keyboard(unsigned char key, int x, int y);
//Idle function
void idle(void);
// Setup scene function
void InitScene(void);
//Main control function for the Ray Tracing
void RayTracingScene(void);
//Render scene function
void RenderScene(void);
//Raycasting function
Colour3f RayTrace(Point3D p, Vector3D direction, int depth);
//Normalises a vector
void Normalise(Vector3D* vec);
//Finds the Dot Product between two vectors
float Dot(Vector3D vec1, Vector3D vec2);
//Tests all objects for intersections with the Ray
int TestIntersection(Point3D p, Vector3D direction, Point3D* pd);
//Sees if the light is visible from the object
bool IsLightVisible(Point3D p, Vector3D direction);
//Finds the normal for the sphere at the intersection point
Vector3D FindNormal(Point3D& pi, int sphereIndex);
//Returns the reflection ray of the light on the sphere
Vector3D CalcReflect(Vector3D& light, Vector3D& normal);

int main(int argc, char **argv)
{
	//Creating graphics window
	glutInit(&argc, argv);
	glutInitDisplayMode(GLUT_DOUBLE| GLUT_RGB);
	glutInitWindowSize(WIDTH, HEIGHT);
	glutInitWindowPosition(0, 0);
	glutCreateWindow("Ray Trace");
	InitScene();
	glutDisplayFunc(display);
	glutIdleFunc(idle);
	glutKeyboardFunc(keyboard);
	glMatrixMode(GL_PROJECTION);
	glLoadIdentity();
	glOrtho(0.0, WIDTH, HEIGHT, 0.0, -100.0, 100.0);
	glMatrixMode(GL_MODELVIEW);
	glLoadIdentity();
	glutMainLoop();
	return 0;
}

void InitScene()
{
	//Sphere information: Co-ordinates, radius and colour
	//Sphere 1 co-ordinates, radius and colour
	sphere[0].x = 0.0; 
	sphere[0].y = 0.0;
	sphere[0].z = -2.0; 
	//sphere[0].r = 1.0;
	//sphere[0].g = 0.0;
	//sphere[0].b = 0.0;
	sphere[0].radius = 1.0;
	sphere[0].KAr = 0.2;
	sphere[0].KAg = 0.1;
	sphere[0].KAb = 0.1;
	sphere[0].KDr = 1.0;
	sphere[0].KDg = 0.1;
	sphere[0].KDb = 0.1;
	sphere[0].KS = 0.7;
	//Sphere 2 co-ordinates, radius and colour…………………………………
	sphere[1].x = -1.0; 
	sphere[1].y = 1.0;
	sphere[1].z = -3.0; 
	/*sphere[1].r = 0.0;
	sphere[1].g = 1.0;
	sphere[1].b = 0.0;*/
	sphere[1].radius = 1.0;
	sphere[1].KAr = 0.1;
	sphere[1].KAg = 0.2;
	sphere[1].KAb = 0.1;
	sphere[1].KDr = 0.1;
	sphere[1].KDg = 0.1;
	sphere[1].KDb = 0.1;
	sphere[1].KS = 0.3;
	//Sphere 3 co-ordinates, radius and colour………………………………
	sphere[2].x = 1.0; 
	sphere[2].y = 0.0;
	sphere[2].z = -4.0; 
	/*sphere[2].r = 0.0;
	sphere[2].g = 0.0;
	sphere[2].b = 1.0;*/
	sphere[2].radius = 1.0;
	sphere[2].KAr = 0.1;
	sphere[2].KAg = 0.1;
	sphere[2].KAb = 0.2;
	sphere[2].KDr = 0.1;
	sphere[2].KDg = 0.1;
	sphere[2].KDb = 1.0;
	sphere[2].KS = 0.5;
	//Light
	light.x = 0.0;
	light.y = 5.0;
	light.z = -2.5;
	light.r = 0.2;
	light.g = 0.2;
	light.b = 0.2;

	return;
}

void display()
{
	// clear the offscreenbuffer
	glClearColor(0.0, 0.0, 0.0, 1.0);/*Background colour*/
	glClear(GL_COLOR_BUFFER_BIT);
	glLoadIdentity();
	//Calling raycast function
	RenderScene();	
	glutSwapBuffers();
	
	return;
}

void keyboard(unsigned char key, int x, int y)
{	
}

void idle(void)
{
	glutPostRedisplay();
}

void RayTracingScene(void)
{
	int i, j, k = 0;
	//width and height of each scene pixel
	float pixelwidth, pixelheight;
	//dx, dy, and dz are the values of the directional vector of the ray
	Vector3D v;	
	//Centre of pixels 
	Point3D centreofpix;
	//Determining the width and height of each pixel
	pixelwidth = (XMAX - XMIN) / WIDTH;
	pixelheight = (YMAX - YMIN) / HEIGHT;
	//Incrementing through our scene
	for (i = 0; i < WIDTH; i++)
	{
		for (j = 0; j < HEIGHT; j++)
		{
			//To compare point of first intersection with this large value
			//Determining the centre of our pixels
			centreofpix.x = XMIN + pixelwidth * (i + 0.5);
			centreofpix.y = YMIN + pixelheight * (j + 0.5);
			centreofpix.z = 0;
			//dx, dy, and dz are the values of the directional vector of the ray
			v.x = centreofpix.x-COP.x;
			v.y = centreofpix.y-COP.y;
			v.z = centreofpix.z-COP.z;
			pixels[j] = RayTrace(COP, v, 0);
			//printf("i: %d\tj: %d\tRED: %.2f\tGREEN: %.2f\tBLUE: %.2f\n", i, j, pixels[j].r, pixels[j].g, pixels[j].b);
		}
	}
}

void RenderScene()
{
	RayTracingScene();
	int i, j;
	//Displaying scene pixels and forming an image
	glBegin(GL_POINTS);
	for (i = 0; i< WIDTH; i++)
	{
		for (j = 0; j < HEIGHT; j++)
		{
			glColor3f(pixels[j].r, pixels[j].g, pixels[j].b);
			glVertex2f(i, j);
		}
	}
	glEnd();
	return;
}

Colour3f RayTrace(Point3D p, Vector3D direction, int depth)
{
	Point3D pd;
	Colour3f result = {0.0, 0.0, 0.0};
	if(depth > MAX) //If reached maximum trace depth
		return result; // (0,0,0) 
	else
	{
		int sphereHit = TestIntersection(p, direction, &pd);
		//printf("spherehit = %d\n", sphereHit);
		if(sphereHit == -1) //If no intersection
			return result; // BACKGROUND 
		else
		{
			Colour3f Idirect = { 0.0, 0.0, 0.0 };
			Colour3f Iindirect = { 0.0, 0.0, 0.0 };
			Colour3f Itotal = { 0.0, 0.0, 0.0 };
			Vector3D lightDirection;
			Vector3D normal = FindNormal(pd, sphereHit);
			Normalise(&normal);
			lightDirection.x = light.x - pd.x;
			lightDirection.y = light.y - pd.y;
			lightDirection.z = light.z - pd.z;
			Normalise(&lightDirection);

			if(IsLightVisible(pd, lightDirection))
			{
				//printf("LIGHT VISIBLE!\n");
				Vector3D reflection = CalcReflect(lightDirection, normal);
				Idirect.r = sphere[sphereHit].KAr * ambient.r + 
					(sphere[sphereHit].KDr * Dot(normal, lightDirection) + 
						sphere[sphereHit].KS * Dot(normal, reflection));

				Idirect.g = sphere[sphereHit].KAg * ambient.g + 
					(sphere[sphereHit].KDg * Dot(normal, lightDirection) + 
						sphere[sphereHit].KS * Dot(normal, reflection));

				Idirect.b = sphere[sphereHit].KAb * ambient.b + 
					(sphere[sphereHit].KDb * Dot(normal, lightDirection) + 
						sphere[sphereHit].KS * Dot(normal, reflection));
			}
			else
			{
				//printf("LIGHT NOT VISIBLE!\n");
				Idirect.r = sphere[sphereHit].KAr * ambient.r;
				Idirect.g = sphere[sphereHit].KAg * ambient.g;
				Idirect.b = sphere[sphereHit].KAb * ambient.b;
			}
			//calculate reflection direction R at point pd ;
			//Iindirect = RayTrace(pd, r, depth + 1);
			Itotal.r = Idirect.r;// + Iindirect.r;
			Itotal.g = Idirect.g;// + Iindirect.g;
			Itotal.b = Idirect.b;// + Iindirect.b;
			return Itotal;
		}
	}	
}
//end RayTrace()

int TestIntersection(Point3D p, Vector3D direction, Point3D* pd)
{
	//Used for the co-ordinates of the intersection point with each sphere
	Point3D intersectpoint[NUMSPHERE];
	//A, B, and C of the quadratic equation
	float A, B, C;
	//t-value 
	float t;
	int k;
	int sphereNearest = -1;
	float distance;
	double depth = 10000000;
	//Intersection tests carried out according to the number of objects
	for (k = 0; k < NUMSPHERE; k++) 
	{
		//A, B, and C of the quadratic equation
		A = direction.x * direction.x + direction.y * direction.y + direction.z * direction.z;
		B = (p.x-sphere[k].x) * direction.x + (p.y-sphere[k].y) * direction.y + (p.z-sphere[k].z) * direction.z;
		C = p.x* p.x+ p.y* p.y+ p.z* p.z-2 * (p.x* sphere[k].x+ p.y * 
			sphere[k].y+ p.z* sphere[k].z) + sphere[k].x* sphere[k].x+ sphere[k].y * 
			sphere[k].y+ sphere[k].z* sphere[k].z-sphere[k].radius* sphere[k].radius;
		//Ray tangent to sphere and intersecting in two places to form image of 
		//spheres on viewing plane
		if (B * B - A * C >= 0)
		{
			//Determining the point of intersection
			t = -B - sqrt(B * B - A * C) / A;
			//Determining the co-ordinates of the intersection point
			intersectpoint[k].x = p.x + t * direction.x;
			intersectpoint[k].y = p.y + t * direction.y;
			intersectpoint[k].z = p.z + t * direction.z;
			//Using pythagoras to work out distance between intersection point 
			//and COP
			distance = sqrt((p.x-intersectpoint[k].x) * (p.x-intersectpoint[k].x) + 
				(p.y-intersectpoint[k].y) * (p.y-intersectpoint[k].y) + (p.z-intersectpoint[k]. z ) * 
				( p.z-intersectpoint[k].z));

			//Comparing distance with depth enabling pixels nearest to COP to 
			//form nearest image of sphere
			if (distance < depth)
			{
				sphereNearest = k;
				depth = distance;
			}
		}
	}
	if(sphereNearest != -1)
		*pd = intersectpoint[sphereNearest];
	return sphereNearest;
}

bool IsLightVisible(Point3D p, Vector3D direction)
{
	//A, B, and C of the quadratic equation
	float A, B, C;	
	int k;	
	//Intersection tests carried out according to the number of objects
	for (k = 0; k < NUMSPHERE; k++) 
	{
		//A, B, and C of the quadratic equation
		A = direction.x * direction.x + direction.y * direction.y + direction.z * direction.z;
		B = (p.x-sphere[k].x) * direction.x + (p.y-sphere[k].y) * direction.y + (p.z-sphere[k].z) * direction.z;
		C = p.x* p.x+ p.y* p.y+ p.z* p.z-2 * (p.x* sphere[k].x+ p.y * 
			sphere[k].y+ p.z* sphere[k].z) + sphere[k].x* sphere[k].x+ sphere[k].y * 
			sphere[k].y+ sphere[k].z* sphere[k].z-sphere[k].radius* sphere[k].radius;
		//Ray tangent to sphere and intersecting in two places to form image of 
		//spheres on viewing plane
		if (B * B - A * C >= 0)
		{
			printf("LIGHT CANNOT BE SEEN\n");
			return false;
		}
	}
	return true;
}

void Normalise(Vector3D* vec)
{
	float length = powf(vec->x, 2.0) + powf(vec->y, 2.0) + powf(vec->z, 2.0);
	length = sqrt(length);
	vec->x /= length;
	vec->y /= length;
	vec->z /= length;
}

float Dot(Vector3D vec1, Vector3D vec2)
{
	return vec1.x * vec2.x + vec1.y * vec2.y + vec1.z * vec2.z;
}

Vector3D FindNormal(Point3D& pi, int sphereIndex)
{
	Vector3D normal;
	normal.x = pi.x - sphere[sphereIndex].x * (1.0 / sphere[sphereIndex].radius);
	normal.y = pi.y - sphere[sphereIndex].y * (1.0 / sphere[sphereIndex].radius);
	normal.z = pi.z - sphere[sphereIndex].z * (1.0 / sphere[sphereIndex].radius);
	return normal;
}

Vector3D CalcReflect(Vector3D& light, Vector3D& normal)
{
	Vector3D ref;
	ref.x = light.x - (2.0 * Dot(light, normal) * normal.x);
	ref.y = light.y - (2.0 * Dot(light, normal) * normal.y);
	ref.z = light.z - (2.0 * Dot(light, normal) * normal.z);
	return ref;
}

Advertisement
In your sphere intersection code, you have the incorrect equation for the determinant (it should be B2 - 4AC). If the direction is normalized then A is 1 and disappears from the equation. That might be causing the false positives.
Ok thanks I've changed that but I'm still having problems. Here is a shot of whats happening after 2 rays (initial plus 1 reflection):

second attempt

It seems as though whenever I use the TestIntersection or IsLightVisible functions (IsLightVisible is a slightly cut down version and doesn't calculate distance) at the point of intersection with a sphere it messes up. I can't see what is making it do this. Looks as though its passing straight through the spheres though as the right-hand sphere has reflections where it shouldn't. :(

#include <GL/glut.h>#include <stdio.h>#include <math.h>//View plane window size#define XMAX 12.0#define XMIN -12.0#define YMAX 9.0#define YMIN -9.0#define WIDTH 512#define HEIGHT 384#define NUMSPHERES 3//Maximum number of trace depths#define MAX 1// Data Structures//3D points data structure typedef struct{ 	float x;	float y;	float z;}Point3D, Vector3D;//Colour data structure typedef struct{	float r;	float g;	float b;}Colour3f;//Sphere data structuretypedef struct{	float x, y, z;//location	float r, g, b;//colour	float radius;	float KDr, KDg, KDb;//Diffuse reflect	float KAr, KAg, KAb;//Ambient reflect	float KS;			//Specular}Sphere;//Light data structuretypedef struct{	float x, y, z;//location	float r, g, b;//light colour}Light;float dx = (XMAX - XMIN) / WIDTH;float dy = (YMAX - YMIN) / HEIGHT;Sphere sphere[3];//Centre of camera projection co-ordinatesPoint3D COP = {0, 0, -10 };//Pixel array for our viewing plane Colour3f pixels[WIDTH][HEIGHT];//The lightLight light;//Ambient light intensityColour3f ambient = { 0.7, 0.7, 0.7 };// Functions prototypes//Display functionvoid display(void);//Idle functionvoid idle(void);// Setup scene functionvoid InitScene(void);//Ray tracing function that generates first ray and calls recursive RayTrace functionvoid RayTraceScene(void);//Recursive raytrace functionColour3f RayTrace(Point3D p, Vector3D ray, int depth);//Tests to see if ray intersects any objectsint TestIntersection(Point3D origin, Vector3D ray, Point3D* pi);//Calculates whether the intersection point can see the lightbool IsLightVisible(Point3D origin, Vector3D ray);//Finds the normal at intersection point with the sphereVector3D FindNormal(Point3D& pi, int sphereIndex);//Calculates the reflection rayVector3D CalcReflect(Vector3D& in, Vector3D& normal);//Normalises a vectorvoid Normalise(Vector3D* vec);//Finds the Dot Product between two vectorsfloat Dot(Vector3D vec1, Vector3D vec2);int main(int argc, char **argv){	//Creating graphics window	glutInit(&argc, argv);	glutInitDisplayMode(GLUT_DOUBLE| GLUT_RGB);	glutInitWindowSize(WIDTH, HEIGHT);	glutInitWindowPosition(0, 0);	glutCreateWindow("Ray Trace");	InitScene();	glutDisplayFunc(display);	glutIdleFunc(idle);	glMatrixMode(GL_PROJECTION);	glLoadIdentity();	glOrtho(0.0, WIDTH, HEIGHT, 0.0, -100.0, 100.0);	glMatrixMode(GL_MODELVIEW);	glLoadIdentity();	glutMainLoop();		return 0;}void display(){	int i, j;	// clear the offscreenbuffer	glClearColor(0.0, 0.0, 0.0, 1.0);/*Background colour*/	glClear(GL_COLOR_BUFFER_BIT);	glLoadIdentity();	//Calling raycast function	RayTraceScene();	//Displaying scene pixels and forming an image	glBegin(GL_POINTS);	for (i = 0; i< WIDTH; i++)	{		for (j = 0; j < HEIGHT; j++)		{			glColor3f(pixels[j].r, pixels[j].g, pixels[j].b);			glVertex2f(i, j);		}	}	glEnd();	glutSwapBuffers();		return;}void idle(void){	glutPostRedisplay();}void InitScene(void){	sphere[0].x = 0.0;	sphere[0].y = 0.0;	sphere[0].z = 7.0;	sphere[0].radius = 4.0;	sphere[0].r = 1.0;	sphere[0].g = 0.0;	sphere[0].b = 0.0;	sphere[0].KAr = 0.2;	sphere[0].KAg = 0.1;	sphere[0].KAb = 0.1;	sphere[0].KDr = 0.9;	sphere[0].KDg = 0.1;	sphere[0].KDb = 0.1;	sphere[0].KS = 0.2;	sphere[1].x = 7.0;	sphere[1].y = 3.0;	sphere[1].z = 5.0;	sphere[1].radius = 3.0;	sphere[1].r = 0.0;	sphere[1].g = 1.0;	sphere[1].b = 0.0;	sphere[1].KAr = 0.1;	sphere[1].KAg = 0.2;	sphere[1].KAb = 0.1;	sphere[1].KDr = 0.1;	sphere[1].KDg = 0.8;	sphere[1].KDb = 0.1;	sphere[1].KS = 0.3;	sphere[2].x = -7.0;	sphere[2].y = -3.0;	sphere[2].z = 5.0;	sphere[2].radius = 3.0;	sphere[2].r = 0.0;	sphere[2].g = 0.0;	sphere[2].b = 1.0;	sphere[2].KAr = 0.2;	sphere[2].KAg = 0.2;	sphere[2].KAb = 0.2;	sphere[2].KDr = 0.8;	sphere[2].KDg = 0.8;	sphere[2].KDb = 1.0;	sphere[2].KS = 0.5;	light.x = 0.0;	light.y = 0.0;	light.z = 1.5;	light.r = 1.0;	light.g = 1.0;	light.b = 1.0;}void RayTraceScene(void){	Vector3D ray;	float Xp, Yp, Zp = 0.0;	int i, j;	for (i = 0; i < WIDTH; i++)	{		for (j = 0; j < HEIGHT; j++)		{			Xp = XMIN + 0.5 * dx + i * dx;			Yp = YMAX - 0.5 * dy - j * dy;			Zp = 0; // since image plane is at Z = 0			ray.x = Xp - COP.x;			ray.y = Yp - COP.y;			ray.z = Zp - COP.z;			Normalise(&ray);			pixels[j] = RayTrace(COP, ray, 0);		}	}}Colour3f RayTrace(Point3D p, Vector3D ray, int depth){	Point3D pd;	Colour3f result = {0.0, 0.0, 0.0};	if(depth > MAX) //If reached maximum trace depth		return result; // (0,0,0) 	else	{		int sphereHit = TestIntersection(p, ray, &pd);		//printf("spherehit = %d\n", sphereHit);		if(sphereHit == -1) //If no intersection			return result; // BACKGROUND 		else		{			Colour3f Idirect = { 0.0, 0.0, 0.0 };			Colour3f Iindirect = { 0.0, 0.0, 0.0 };			Colour3f Itotal = { 0.0, 0.0, 0.0 };			Vector3D lightDirection;			Vector3D normal = FindNormal(pd, sphereHit);			lightDirection.x = light.x - pd.x;			lightDirection.y = light.y - pd.y;			lightDirection.z = light.z - pd.z;			Normalise(&lightDirection);			Vector3D temp;			if(TestIntersection(pd, lightDirection, &temp) != -1)			//float dot = Dot(normal, lightDirection);			//if (dot > 0)			{				//Idirect.r = 1.0;				//Idirect.b = 1.0;				//Idirect.g = 1.0;				//printf("LIGHT VISIBLE!\n");				Vector3D reflection = CalcReflect(lightDirection, normal);				Idirect.r = sphere[sphereHit].KAr * ambient.r + light.r *					(sphere[sphereHit].KDr * Dot(normal, lightDirection)) + 						(sphere[sphereHit].KS * Dot(normal, reflection));				Idirect.g = sphere[sphereHit].KAg * ambient.g + light.g * 					(sphere[sphereHit].KDg * Dot(normal, lightDirection)) + 						(sphere[sphereHit].KS * Dot(normal, reflection));				Idirect.b = sphere[sphereHit].KAb * ambient.b + light.b * 					(sphere[sphereHit].KDb * Dot(normal, lightDirection)) + 						(sphere[sphereHit].KS * Dot(normal, reflection));			}			else			{				//printf("LIGHT NOT VISIBLE!\n");				Idirect.r = sphere[sphereHit].KAr * ambient.r;				Idirect.g = sphere[sphereHit].KAg * ambient.g;				Idirect.b = sphere[sphereHit].KAb * ambient.b;			}			//calculate reflection direction at point pd			Vector3D reflect = CalcReflect(ray, normal);			Iindirect = RayTrace(pd, reflect, depth + 1);			Itotal.r = Idirect.r + Iindirect.r;			Itotal.g = Idirect.g + Iindirect.g;			Itotal.b = Idirect.b + Iindirect.b;			return Itotal;		}	}	}int TestIntersection(Point3D origin, Vector3D ray, Point3D* pi){	int sphereHit = -1;	float depth = 10000000;	float distance;	float A, B, C;	int k;	for(k = 0; k < NUMSPHERES; k++)	{		A = powf(ray.x, 2.0) + powf(ray.y, 2.0) + powf(ray.z, 2.0);//  = 1 since ray is normalised		B = 2 * (ray.x * (origin.x - sphere[k].x) + ray.y * (origin.y - sphere[k].y) + ray.z * (origin.z - sphere[k].z)); //-39.85		C = powf((origin.x - sphere[k].x), 2.0) + powf((origin.y - sphere[k].y), 2.0)			+ powf((origin.z - sphere[k].z), 2.0) - powf(sphere[k].radius, 2.0); // 375		if(B * B - 4 * C >= 0)		{			float t0 = (- B - sqrtf(B * B - 4 * C)) / 2;			//float t1 = (B + sqrtf(B * B - 4 * C)) / 2;			//Find intersect point			pi->x = origin.x + ray.x * t0;			pi->y = origin.y + ray.y * t0;			pi->z = origin.z + ray.z * t0;			//Work out distance from origin to intersect point			distance = sqrtf((origin.x - pi->x) * (origin.x - pi->x) + 				(origin.y - pi->y) * (origin.y - pi->y) + (origin.z - pi->z) * (origin.z - pi->z));			if(t0 < depth)			{								depth = t0;				sphereHit = k;			}		} 	}	return sphereHit;}bool IsLightVisible(Point3D origin, Vector3D ray){	//A, B, and C of the quadratic equation	float A, B, C;		int k;		//Intersection tests carried out according to the number of objects	for (k = 0; k < NUMSPHERES; k++) 	{		//A, B, and C of the quadratic equation		A = powf(ray.x, 2.0) + powf(ray.y, 2.0) + powf(ray.z, 2.0);//  = 1 since ray is normalised		B = 2 * (ray.x * (origin.x - sphere[k].x) + ray.y * (origin.y - sphere[k].y) + ray.z * (origin.z - sphere[k].z));				C = powf((origin.x - sphere[k].x), 2.0) + powf((origin.y - sphere[k].y), 2.0)			+ powf((origin.z - sphere[k].z), 2.0) - powf(sphere[k].radius, 2.0); 		//Ray tangent to sphere and intersecting in two places to form image of 		//spheres on viewing plane		printf("B: %.2f\n", B);		if(B * B - 4 * C >= 0)		{			//printf("LIGHT CANNOT BE SEEN\n");			return false;		}	}	printf("LIGHT SEEN\n");	return true;}Vector3D FindNormal(Point3D& pi, int sphereIndex){	Vector3D normal;	normal.x = (pi.x - sphere[sphereIndex].x) / sphere[sphereIndex].radius;	normal.y = (pi.y - sphere[sphereIndex].y) / sphere[sphereIndex].radius;	normal.z = (pi.z - sphere[sphereIndex].z) / sphere[sphereIndex].radius;	return normal;}Vector3D CalcReflect(Vector3D& in, Vector3D& normal){	// Formula: R = V – 2 * (V·N) * N 	Vector3D ref;	//Vector3D lightTemp = { -light.x, -light.y, -light.z };	ref.x = in.x - (2.0 * Dot(in, normal) * normal.x);	ref.y = in.y - (2.0 * Dot(in, normal) * normal.y);	ref.z = in.z - (2.0 * Dot(in, normal) * normal.z);	/*ref.x = 2 * normal.x * Dot(normal, lightTemp) - lightTemp.x;	ref.y = 2 * normal.y * Dot(normal, lightTemp) - lightTemp.y;	ref.z = 2 * normal.z * Dot(normal, lightTemp) - lightTemp.z;*/	return ref;}void Normalise(Vector3D* vec){	float length = powf(vec->x, 2.0) + powf(vec->y, 2.0) + powf(vec->z, 2.0);	length = sqrtf(length);	vec->x /= length;	vec->y /= length;	vec->z /= length;}float Dot(Vector3D vec1, Vector3D vec2){	return vec1.x * vec2.x + vec1.y * vec2.y + vec1.z * vec2.z;}


Any help appreciated.
When performing ray tracing, it's usually a good idea to add a small fudge factor to the intersection point in the direction of the new cast before casting the reflection/refraction/translucence ray so that you don't intersect with the original surface at t = 0. It doesn't have to be much, something like pd + reflect * 0.0001f should do. Either that, or you keep track of the original sphere intersected and don't check against that one. However this only works when doing reflection, since you'll need to be able to cast a ray through the middle of a sphere with refraction and translucence.

Second, you have to keep in mind that the sphere intersection code returns two results. You want the smallest positive root, but right now you only take the smallest root and don't check if it's also positive. This doesn't affect anything in your ray tracer at the moment as all intersection points are in front of the ray, but if you add refraction and translucence you may get an intersection point behind the ray with t0 < 0 and it's important that it be rejected. Likewise, if t1 < 0 then it should also be rejected.

Third, your lighting model looks off. A lot of it can be explained due to the intersection code but the specular lighting is still weird and there's no light attenuation, which is what provides you with a smooth surface appearance. When you calculate the reflection vector, the input vector will either be "pointing" toward or away from the surface. In other words, either V.N > 0 or V.N < 0, but the equation you use is only designed for the latter case when it "points" toward the surface. When calculating the specular lighting your input vector points away from the surface toward the light, so the reflection vector you use for specular lighting is incorrect. I can tell you that the OpenGL model doesn't calculate light reflection at all - this page gives a good overview of how the lighting is calculated. Attenuation is covered on that page as well.

Finally, something that isn't critical but still bothers me a little is your use of powf [smile] It's much more efficient and easier to read if you do x * x.

This topic is closed to new replies.

Advertisement