refraction
updated demo.py and bunny.py to present new feature
python binding for material settings
--- 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;