Ray Trace Shading Problem: Isn't shaded

Hello all,

I’m a CS student and for our final we were told to construct the reflections on multiple spheres via ray tracing. That’s almost literally what we got for directions except a picture for how it should look when finished. So I need spheres, with they’re reflections (using ray tracing) mapped on them with the proper shading from a light.

Well I have all of it working, except having multiple spheres and the fact that it doesn’t look like the picture he gave us for a rubric.

The multiple spheres thing I’m not too sure how to do, but I’d say I need to store them in a 2D array and modify a few sections of code.

What I thought was modifying the sphere_intersect and find_reflect to include which sphere is being analyzed. Next, modify find_reflect so that when the new vector u is calculated its starting point (P0) is also updated. Then if the ray hits a sphere it will have to count how many times the ray has been reflected. At some point terminate (after 10 times maybe) and then I’ll just draw the pixel. For an added touch I’d like to add solid colors to the spheres which would call for finding the normal of a sphere I believe.

Anyways I’m going to attach a picture of his, a picture of mine, and the source code. Hopefully someone can help me out on this one.

Thanks in advance!

 


#include "stdafx.h"
#include <stdio.h>
#include <stdlib.h>
#include <GL/glut.h>
#include <math.h>
#include <string>

#define screen_width 750
#define screen_height 750
#define true 1
#define false 0
#define perpendicular 0

int gridXsize = 20;
int gridZsize = 20;
float plane[] = {0.0, 1.0, 0.0, -50.0,};
float sphere[] = {250.0, 270.0, -100.0, 100.0};
float eye[] ={0.0, 400.0, 550.0};
float light[] = {250.0, 550.0, -200.0};

float dot(float *u, float *v)
{
	return u[0]*v[0] + u[1]*v[1] + u[2]*v[2];
}

void norm(float *u)
{
	float norm = sqrt(abs(dot(u,u)));
	for(int i =0; i <3; i++)
	{
		u[i] = u[i]/norm;
	}
	
}

float plane_intersect(float *u, float *pO)
{
	float normt[3] = {plane[0], plane[1], plane[2]};
	
	float s;
	if(dot(u,normt) == 0)
		s = -10;
	else
		s = (plane[3]-(dot(pO,normt)))/(dot(u,normt));
	
	return s;
}

float sphere_intersect(float *u, float *pO)
{
	
	float deltaP[3] = {sphere[0]-pO[0],sphere[1]-pO[1],sphere[2]-pO[2]};
	float deltLen = sqrt(abs(dot(deltaP,deltaP)));
	float t=0;
	float answer;
	float det;
	if ((det =( abs(dot(u,deltaP)*dot(u,deltaP))-(deltLen*deltLen)+sphere[3]*sphere[3])) < 0)
		answer = -10;
	else
	{		
		t =-1*dot(u,deltaP)- sqrt(det) ;
		if(t>0)
			answer = t;
		else answer = -10;
	}
	return answer;
}

void find_reflect(float *u, float s, float *pO)
{
	float n[3] = {pO[0]+s*u[0]-sphere[0],pO[1]+s*u[1]-sphere[1],pO[2]+s*u[2]-sphere[2]};
	float l[3] = {s*u[0],s*u[1],s*u[2]};
	u[0] =(2*dot(l,n)*n[0])-l[0];
	u[1] = (2*dot(l,n)*n[1])-l[1];
	u[2] =  (2*dot(l,n)*n[2])-l[2];
}

float find_shade(float *u,float s, float *pO )
{
		float answer;
		float lightVec[3] = {light[0]-(pO[0]+s*u[0]), light[1]-(pO[1]+s*u[1]), light[2]-(pO[2]+s*u[2])};
		float n[3] = {pO[0]+s*u[0]-sphere[0],pO[1]+s*u[1]-sphere[1],pO[2]+s*u[2]-sphere[2]};
		answer = -1*dot(lightVec,n)/(sqrt(abs(dot(lightVec,lightVec)))*sqrt(abs(dot(n,n))));
		return answer;
}

void init()
{
	glMatrixMode(GL_PROJECTION);
	glLoadIdentity();
	gluOrtho2D(0,screen_width,0,screen_height);
}

void display()
{
	glClear(GL_COLOR_BUFFER_BIT| GL_DEPTH_BUFFER_BIT);
	glMatrixMode(GL_MODELVIEW);
	glLoadIdentity();
	for(int i=0; i < screen_width;i++)
	{
		for(int j=0; j < screen_height; j++)
		{
			float ray[3] = {1*(eye[0]-i),-1*(eye[1]-j),1*eye[2]};
			float point[3] ={i,j,0};
			norm(ray);
			int plotted = false;
			while(!plotted)
			{
				float s_plane = plane_intersect(ray, point);
				float s_sphere = sphere_intersect(ray, point);

				if(s_plane <= 0 && s_sphere <=0)
				{
					glColor3f(0,0,0);
					glBegin(GL_POINTS);
						glVertex3f(i,j,0);
					glEnd();
					plotted = true;
				}
				else if (s_sphere >= 0  && (s_plane <=0 || s_sphere <= s_plane))
				{
					find_reflect(ray, s_sphere, point);
				}
				else if(s_plane >=0 && (s_sphere <=0 ||s_plane <= s_sphere))
				{
					float shade = find_shade(ray, s_plane, point);
					float xx = s_plane*ray[0] + eye[0];
					float z = s_plane*ray[2] + eye[2];
					if(abs((int)xx/gridXsize)%2 == abs((int)z/gridZsize)%2)
						glColor3f(shade,0,0);
					else
						glColor3f(shade,shade,shade);
					glBegin(GL_POINTS);
					glVertex3f(i,j,0);
					glEnd();
					plotted = true;
				}
			}
		}
	}
	glFlush();
}

int main(int argc, char** argv)
{
	glutInit(&argc, argv);
	glutCreateWindow("Ray Trace with Sphere.");
	glutInitWindowSize(screen_width,screen_height);
	glutInitDisplayMode(GLUT_SINGLE|GLUT_RGB);
	glutDisplayFunc(display);
	init();
	glutMainLoop();
	return 0;
}

Hi,
You need to restructure your code. You should create a simple structure for holding the sphere’s position and radius like this,


struct Sphere { vec3 center; float radius;};

Next, modify the intersect function to accept a Sphere as parameter.


float sphere_intersect(float *u, float *pO, Sphere& whichSphere)
{

}

Now when raytracing, loop through all primitives i.e. all spheres and the ground plane and test each for the ray intersection however return the nearest hit. So at a high level, it is something like this,


float tmin = INFINITY;
for each sphere s
   float t = intersectSphere(ray, s);
   if(t<tmin && t>0)
   {
      tmin = t; 
   }
end for

//do the same for other primitives

Now at the end of the above calls, tmin contains the nearest t value (i.e. the nearest intersection point. get the points coord by simply putting in ray equation. For sphere’s normal simply subtract the hit point from its center.

Do this much and let me know if there is any progress.