refraction pyrit
authorRadek Brich <radek.brich@devl.cz>
Sun, 09 Dec 2007 10:45:26 +0100
branchpyrit
changeset 31 b4e09433934a
parent 30 33f95441790e
child 32 8af5c17d368b
refraction updated demo.py and bunny.py to present new feature python binding for material settings
TODO
demos/bunny.py
demos/demo.py
include/raytracer.h
include/scene.h
src/raytracer.cc
src/raytracermodule.cc
src/scene.cc
--- a/TODO	Sat Dec 08 16:02:37 2007 +0100
+++ b/TODO	Sun Dec 09 10:45:26 2007 +0100
@@ -1,11 +1,17 @@
+Bugs
+====
+ * concurrent read? (concurrent write should not occur)
+
+Future Plans
+============
  * kd-tree:
    - optimize structures
    - optimize construction: do not use bounding boxes of shapes, instead implement box-shape intersection
    - save/load
+ * uniform grid, octree
+ * textures (3D procedural, pixmaps later)
  * update Python binding: Camera, new classes
- * more complex demos
  * namespace
- * refractions, glass
 
 New Classes?
 ============
--- a/demos/bunny.py	Sat Dec 08 16:02:37 2007 +0100
+++ b/demos/bunny.py	Sun Dec 09 10:45:26 2007 +0100
@@ -6,19 +6,31 @@
 import sys
 sys.path.append(open('ModulePath').read().strip())
 
-from raytracer import Raytracer, Light, Sphere, Triangle, NormalVertex, Material
+from raytracer import Raytracer, Light, Box, Triangle, NormalVertex, Material
 from plyreader import LoadStanfordPlyFile
 import Image
 
 rt = Raytracer()
+#rt.ambientocclusion(samples=100, distance=16.0, angle=0.5)
+
 mat = Material(colour=(0.9, 0.9, 0.9))
+mat.setTransmissivity(0.8)
 LoadStanfordPlyFile(rt, "../models/bunny/bun_zipper.ply",
-	mat, smooth=True, scale=(-29.0, 29.0, 29.0), trans=(-1,-3,-3))
+	mat, smooth=True, scale=(-29.0, 29.0, 29.0), trans=(-1,-2.5,-3))
+
+mat0 = Material(colour=(0.1, 0.2, 0.9))
+box1 = Box(L=(-20.0, -1.7, -20.0), H=(20.0, -1.5, 20.0), material=mat0)
+rt.addshape(box1)
 
-light = Light(position=(-5.0, 2.0, 10.0), colour=(0.9, 0.3, 0.6))
+mat1 = Material(colour=(0.2, 0.8, 0.4))
+mat1.setReflectivity(0.0)
+box2 = Box(L=(-20.0, -20.0, -10.0), H=(20.0, 20.0, -12.0), material=mat1)
+rt.addshape(box2)
+
+light = Light(position=(-5.0, 3.0, 10.0), colour=(0.9, 0.3, 0.6))
 rt.addlight(light)
 
-light2 = Light(position=(4.0, -3.0, 10.0), colour=(0.2, 0.9, 0.5))
+light2 = Light(position=(4.0, 1.0, 10.0), colour=(0.2, 0.9, 0.5))
 rt.addlight(light2)
 
 imagesize = (800, 600)
--- a/demos/demo.py	Sat Dec 08 16:02:37 2007 +0100
+++ b/demos/demo.py	Sun Dec 09 10:45:26 2007 +0100
@@ -9,35 +9,38 @@
 
 rt = Raytracer()
 
-light1 = Light(position=(0.0, 5.0, -3.0), colour=(0.9, 0.3, 0.6))
+light1 = Light(position=(0.0, 4.0, -3.0), colour=(0.9, 0.3, 0.6))
 rt.addlight(light1)
 
 #light2 = SphericalLight(position=(-2.0, 5.0, 1.0), radius=3.0, colour=(0.7, 1.0, 0.3))
-light2 = Light(position=(-2.0, -5.0, -1.0), colour=(0.7, 1.0, 0.3))
+light2 = Light(position=(-2.0, -4.0, -1.0), colour=(0.7, 1.0, 0.3))
+rt.addlight(light2)
+
+light2 = Light(position=(2.0, 5.0, 1.0), colour=(0.8, 0.9, 1.0))
 rt.addlight(light2)
 
 mat0 = Material(colour=(0.1, 0.2, 0.9))
-box = Box(L=(-20.0, -1.2, -20.0), H=(20.0, -1.0, 20.0), material=mat0)
+box = Box(L=(-20.0, -2.2, -20.0), H=(20.0, -2.0, 20.0), material=mat0)
 rt.addshape(box)
 
 mat1 = Material(colour=(1.0, 0.2, 0.1))
-bigsphere = Sphere(centre=(2.0, 2.0, -5.0), radius=2.5, material=mat1)
+mat1.setReflectivity(0.7)
+bigsphere = Sphere(centre=(2.0, 1.0, -5.0), radius=2.5, material=mat1)
 #      reflection=0.6)
 rt.addshape(bigsphere)
 
 mat2 = Material(colour=(0.1, 0.7, 1.0))
-smallsphere = Sphere(centre=(-5.5, 1.5, -8.0), radius=2.0, material=mat2)
+smallsphere = Sphere(centre=(-5.5, 0.5, -8.0), radius=2.0, material=mat2)
 #      reflection=1.0, diffuse=0.1)
 rt.addshape(smallsphere)
 
-mat3 = Material(colour=(0.9, 0.9, 0.1))
-tinysphere = Sphere(centre=(-0.5, 0.0, -2.0), radius=0.5, material=mat3)
-#      reflection=1.0, diffuse=0.1)
-rt.addshape(tinysphere)
-
-#for i in range(100):
-#      sph=Sphere((-5.5+i/10.0, -0.5, 7.0), 2.0)
-#      rt.addshape(sph)
+mat3 = Material(colour=(0.9, 0.9, 1.0))
+mat3.setPhong(0.2, 1.0, 0.2)
+mat3.setTransmissivity(0.9)
+mat3.setReflectivity(0.0)
+for i in range(10):
+	sph = Sphere(centre=(-5.0+i, -1.5, -4.0), radius=0.5, material=mat3)
+	rt.addshape(sph)
 
 rendersize = (800, 600)
 data = rt.render(rendersize)
--- a/include/raytracer.h	Sat Dec 08 16:02:37 2007 +0100
+++ b/include/raytracer.h	Sun Dec 09 10:45:26 2007 +0100
@@ -39,7 +39,7 @@
 	Vector3 SphereDistribute(int i, int n, Float extent, Vector3 &normal);
 public:
 	Raytracer(): top(NULL), camera(NULL), lights(), bg_colour(0.0, 0.0, 0.0),
-		ao_samples(0), num_threads(4), subsample(8), max_depth(4) {};
+		ao_samples(0), num_threads(2), subsample(8), max_depth(3) {};
 	void render(int w, int h, Float *buffer);
 	Colour raytrace(Ray &ray, int depth, Shape *origin_shape);
 	void addshape(Shape *shape) { top->addShape(shape); };
--- a/include/scene.h	Sat Dec 08 16:02:37 2007 +0100
+++ b/include/scene.h	Sun Dec 09 10:45:26 2007 +0100
@@ -128,19 +128,26 @@
 {
 public:
 	Float ambient, diffuse, specular, shininess; // Phong constants
-	Float reflection; // how much reflectife is the surface
-	Float refraction; // refraction index
-	Float transmitivity;
+	Float reflectivity; // how much reflective is the surface
+	Float transmissivity, refract_index; // part of light which can be refracted; index of refraction
 	Texture texture;
 
 	Material(const Colour &acolour) {
 		texture.colour = acolour;
-		ambient = 0.1;
-		diffuse = 0.5;
-		specular = 0.1;
+		ambient = 0.2;
+		diffuse = 0.8;
+		specular = 0.2;
 		shininess = 0.5;
-		reflection = 0.5;
+		reflectivity = 0.2;
+		transmissivity = 0.0;
+		refract_index = 1.3;
 	}
+
+	void setPhong(const Float amb, const Float dif, const Float spec, const Float shin)
+		{ ambient = amb; diffuse = dif; specular = spec; shininess = shin; };
+	void setReflectivity(const Float refl) { reflectivity = refl; };
+	void setTransmissivity(const Float trans, const Float rindex)
+		{ transmissivity = trans; refract_index = rindex; };
 };
 
 class Shape
--- 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;
 	}
 }
 
--- a/src/raytracermodule.cc	Sat Dec 08 16:02:37 2007 +0100
+++ b/src/raytracermodule.cc	Sun Dec 09 10:45:26 2007 +0100
@@ -104,6 +104,9 @@
 static PyObject *Material_Constructor(PyObject* self, PyObject* args, PyObject *kwd);
 static void Material_Destructor(PyObject* self);
 static PyObject *Material_Getattr(PyObject *self, char *name);
+static PyObject *Material_setPhong(PyObject* self, PyObject* args);
+static PyObject *Material_setReflectivity(PyObject* self, PyObject* args);
+static PyObject *Material_setTransmissivity(PyObject* self, PyObject* args);
 
 static PyTypeObject MaterialType = {
 	PyObject_HEAD_INIT(NULL)
@@ -125,6 +128,9 @@
 };
 
 static PyMethodDef MaterialMethods[] = {
+	{"setPhong", (PyCFunction)Material_setPhong, METH_VARARGS, "Set ambient, diffuse, specular and shininess Phong model constants."},
+	{"setReflectivity", (PyCFunction)Material_setReflectivity, METH_VARARGS, "Set reflectivity."},
+	{"setTransmissivity", (PyCFunction)Material_setTransmissivity, METH_VARARGS, "Set transmissivity and refraction index."},
 	{NULL, NULL}
 };
 
@@ -159,6 +165,45 @@
 	return Py_FindMethod(MaterialMethods, self, name);
 }
 
+static PyObject *Material_setPhong(PyObject* self, PyObject* args)
+{
+	Float amb, dif, spec, shin = 0.5;
+
+	if (!PyArg_ParseTuple(args, "fff|f", &amb, &dif, &spec, &shin))
+		return NULL;
+
+	((MaterialObject *)self)->material->setPhong(amb, dif, spec, shin);
+
+	Py_INCREF(Py_None);
+	return Py_None;
+}
+
+static PyObject *Material_setReflectivity(PyObject* self, PyObject* args)
+{
+	Float refl;
+
+	if (!PyArg_ParseTuple(args, "f", &refl))
+		return NULL;
+
+	((MaterialObject *)self)->material->setReflectivity(refl);
+
+	Py_INCREF(Py_None);
+	return Py_None;
+}
+
+static PyObject *Material_setTransmissivity(PyObject* self, PyObject* args)
+{
+	Float trans, rindex = 1.3;
+
+	if (!PyArg_ParseTuple(args, "f|f", &trans, &rindex))
+		return NULL;
+
+	((MaterialObject *)self)->material->setTransmissivity(trans, rindex);
+
+	Py_INCREF(Py_None);
+	return Py_None;
+}
+
 //=========================== NormalVertex Object ===========================
 
 typedef struct {
@@ -555,7 +600,7 @@
 	if (!PyArg_ParseTuple(args, "(ii)", &w, &h))
 		return NULL;
 
-	printf("[pyrit] Raytracing...\n");
+	printf("[pyrit] Running ray tracer\n");
 	((RaytracerObject *)self)->raytracer->getTop()->optimize();
 	data = (Float *) malloc(w*h*3*sizeof(Float));
 	((RaytracerObject *)self)->raytracer->render(w, h, data);
@@ -565,7 +610,7 @@
 	}
 
 	// convert data to char
-	printf("[pyrit] Converting image data (float to char)...\n");
+	printf("[pyrit] Converting image data (float to char)\n");
 	chardata = (char *) malloc(w*h*3);
 	Float *d = data;
 	for (char *c = chardata; c != chardata + w*h*3; c++, d++) {
--- a/src/scene.cc	Sat Dec 08 16:02:37 2007 +0100
+++ b/src/scene.cc	Sun Dec 09 10:45:26 2007 +0100
@@ -207,7 +207,6 @@
 	: smooth(false), A(aA), B(aB), C(aC)
 {
 	material = amaterial;
-	material->reflection = 0;
 
 	const Vector3 c = B->P - A->P;
 	const Vector3 b = C->P - A->P;