replace Plane with axis-aligned Box (because infinite Plane is not usable with kd-tree)
fix memory leak in KdTree::nearest_intersection
rename BBox::R to BBox::H
new file: common.h (Eps and Inf constants)
--- a/Makefile Sat Nov 24 23:55:54 2007 +0100
+++ b/Makefile Sun Nov 25 15:50:01 2007 +0100
@@ -45,7 +45,7 @@
vector.o: src/vector.cc src/vector.h
matrix.o: src/matrix.cc src/matrix.h src/vector.h
noise.o: src/noise.cc src/noise.h
-scene.o: src/scene.cc src/scene.h src/vector.h src/noise.h
+scene.o: src/scene.cc src/scene.h src/vector.h src/noise.h src/common.h
kdtree.o: src/kdtree.cc src/kdtree.h
raytracer.o: src/raytracer.cc src/raytracer.h src/scene.h src/vector.h src/noise.h
--- a/README Sat Nov 24 23:55:54 2007 +0100
+++ b/README Sun Nov 25 15:50:01 2007 +0100
@@ -2,6 +2,11 @@
Pyrit Ray Tracer
==================
+License
+-------
+Currently unlicensed, you may not redistribute or use this work for any purposes.
+Will be MIT licensed when ready.
+
Pthreads
--------
Threads can be used to render rows of picture paralelly. Arbitrary number
--- a/TODO Sat Nov 24 23:55:54 2007 +0100
+++ b/TODO Sun Nov 25 15:50:01 2007 +0100
@@ -5,10 +5,10 @@
* update Python binding, new classes
* rename:
- Ray.a -> Ray.o or Ray.origin
- - BBox.R -> H
* C++ demos
* more complex demos
+
New Classes?
============
--- a/demos/demo.py Sat Nov 24 23:55:54 2007 +0100
+++ b/demos/demo.py Sun Nov 25 15:50:01 2007 +0100
@@ -3,7 +3,7 @@
import sys
sys.path.append("..")
-from raytracer import Raytracer, Material, Plane, Sphere, Light
+from raytracer import Raytracer, Material, Box, Sphere, Light
#, SphericalLight
import Image
@@ -17,8 +17,8 @@
rt.addlight(light2)
mat0 = Material(colour=(0.1, 0.2, 0.9))
-plane = Plane(normal=(0.0, 1.0, 0.0), d=1.0, material=mat0)
-rt.addshape(plane)
+box = Box(L=(-20.0, -1.2, -20.0), H=(20.0, -1.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)
@@ -42,4 +42,4 @@
rendersize = (800, 600)
data = rt.render(rendersize)
img = Image.fromstring("RGB", rendersize, data)
-img.save('out.png')
+img.save('demo.png')
--- a/demos/spheres_ao.py Sat Nov 24 23:55:54 2007 +0100
+++ b/demos/spheres_ao.py Sun Nov 25 15:50:01 2007 +0100
@@ -3,7 +3,7 @@
import sys
sys.path.append("..")
-from raytracer import Raytracer, Material, Plane, Sphere, Light
+from raytracer import Raytracer, Material, Box, Sphere, Light
import Image
rt = Raytracer()
@@ -19,8 +19,8 @@
mat0 = Material(colour=(0.7, 0.7, 0.7))
-plane = Plane(normal=(0.0, 1.0, 0.0), d=1.0, material=mat0)
-rt.addshape(plane)
+box = Box(L=(-20.0, -1.2, -20.0), H=(20.0, -1.0, 20.0), material=mat0)
+rt.addshape(box)
mat1 = Material(colour=(1.0, 0.0, 0.0))
bigsphere = Sphere(centre=(3.0, 2.0, 7.0), radius=3.0, material=mat1)
--- a/demos/spheres_shadow.py Sat Nov 24 23:55:54 2007 +0100
+++ b/demos/spheres_shadow.py Sun Nov 25 15:50:01 2007 +0100
@@ -3,7 +3,7 @@
import sys
sys.path.append("..")
-from raytracer import Raytracer, Material, Plane, Sphere, Light
+from raytracer import Raytracer, Material, Box, Sphere, Light
import Image
rt = Raytracer()
@@ -16,8 +16,8 @@
mat0 = Material(colour=(0.7, 0.7, 0.7))
-plane = Plane(normal=(0.0, 1.0, 0.0), d=1.0, material=mat0)
-rt.addshape(plane)
+box = Box(L=(-20.0, -1.2, -20.0), H=(20.0, -1.0, 20.0), material=mat0)
+rt.addshape(box)
mat1 = Material(colour=(1.0, 0.0, 0.0))
bigsphere = Sphere(centre=(3.0, 2.0, 7.0), radius=3.0, material=mat1)
--- a/src/kdtree.cc Sat Nov 24 23:55:54 2007 +0100
+++ b/src/kdtree.cc Sun Nov 25 15:50:01 2007 +0100
@@ -70,9 +70,9 @@
if (shapebb.L.x < bbox.L.x) bbox.L.x = shapebb.L.x;
if (shapebb.L.y < bbox.L.y) bbox.L.y = shapebb.L.y;
if (shapebb.L.z < bbox.L.z) bbox.L.z = shapebb.L.z;
- if (shapebb.R.x > bbox.R.x) bbox.R.x = shapebb.R.x;
- if (shapebb.R.y > bbox.R.y) bbox.R.y = shapebb.R.y;
- if (shapebb.R.z > bbox.R.z) bbox.R.z = shapebb.R.z;
+ if (shapebb.H.x > bbox.H.x) bbox.H.x = shapebb.H.x;
+ if (shapebb.H.y > bbox.H.y) bbox.H.y = shapebb.H.y;
+ if (shapebb.H.z > bbox.H.z) bbox.H.z = shapebb.H.z;
}
};
@@ -112,7 +112,7 @@
for (sh = sslist.begin(); sh != sslist.end(); sh++)
{
splitlist.push_back(SplitPos(sh->bbox.L.cell[axis]));
- splitlist.push_back(SplitPos(sh->bbox.R.cell[axis]));
+ splitlist.push_back(SplitPos(sh->bbox.H.cell[axis]));
}
sort(splitlist.begin(), splitlist.end());
// remove duplicate splits
@@ -131,9 +131,9 @@
continue;
}
// if shape is completely contained in split plane
- if (spl->pos == sh->bbox.L.cell[axis] == sh->bbox.R.cell[axis])
+ if (spl->pos == sh->bbox.L.cell[axis] == sh->bbox.H.cell[axis])
{
- if (spl->pos - bbox.L.cell[axis] < bbox.R.cell[axis] - spl->pos)
+ if (spl->pos - bbox.L.cell[axis] < bbox.H.cell[axis] - spl->pos)
{
// left subcell is smaller -> if not empty, put shape here
if (spl->lnum)
@@ -150,13 +150,13 @@
sh->setMark();
} else
// if shape is on left side of split plane
- if (sh->bbox.R.cell[axis] <= spl->pos)
+ if (sh->bbox.H.cell[axis] <= spl->pos)
{
spl->lnum++;
sh->setMark();
} else
// if shape occupies both sides of split plane
- if (sh->bbox.L.cell[axis] < spl->pos && sh->bbox.R.cell[axis] > spl->pos)
+ if (sh->bbox.L.cell[axis] < spl->pos && sh->bbox.H.cell[axis] > spl->pos)
{
spl->lnum++;
spl->rnum++;
@@ -181,7 +181,7 @@
for (spl = splitlist.begin(); spl != splitlist.end(); spl++)
{
// calculate SAH cost of this split
- lbb.R.cell[axis] = spl->pos;
+ lbb.H.cell[axis] = spl->pos;
rbb.L.cell[axis] = spl->pos;
float SAL = 2*(lbb.w()*lbb.h() + lbb.w()*lbb.d() + lbb.h()*lbb.d());
float SAR = 2*(rbb.w()*rbb.h() + rbb.w()*rbb.d() + rbb.h()*rbb.d());
@@ -209,12 +209,12 @@
v.cell[(axis+2)%3] = bbox.L.cell[(axis+2)%3];
F << "v " << v.x << " " << v.y << " " << v.z << endl;
v.cell[(axis+1)%3] = bbox.L.cell[(axis+1)%3];
- v.cell[(axis+2)%3] = bbox.R.cell[(axis+2)%3];
+ v.cell[(axis+2)%3] = bbox.H.cell[(axis+2)%3];
F << "v " << v.x << " " << v.y << " " << v.z << endl;
- v.cell[(axis+1)%3] = bbox.R.cell[(axis+1)%3];
- v.cell[(axis+2)%3] = bbox.R.cell[(axis+2)%3];
+ v.cell[(axis+1)%3] = bbox.H.cell[(axis+1)%3];
+ v.cell[(axis+2)%3] = bbox.H.cell[(axis+2)%3];
F << "v " << v.x << " " << v.y << " " << v.z << endl;
- v.cell[(axis+1)%3] = bbox.R.cell[(axis+1)%3];
+ v.cell[(axis+1)%3] = bbox.H.cell[(axis+1)%3];
v.cell[(axis+2)%3] = bbox.L.cell[(axis+2)%3];
F << "v " << v.x << " " << v.y << " " << v.z << endl;
F << "f " << f+1 << " " << f+2 << " " << f+3 << " " << f+4 << endl;
@@ -238,11 +238,11 @@
}
if (state == 0)
{
- if (sh->bbox.R.cell[axis] < split)
+ if (sh->bbox.H.cell[axis] < split)
{ // left
children[0].addShape(sh->shape);
} else
- if (sh->bbox.R.cell[axis] > split)
+ if (sh->bbox.H.cell[axis] > split)
{
if (sh->bbox.L.cell[axis] < split)
{ // both
@@ -254,13 +254,13 @@
state = 1;
}
} else
- { // R == split
+ { // H == split
if (sh->bbox.L.cell[axis] < split)
{ // left
children[0].addShape(sh->shape);
} else
{ // contained
- if (split - bbox.L.cell[axis] < bbox.R.cell[axis] - split)
+ if (split - bbox.L.cell[axis] < bbox.H.cell[axis] - split)
{
// left subcell is smaller -> if not empty, put shape here
if (lnum)
@@ -279,7 +279,7 @@
}
}
- lbb.R.cell[axis] = split;
+ lbb.H.cell[axis] = split;
rbb.L.cell[axis] = split;
children[0].subdivide(lbb, depth+1);
@@ -406,6 +406,7 @@
}
/* pop from the stack */
+ delete enPt;
enPt = exPt; /* the signed distance intervals are adjacent */
/* retrieve the pointer to the next node, it is possible that ray traversal terminates */
@@ -416,6 +417,8 @@
st.pop();
} /* while */
+ delete enPt;
+
/* ray leaves the scene */
return NULL;
}
--- a/src/raytracer.cc Sat Nov 24 23:55:54 2007 +0100
+++ b/src/raytracer.cc Sun Nov 25 15:50:01 2007 +0100
@@ -11,7 +11,7 @@
#include <stdio.h>
#include <malloc.h>
-#include <float.h>
+#include "common.h"
#include "raytracer.h"
// Hammersley spherical point distribution
--- a/src/raytracermodule.cc Sat Nov 24 23:55:54 2007 +0100
+++ b/src/raytracermodule.cc Sun Nov 25 15:50:01 2007 +0100
@@ -224,27 +224,27 @@
return Py_FindMethod(SphereMethods, self, name);
}
-//=========================== Plane Object ===========================
+//=========================== Box Object ===========================
typedef struct {
PyObject_HEAD
- Plane *shape;
-} PlaneObject;
+ Box *shape;
+} BoxObject;
-static PyObject *Plane_Constructor(PyObject* self, PyObject* args, PyObject *kwd);
-static void Plane_Destructor(PyObject* self);
-static PyObject *Plane_Getattr(PyObject *self, char *name);
+static PyObject *Box_Constructor(PyObject* self, PyObject* args, PyObject *kwd);
+static void Box_Destructor(PyObject* self);
+static PyObject *Box_Getattr(PyObject *self, char *name);
-static PyTypeObject PlaneType = {
+static PyTypeObject BoxType = {
PyObject_HEAD_INIT(NULL)
0, /*ob_size*/
- "Plane", /*tp_name*/
- sizeof(PlaneObject), /*tp_basicsize*/
+ "Box", /*tp_name*/
+ sizeof(BoxObject), /*tp_basicsize*/
0, /*tp_itemsize*/
/* methods */
- Plane_Destructor, /*tp_dealloc*/
+ Box_Destructor, /*tp_dealloc*/
0, /*tp_print*/
- Plane_Getattr, /*tp_getattr*/
+ Box_Getattr, /*tp_getattr*/
0, /*tp_setattr*/
0, /*tp_compare*/
0, /*tp_repr*/
@@ -254,40 +254,44 @@
0, /*tp_hash */
};
-static PyMethodDef PlaneMethods[] = {
+static PyMethodDef BoxMethods[] = {
{NULL, NULL}
};
-static PyObject* Plane_Constructor(PyObject* self, PyObject* args, PyObject *kwd)
+static PyObject* Box_Constructor(PyObject* self, PyObject* args, PyObject *kwd)
{
- PlaneObject *v;
+ BoxObject *v;
MaterialObject *material;
- static char *kwdlist[] = {"normal", "d", "material", NULL};
- PyObject *TNorm = NULL;
- float nx, ny, nz, d;
+ static char *kwdlist[] = {"L", "H", "material", NULL};
+ PyObject *TL = NULL;
+ PyObject *TH = NULL;
+ float lx, ly, lz, hx, hy, hz;
- if (!PyArg_ParseTupleAndKeywords(args, kwd, "O!fO!", kwdlist,
- &PyTuple_Type, &TNorm, &d, &MaterialType, &material))
+ if (!PyArg_ParseTupleAndKeywords(args, kwd, "O!O!O!", kwdlist,
+ &PyTuple_Type, &TL, &PyTuple_Type, &TH, &MaterialType, &material))
return NULL;
- if (!PyArg_ParseTuple(TNorm, "fff", &nx, &ny, &nz))
+ if (!PyArg_ParseTuple(TL, "fff", &lx, &ly, &lz))
return NULL;
- v = PyObject_New(PlaneObject, &PlaneType);
- v->shape = new Plane(Vector3(nx, ny, nz), d, material->material);
+ if (!PyArg_ParseTuple(TH, "fff", &hx, &hy, &hz))
+ return NULL;
+
+ v = PyObject_New(BoxObject, &BoxType);
+ v->shape = new Box(Vector3(lx, ly, lz), Vector3(hx, hy, hz), material->material);
Py_INCREF(material);
return (PyObject*)v;
}
-static void Plane_Destructor(PyObject* self)
+static void Box_Destructor(PyObject* self)
{
- delete ((PlaneObject *)self)->shape;
+ delete ((BoxObject *)self)->shape;
PyObject_Del(self);
}
-static PyObject *Plane_Getattr(PyObject *self, char *name)
+static PyObject *Box_Getattr(PyObject *self, char *name)
{
- return Py_FindMethod(PlaneMethods, self, name);
+ return Py_FindMethod(BoxMethods, self, name);
}
//=========================== Triangle Object ===========================
@@ -479,7 +483,7 @@
return NULL;
((RaytracerObject *)self)->raytracer->addshape(
- ((PlaneObject*)obj)->shape);
+ ((BoxObject*)obj)->shape);
((RaytracerObject *)self)->children->push_back(obj);
Py_INCREF(obj);
@@ -526,8 +530,8 @@
METH_VARARGS | METH_KEYWORDS, "Material object constructor."},
{"Sphere", (PyCFunction) Sphere_Constructor,
METH_VARARGS | METH_KEYWORDS, "Sphere object constructor."},
- {"Plane", (PyCFunction) Plane_Constructor,
- METH_VARARGS | METH_KEYWORDS, "Plane object constructor."},
+ {"Box", (PyCFunction) Box_Constructor,
+ METH_VARARGS | METH_KEYWORDS, "Box object constructor."},
{"Triangle", (PyCFunction) Triangle_Constructor,
METH_VARARGS | METH_KEYWORDS, "Triangle object constructor."},
{NULL, NULL}
--- a/src/scene.cc Sat Nov 24 23:55:54 2007 +0100
+++ b/src/scene.cc Sun Nov 25 15:50:01 2007 +0100
@@ -6,8 +6,8 @@
*/
#include <math.h>
-#include <float.h>
+#include "common.h"
#include "scene.h"
/* http://www.siggraph.org/education/materials/HyperGraph/raytrace/rtinter3.htm */
@@ -21,13 +21,13 @@
{
if (ray.dir.cell[i] == 0) {
/* ray is parallel to these planes */
- if (ray.a.cell[i] < L.cell[i] || ray.a.cell[i] > R.cell[i])
+ if (ray.a.cell[i] < L.cell[i] || ray.a.cell[i] > H.cell[i])
return false;
} else
{
/* compute the intersection distance of the planes */
t1 = (L.cell[i] - ray.a.cell[i]) / ray.dir.cell[i];
- t2 = (R.cell[i] - ray.a.cell[i]) / ray.dir.cell[i];
+ t2 = (H.cell[i] - ray.a.cell[i]) / ray.dir.cell[i];
if (t1 > t2)
swap(t1, t2);
@@ -114,32 +114,40 @@
BBox Sphere::get_bbox()
{
BBox bbox = BBox();
- bbox.L.x = center.x - radius;
- bbox.L.y = center.y - radius;
- bbox.L.z = center.z - radius;
- bbox.R.x = center.x + radius;
- bbox.R.y = center.y + radius;
- bbox.R.z = center.z + radius;
+ bbox.L = center - radius;
+ //bbox.L.y = center.y - radius;
+ //bbox.L.z = center.z - radius;
+ bbox.H = center + radius;
+ //bbox.H.y = center.y + radius;
+ //bbox.H.z = center.z + radius;
return bbox;
}
-bool Plane::intersect(const Ray &ray, float &dist)
+bool Box::intersect(const Ray &ray, float &dist)
{
- float dir = dot(N, ray.dir);
- if (dir != 0)
- {
- float newdist = -(dot(N, ray.a) + d) / dir;
- if (newdist > 0 && newdist < dist) {
- dist = newdist;
- return true;
- }
- }
- return false;
+ float b;
+ return get_bbox().intersect(ray, dist, b);
}
-BBox Plane::get_bbox()
+Vector3 Box::normal(Vector3 &P)
{
- return BBox();
+ Vector3 N(0,1,0);
+ /*for (int i = 0; i < 3; i++)
+ {
+ if (P.cell[i] >= L.cell[i]-Eps && P.cell[i] <= L.cell[i]+Eps)
+ //if (P.cell[i] == L.cell[i])
+ {
+ N.cell[i] = -1.0;
+ break;
+ }
+ if (P.cell[i] >= H.cell[i]-Eps && P.cell[i] <= H.cell[i]+Eps)
+ //if (P.cell[i] == H.cell[i])
+ {
+ N.cell[i] = +1.0;
+ break;
+ }
+ }*/
+ return N;
}
// this initialization and following intersection methods implements
@@ -233,12 +241,12 @@
if (C.y < bbox.L.y) bbox.L.y = C.y;
if (B.z < bbox.L.z) bbox.L.z = B.z;
if (C.z < bbox.L.z) bbox.L.z = C.z;
- bbox.R = A;
- if (B.x > bbox.R.x) bbox.R.x = B.x;
- if (C.x > bbox.R.x) bbox.R.x = C.x;
- if (B.y > bbox.R.y) bbox.R.y = B.y;
- if (C.y > bbox.R.y) bbox.R.y = C.y;
- if (B.z > bbox.R.z) bbox.R.z = B.z;
- if (C.z > bbox.R.z) bbox.R.z = C.z;
+ bbox.H = A;
+ if (B.x > bbox.H.x) bbox.H.x = B.x;
+ if (C.x > bbox.H.x) bbox.H.x = C.x;
+ if (B.y > bbox.H.y) bbox.H.y = B.y;
+ if (C.y > bbox.H.y) bbox.H.y = C.y;
+ if (B.z > bbox.H.z) bbox.H.z = B.z;
+ if (C.z > bbox.H.z) bbox.H.z = C.z;
return bbox;
};
--- a/src/scene.h Sat Nov 24 23:55:54 2007 +0100
+++ b/src/scene.h Sun Nov 25 15:50:01 2007 +0100
@@ -29,11 +29,12 @@
{
public:
Vector3 L;
- Vector3 R;
- BBox(): L(), R() {};
- float w() { return R.x-L.x; };
- float h() { return R.y-L.y; };
- float d() { return R.z-L.z; };
+ Vector3 H;
+ BBox(): L(), H() {};
+ BBox(const Vector3 aL, const Vector3 aH): L(aL), H(aH) {};
+ float w() { return H.x-L.x; };
+ float h() { return H.y-L.y; };
+ float d() { return H.z-L.z; };
bool intersect(const Ray &ray, float &a, float &b);
};
@@ -118,20 +119,22 @@
BBox get_bbox();
};
-class Plane: public Shape
+class Box: public Shape
{
+ Vector3 L;
+ Vector3 H;
public:
- Vector3 N;
- float d;
-
- Plane(const Vector3 &normal, const float ad, Material *amaterial):
- N(normal), d(ad) { material = amaterial; };
- Plane(const Vector3 &normal, const Vector3 &point):
- N(normal), d(0) { /*TODO*/};
+ Box(const Vector3 &aL, const Vector3 &aH, Material *amaterial): L(aL), H(aH)
+ {
+ for (int i = 0; i < 3; i++)
+ if (L.cell[i] > H.cell[i])
+ swap(L.cell[i], H.cell[i]);
+ material = amaterial;
+ };
bool intersect(const Ray &ray, float &dist);
bool intersect_all(const Ray &ray, float dist, vector<float> &allts) {return false;};
- Vector3 normal(Vector3 &) { return N; };
- BBox get_bbox();
+ Vector3 normal(Vector3 &P);
+ BBox get_bbox() { return BBox(L, H); };
};
class Triangle: public Shape
--- a/src/vector.h Sat Nov 24 23:55:54 2007 +0100
+++ b/src/vector.h Sun Nov 25 15:50:01 2007 +0100
@@ -99,11 +99,23 @@
return Vector3(f * v.x, f * v.y, f * v.z);
}
- friend Vector3 operator*(const float &f, Vector3 &v)
+ friend Vector3 operator*(const float &f, const Vector3 &v)
{
return v * f;
};
+ // vector plus scalar
+ friend Vector3 operator+(const Vector3 &v, const float &f)
+ {
+ return Vector3(v.x + f, v.y + f, v.z + f);
+ }
+
+ // vector minus scalar
+ friend Vector3 operator-(const Vector3 &v, const float &f)
+ {
+ return Vector3(v.x - f, v.y - f, v.z - f);
+ }
+
// cell by cell product (only usable for colours)
friend Vector3 operator*(const Vector3 &a, const Vector3 &b)
{