src/raytracer.cc
branchpyrit
changeset 31 b4e09433934a
parent 30 33f95441790e
child 32 8af5c17d368b
--- a/src/raytracer.cc	Sat Dec 08 16:02:37 2007 +0100
+++ b/src/raytracer.cc	Sun Dec 09 10:45:26 2007 +0100
@@ -99,13 +99,19 @@
 	if (nearest_shape == NULL) {
 		return bg_colour;
 	} else {
-		Colour acc = Colour();
+		Colour col = Colour();
 		Vector3 P = ray.o + ray.dir * nearest_distance; // point of intersection
 		Vector3 normal = nearest_shape->normal(P);
+		bool from_inside = false;
+
 		// make shapes double sided
 		if (dot(normal, ray.dir) > 0.0)
+		{
 			normal = - normal;
-		acc = PhongShader_ambient(*nearest_shape->material, P);
+			from_inside = true;
+		}
+
+		col = PhongShader_ambient(*nearest_shape->material, P);
 
 		vector<Light*>::iterator light;
 		for (light = lights.begin(); light != lights.end(); light++) {
@@ -123,22 +129,66 @@
 
 				// shading function
 				Vector3 R = L - 2.0 * L_dot_N * normal;
-				acc += PhongShader_calculate(*nearest_shape->material,
+				col += PhongShader_calculate(*nearest_shape->material,
 					P, normal, R, ray.dir, **light);
 			}
 		}
 
-		// reflection
-		Vector3 newdir = ray.dir - 2.0 * dot(ray.dir, normal) * normal;
-		if (depth < max_depth && nearest_shape->material->reflection > 0.01) {
-			Ray newray = Ray(P, newdir);
-			Colour refl_col = raytrace(newray, depth + 1, nearest_shape);
-			acc += nearest_shape->material->reflection * refl_col;
+		if (depth < max_depth)
+		{
+			Colour trans_col, refl_col;
+			Float trans = nearest_shape->material->transmissivity;
+			Float refl = nearest_shape->material->reflectivity;
+			const Float cos_i = - dot(normal, ray.dir);
+
+			// reflection
+			if (refl > 0.01)
+			{
+				Vector3 newdir = ray.dir + 2.0 * cos_i * normal;
+				Ray newray = Ray(P, newdir);
+				refl_col = raytrace(newray, depth + 1, nearest_shape);
+			}
+
+			// refraction
+		 	if (trans > 0.01)
+			{
+				Float n, n1, n2;
+				if (from_inside)
+				{
+					n1 = nearest_shape->material->refract_index;
+					n2 = 1.0;
+					n = n1;
+				}
+				else
+				{
+					n1 = 1.0;
+					n2 = nearest_shape->material->refract_index;
+					n = 1.0 / n2;
+				}
+				const Float sin2_t = n*n * (1 - cos_i*cos_i);
+				if (sin2_t >= 1.0)
+				{
+					 // totally reflected
+					 refl += trans;
+					 trans = 0;
+				}
+				else
+				{
+					const Float cos_t = sqrtf(1 - sin2_t);
+					const Float Rdiv = 1.0/(n1*cos_i + n2*cos_t);
+					const Float Rper = (n1*cos_i - n2*cos_t)*Rdiv;
+					const Float Rpar = (n2*cos_i - n1*cos_t)*Rdiv;
+					const Float R = (Rper*Rper + Rpar*Rpar)/2;
+					refl += R*trans;
+					trans = (1-R)*trans;
+					Vector3 newdir = n * ray.dir + (n*cos_i - cos_t) * normal;
+					Ray newray = Ray(P, newdir);
+					trans_col = raytrace(newray, depth + 1, nearest_shape);
+				}
+			}
+			col = (1-refl-trans)*col + refl*refl_col + trans*trans_col;
 		}
 
-		// refraction
-		/* ... */
-
 		// ambient occlusion
 		if (ao_samples)
 		{
@@ -154,10 +204,10 @@
 					miss += dist / ao_distance;
 			}
 			Float ao_intensity = miss / ao_samples;
-			acc = acc * ao_intensity;
+			col = col * ao_intensity;
 		}
 
-		return acc;
+		return col;
 	}
 }