Ray Tracer Question


#39

excellent :smiley:

what was the problem?


#40

My problem was here:
clostesSphere should be less than 0 and closesSphereDistance should be high to ensure that a new distance is assigned to i when I check for spheres.


 			// A variable for checking which sphere is closest
 			float closesSphereDistance = -1;
 			int closestSphere = 0;
 

Right now I am trying to add lights to it, but I am stuggeling a bit with adding it. Somehow I get a flat color, so it looks like the picture above, just a bit lighter.

Any ideas`?


#41

oh how annoying - it’s always simple things!

are you calculating the colour using equations for ambient, diffuse and specular? and you’re using the angle of incidence etc etc?

it’s these things that will make it look 3d so if you are just combining the object colour and the light colour then it will appear flat


#42

I think its defuse lightning I am doing.

Here is the code for it:


 // We have now looped through all the spheres in the scene and found
			// the closest one
			// Find the color of it
			if ( closestSphere != -1 )
			{

				//std::cout << closesSphereDistance << std::endl;
				
				float r, g, b = 0;
				
				// Check which if there is a light affecting the sphere
				for (int currentLight = 0; currentLight <= thisScene.getAmountOfObjects(); currentLight++)
				{
					Vector3D sphereRayIntersection;
					Point rayOrg = currentRay.getOrigin();
					
					// Add the start point of the ray and the direction of the sphere together
					// and mult. it with the distance to closest sphere
					sphereRayIntersection = currentRay.getDirection();
					sphereRayIntersection.setX(rayOrg.getX() + (sphereRayIntersection.getX() * closesSphereDistance ));
					sphereRayIntersection.setY(rayOrg.getY() + (sphereRayIntersection.getY() * closesSphereDistance ));
					sphereRayIntersection.setZ(rayOrg.getZ() + (sphereRayIntersection.getZ() * closesSphereDistance ));
					
					
					// Find the normal to the sphere at point of intersection
					Sphere thisSphere = thisScene.getSphere(closestSphere);
					Vector3D normal;
					float oneOverRadius = 1/thisSphere.getRadius();
					
					normal = sphereRayIntersection - thisSphere.getPosition();
					normal.scale(oneOverRadius);
					
					normal.normalize();
					
					// Get the light direction
					Vector3D lightDir;
					
					Sphere thisLight = thisScene.getLight(currentLight);
					lightDir = thisLight.getPosition() - sphereRayIntersection;
									 
					lightDir.normalize();
   
					// Find light coefficient
					float lightCoef = AbsDot(lightDir,normal);
					if (lightCoef < 0)
					   lightCoef = 0;
					   
					
					// Get the color of the light and how much it affects the sphere
					Material thisMaterial = thisLight.getMaterial();
					
					float lightR = thisMaterial.getR() * lightCoef;
					float lightG = thisMaterial.getG() * lightCoef;
					float lightB = thisMaterial.getB() * lightCoef;
					
					
					// Add the effect of the light to the color of the sphere
					Material sphereColor = thisSphere.getMaterial();
					
					 r = ((sphereColor.getR() * lightR) / 255 );
					 g = ((sphereColor.getG() * lightG) / 255);
					 b = ((sphereColor.getB() * lightB) / 255);
					 
					 
					
					// Make sure that the color is not higher than 255
					if (r > 255)
					   r = 255;
					if (g > 255)
					   g = 255;
					if (b > 255)
					   b = 255;
					   
					   //std::cout << r << "," << g << "," << b << std::endl;
				}
					   
				// Assign the color to the pixel
				int colorR = r;
				int colorG = g;
				int colorB = b;
				
				colorBuffer[arrayTracer + 0] = colorR;
				colorBuffer[arrayTracer + 1] = colorG;
				colorBuffer[arrayTracer + 2] = colorB;
				
			}   

Going to do some reading today on the topic of adding light, as I am not 100% sure how its done.


#43

Ok, I have given up the code posted above and decided to try the algorithm from an other tutorialinsted.

I find the code in that tutorial kind of confusing as the variable names and commenst are weird. So I have rewriten it in my own words insted. Is this right?

I am not sure what everything here does, as my math knowledge is kind of limited (going to cover this next year :slight_smile: ) so I was wondering if someone could comment in a bit or something to give me a clue of what is going one.

Kind of feeling like I am flooding the forum here:p When you are tierdof me, just ask me to shut up :slight_smile:


for(each light in the scene)
{
		 // dist = the distance between the ray.org and the intersectionPoint
		 Vector lenght = Sphere.position - (ray.org + ray.dir * dist)
		 Normalize(lenght)
		 
		 Vector normal = Normal(ray.org + ray.dir + dist)
		 
		 dotProduct = Dot(normal, light)
		 if(dotPoroduct > 0)
		 {
			 DiffuseColor = dotPoroduct * sphere.diffuseValue
			 finalColor += DiffuseColor * sphere.color * lightColor
		 }
}



#44

Please keep posting. :smiley:


#45

This seems almost correct.

for (each light)
{
Vector Normal = intersection_pt - sphere.position;

Normal.normalize(); // normalize the normal

Vector LightDir = light.position - intersection_pt;

LightDir.normalize(); // normalize the light vector

float dot = clamp(0, 1, Dot(Normal, LightDir));

finalColor += dot * sphere.diffuseValue (this is a scalar value to increase the diffuse effect) * sphere.color * lightColor;

}


#46

for (each light)
{
Vector Normal = intersection_pt - sphere.position;

Normal.normalize(); // normalize the normal

Vector LightDir = light.position  - intersection_pt;

LightDir.normalize(); // normalize the light vector

float dot = clamp(0, 1, Dot(Normal, LightDir));

 finalColor += dot * sphere.diffuseValue (this is a scalar value to increase the diffuse effect) * sphere.color * lightColor;

}

Thanks for sharing, I will try to add it do my own code tonight.

The more and more I work on this project I realize that I have a fundamental problem, as I lack knowledge in math and fundamental computer graphics. So I guess I have to find the money to get myself a new book. Could anyone recomend a book which covers the math in computer graphics? Not just has it as an introduction before the other topic starts, but that has math as one of its main topics. Other topics I would like to know more about is rendering/raytracing and physic simulation. So, do anyone by chance know of a book that would work for me?

Thanks in advance


#47

Woho, next step reached :slight_smile:


#48

How many lights do you have in the scene? The bottom of the spheres seems off unless you have a light placed near the bottom of the sphere and pointed up.

Btw, congrats on the next level! :thumbsup:

I’ll leave you to exploring now. Good Luck!

Cheers,

-M


#49

woohoo! go H3ro!! isn’t it satisfying to see the results of something you’ve made from scratch :slight_smile: i think i’ve still got the pic of my v first ray-traced sphere (yes i know i’m a little bit sad)

books-wise i’ve got the classic Foley book: Introduction to Computer Graphics
http://www.amazon.com/Introduction-Computer-Graphics-James-Foley/dp/0201609215/ref=sr_1_3/103-9288412-5006250?ie=UTF8&s=books&qid=1177319231&sr=8-3

I had to buy it for a course at uni but i really think it’s worthwhile. it doesn’t cover things like differential equations but it does all your vector/matrix math very clearly - as well as projections, parametric curves/surgaces, solid modelling etc. there are a couple of chapters that are’nt interesting to me at all (Input Devices, Graphics Hardware etc) but it gives you a nice theoretical coverage of main topics. Only problem is that it doesn’t go into detail on everything - but it’s a great all-rounder. And i found that you can google anything that’s missing.

finally - try the sticky at the top of this forum - i think there’s a book review there


#50

How many lights do you have in the scene? The bottom of the spheres seems o unless you have a light placed near the bottom of the sphere and pointed up.

There is only one light in the scene, so there is a small bug somewhere. I guess it has something to do with my light being to bright(have to do finalColor / 1000000 to get something usefull).

woohoo! go H3ro!! isn’t it satisfying to see the results of something you’ve made from scratch :slight_smile: i think i’ve still got the pic of my v first ray-traced sphere (yes i know i’m a little bit sad)

Hehe, its like a baby:P It was kind of satisfying to see that something that I have spendt that much time

books-wise i’ve got the classic Foley book: Introduction to Computer Graphics
http://www.amazon.com/Introduction-…77319231&sr=8-3

I will see if I can get my hands on it, thanks for recomending:)

I am now in the progres of rewriting the whole program (lot of crap and “hacks” to make it work) so that it can support more interesting objects than just spheres. Finally the book I first bought are starting to make some sense to me, so hopefully I will be able to use it as a reference instead of browsing for tutorials and sourcecode online.

I will post more when I have something interesting to show :slight_smile:

Thanks for all support, would never got this to work if it was not for the help I got from you guys.


#51

By the looks of it, I’d say you’re calculating how perpendicular/parralel the normal on the sphere is without taking into account whether its facing towards or away from the light (+/- relative). I’m afraid I’m not especially well ATM so maybe someone else can demonstrate the math relative to a non-planar object?

Also, the Introduction book may not go into great detail, but the other book listed under ‘better together’ is one I’ve recommended many a time, is by the same authors and goes into stupid levels of detail… and by stupid I mean BSc (Honours) levels of detail.


#52

Now I have rewritten my intersection code so that it takes into account if its starts inside of an object. I am not sure how to calc the intersection point, but I think it is done by:
(ray.dir + distanceBetweenRayAndSphere) + ray.start

Is that right?


 // The intersectiontest between a sphere and a ray:
 result Sphere::intersectionTest(Ray r)
 {
 	   // A variable for holding the result
 	   result res;
 	   
 	   // Change the point where the ray starts into a vector to
 	   // ease calculations later on
 	   Point rayOrgP = r.getOrigin();
 	   Vector3D rayOrg(rayOrgP.getX(), rayOrgP.getY(), rayOrgP.getZ());
 	   
 	   // Find a vector from the ray origin to the center of the sphere,
 	   Vector3D RaySphereDirection = getPos() - rayOrg;
 	   
 	   float DotRaySphereDirection = Dot(RaySphereDirection, RaySphereDirection);
 	   
 	   // Check if the ray starts inside of the sphere
 	   if (DotRaySphereDirection < (radius * radius))
 	   {
 		   // Find t
 		   float t = Dot(RaySphereDirection, r.getDirection());
 		   float t2 = (radius * radius) - DotRaySphereDirection + (t * t) / 
 					  (Dot(r.getDirection(),r.getDirection()));
 		   float distance = t - sqrt(t2);
 		   
 		   // The ray hits the inside of the sphere
 		   res.hit = -1;
 		   res.distance = distance;
 		   //res.intersectionPoint = ??
 		   
 		   return res;
 	   }
 	   else
 	   {
 		   float t = Dot(RaySphereDirection,r.getDirection());
 		   if (t < 0)
 		   {
 				 // The ray points away from the sphere
 				 // MISS
 				 res.hit = 0;
 				 
 				 return res;
 		   }
 		   float t2 = (radius * radius) - DotRaySphereDirection + (t * t) /
 					  (Dot(r.getDirection(),r.getDirection()));
 					  
 		   if (t2 > 0)
 		   {
 				  // The ray hits the outside
 				  res.hit = 1;
 				  res.distance = t - sqrt(t2);
 				  //res.intersectionPoint = ??
 		   }
 		   else
 		   {
 			   res.hit = 0;
 		   }
 	   }	  
 }
 

#53

Shaderhacker - is this the C equivalent of:

struct RGB{
unsigned int r;
unsigned int g;
unsigned int b;
unsigned int a;
};

???

or is there a subtle difference?
cheers
Holly


#54

In strict C, this struct :

 
  struct RGB{
  unsigned int r;
    unsigned int g;
    unsigned int b;
    unsigned int a;
};
  

would need to instanced with :


  struct RGB someInstance;
  

so, you could do :


  typedef struct RGB RGB;
  
  RGB someInstance;
  

or, you could collapse the entire thing to :

 
   typedef struct {
  unsigned int r;
  unsigned int g;
  unsigned int b;
  unsigned int a;
} RGB;
   

which would typedef the entire struct definition to RGB. In C++, this was one of the first things that got simplified, so to maintain portability :

 
   struct RGB {
  unsigned int r;
  unsigned int g;
  unsigned int b;
  unsigned int a;
};
   

can be instanced (in C++) with either :

 
  struct RGB someInstance;
  
  // or 
  RGB someInstance;
   

#55

cool - thanks Rob - that’s what i thought


#56

Ok, now I’m back again, with some more questions:P

I have rewritten most of the raytracer, so it can more easily take different types of objects, and removed alot of nasty stuff and crap.

I am now at the point where the other raytracer was, so nothing new. But this time something weird has happened, I have transparency, but no clue why :stuck_out_tongue:

Here is the code:


  Color addDiffuse(int closestPrim, Ray &r, Vector3D &intersectionPoint, Scene &thisScene)
  {
  	 Color primCol;
  	 primCol.r = 0;
  	 primCol.g = 0;
  	 primCol.b = 0;
  	  
  	 for (int currentLight = 0; currentLight <= thisScene.getNrLights(); currentLight++)
  	 {
  		 // Find the closest Primitive and the material of it
  		 Primitive *closestPrimitive = thisScene.getPrimitive(closestPrim);
  		 Material *primColor = closestPrimitive->getMaterial();
  		 
  		 // Find the light we are currently using and the color of it
  		 Light *testLight = thisScene.getLight(currentLight);
  		 Color lightColor = testLight->getColor();
  		 
  		 // Find the normal
  		 Vector3D normal = intersectionPoint - closestPrimitive->getPos();
  		 normal.normalize();
  		 
  		 // Find the light direction
  		 Vector3D lightDir = testLight->getPos() - intersectionPoint;
  		 lightDir.normalize();
  		 
  		 float dot = Dot(normal, lightDir);
  		 if (dot < 0)
  			dot = 0;
  			
  		 // Find the color
  		 primCol.r += (int)(dot * primColor->getDiffuse() * primColor->getR() * lightColor.r);
  		 primCol.g += (int)(dot * primColor->getDiffuse() * primColor->getG() * lightColor.g);
  		 primCol.b += (int)(dot * primColor->getDiffuse() * primColor->getB() * lightColor.b);
  		 
  		 // Clamp he color
  		 if (primCol.r >= 255)
  			primCol.r = 255;
  		 if (primCol.g >= 255)
  			primCol.g = 255;
  		 if (primCol.b >= 255)
  			primCol.b = 255;   
  	 }
  	 return primCol;
  }
  

Any ideas anyone?

EDIT: Firefox with spell checker now installed:)

:slight_smile:


#57

I only have time for a quick look but it appears that your diffuse code is fine (I think; again, I only glossed over it). One thing to check is that you’re only computing the surface of the closest ray (and not adding up the result from all objects the ray could intersect).

Double check all sections of code where you’re adding colours together, chances are that’s where the problem is originating from :slight_smile:


#58

Thanks for your reply. That was the first thing I suspected as well, but the problem is that there is not adding up of colors. Or there is one, where I add the effects of all the lights, but as there is only one light in my scene this should not cause the effect.


   		 // Find the color
   		 primCol.r += (int)(dot * primColor->getDiffuse() * primColor->getR() * lightColor.r);
   		 primCol.g += (int)(dot * primColor->getDiffuse() * primColor->getG() * lightColor.g);
   		 primCol.b += (int)(dot * primColor->getDiffuse() * primColor->getB() * lightColor.b);
 

I have also tried to change the above code from “+=” to “=” but the result is the same. After what I know about raytracing(limited knowledge) it should be impossible to have transparency without shooting some secondary rays to find whats behind the original object?

The part belove here is the “core” part of the raytracer, if that in someway can help.


 	// This is where the raytracing is done. Here we create a ray 
 	// and trace it through the scene to see if there is an 
 	// intersection. Then we set the color at the corresponding pixel
 	// We make a loop for the hight and the width in order to trace
 	// all pixels
 	for (int y = 0; y < hight; y++)
 	{
 		for (int x = 0; x < widht; x++, arrayTracer+=3)
 		{			
 			//std::cout << x << "," << y << ": We are here" << std::endl;
 			// Set the ray to trace through the current pixel
 			currentRay.setDirection(directionList[x + y * widht]);
 			
 			// Variables for checking which objects that are closest to the
 			// camera
 			float closestDistance = 1000000;
 			int closestPrimitive = -1;
 
 			
 			// Loop through all the primitives in the scene and return the 
 			// the closest one
 			for (int currentPrimitive = 0; currentPrimitive <=totalPrimitves;
 				 currentPrimitive++)
 			{	
 				 // Find the primitive we are currently testing against
 				 Primitive* testObject = thisScene.getPrimitive(currentPrimitive);
 				 
 				 // Check if the ray hits the current object
 				 intersectionRes = testObject->intersectionTest(currentRay);
 				 
 				 // If the ray hits something, check if its the closest object
 				 if  (intersectionRes.hit == 1)
 				 {   
 					// Find closest primitive by comparing distance
 					if (intersectionRes.distance < closestDistance )
 					{
 						closestDistance = intersectionRes.distance;
 						closestPrimitive = currentPrimitive;	
 					}
 				 }
 			}
 			
 			// We now know if the ray has hit something and what the closest object is
 			if (closestPrimitive != -1)
 			{				 
 				 // Store the color 
 				 Color currentColor;
 				 
 				 // Find the intersectionPoint between the ray and the closest
 				 // primitive
 				 Vector3D interPoint = currentRay.getDirection();
 				 interPoint.scale(intersectionRes.distance);
 				 interPoint = interPoint + PointToVector3D(currentRay.getOrigin());
 				 
 				 // Add diffuse lighting
 				 currentColor = addDiffuse(closestPrimitive, interPoint, thisScene);
 				 
 				 // Add the color to the colorBuffer
 				 colBuffer[arrayTracer + 0] = currentColor.r;
 				 colBuffer[arrayTracer + 1] = currentColor.g;
 				 colBuffer[arrayTracer + 2] = currentColor.b;
 				
 			}
 		}