new virtual Shape::intersect_bbox pyrit
authorRadek Brich <radek.brich@devl.cz>
Thu, 13 Dec 2007 00:08:11 +0100
branchpyrit
changeset 36 b490093b0ac3
parent 35 fb170fccb19f
child 37 5f954c0d34fc
new virtual Shape::intersect_bbox implementation of triangle-AABB intersection octree building updated and simplified with help of this new method octree made default for Python, it's currently much faster than kd-tree (both building and traversal)
ccdemos/realtime_bunny.cc
ccdemos/realtime_dragon.cc
include/octree.h
include/scene.h
src/octree.cc
src/raytracermodule.cc
src/scene.cc
--- a/ccdemos/realtime_bunny.cc	Wed Dec 12 19:59:19 2007 +0100
+++ b/ccdemos/realtime_bunny.cc	Thu Dec 13 00:08:11 2007 +0100
@@ -30,7 +30,6 @@
 	while (token != "end_header")
 	{
 		f >> token;
-		cout << token << endl;
 		if (token == "element")
 		{
 			f >> token;
@@ -146,7 +145,7 @@
 	render_buffer = (Float *) malloc(w*h*3*sizeof(Float));
 
 	rt.setThreads(2);
-	rt.setMaxDepth(3);
+	rt.setMaxDepth(0);
 
 	Octree top;
 	rt.setTop(&top);
@@ -160,13 +159,13 @@
 	//rt.addlight(&light2);
 
 	Material mat(Colour(0.9, 0.9, 0.9));
-	load_ply("../models/bunny/bun_zipper_res4.ply", &mat, 29);
+	load_ply("../models/bunny/bun_zipper.ply", &mat, 29);
 
 	rt.setCamera(&cam);
 	cam.setEye(Vector3(0,0,10));
 
 	/* build kd-tree */
-	top.setMaxDepth(3);
+	top.setMaxDepth(8);
 	top.optimize();
 
 	/* loop... */
--- a/ccdemos/realtime_dragon.cc	Wed Dec 12 19:59:19 2007 +0100
+++ b/ccdemos/realtime_dragon.cc	Thu Dec 13 00:08:11 2007 +0100
@@ -143,7 +143,7 @@
 	rt.setThreads(1);
 	rt.setMaxDepth(3);
 
-	Kdtree top;
+	KdTree top;
 	rt.setTop(&top);
 
 	Light light1(Vector3(-5.0, 2.0, 8.0), Colour(0.9, 0.3, 0.6));
--- a/include/octree.h	Wed Dec 12 19:59:19 2007 +0100
+++ b/include/octree.h	Thu Dec 13 00:08:11 2007 +0100
@@ -38,7 +38,7 @@
 	bool built;
 	int max_depth;
 public:
-	Octree() : Container(), root(NULL), built(false), max_depth(4) {};
+	Octree() : Container(), root(NULL), built(false), max_depth(10) {};
 	~Octree() { if (root) delete root; };
 	void addShape(Shape* aShape) { Container::addShape(aShape); built = false; };
 	Shape *nearest_intersection(const Shape *origin_shape, const Ray &ray,
--- a/include/scene.h	Wed Dec 12 19:59:19 2007 +0100
+++ b/include/scene.h	Thu Dec 13 00:08:11 2007 +0100
@@ -130,6 +130,9 @@
 	// all intersections (only for CSG)
 	virtual bool intersect_all(const Ray &ray, Float dist, vector<Float> &allts) const = 0;
 
+	// intersection with AABB
+	virtual bool intersect_bbox(const BBox &bbox) const = 0;
+
 	// normal at point P
 	virtual const Vector3 normal(const Vector3 &P) const = 0;
 
@@ -153,6 +156,7 @@
 		center(acenter), radius(aradius) { material = amaterial; }
 	bool intersect(const Ray &ray, Float &dist) const;
 	bool intersect_all(const Ray &ray, Float dist, vector<Float> &allts) const;
+	bool intersect_bbox(const BBox &bbox) const { return true; };
 	const Vector3 normal(const Vector3 &P) const { return (P - center) * inv_radius; };
 	BBox get_bbox() const;
 };
@@ -171,6 +175,7 @@
 	};
 	bool intersect(const Ray &ray, Float &dist) const;
 	bool intersect_all(const Ray &ray, Float dist, vector<Float> &allts) const { return false; };
+	bool intersect_bbox(const BBox &bbox) const { return true; };
 	const Vector3 normal(const Vector3 &P) const;
 	BBox get_bbox() const { return BBox(L, H); };
 };
@@ -235,6 +240,7 @@
 	Triangle(Vertex *aA, Vertex *aB, Vertex *aC, Material *amaterial);
 	bool intersect(const Ray &ray, Float &dist) const;
 	bool intersect_all(const Ray &ray, Float dist, vector<Float> &allts) const {return false;};
+	bool intersect_bbox(const BBox &bbox) const;
 	const Vector3 normal(const Vector3 &P) const { return (smooth ? smooth_normal(P) : N); };
 	const Vector3 getNormal() const { return N; };
 	void setSmooth() { smooth = true; };//(typeid(*A) == typeid(*B) == typeid(*C) == typeid(NormalVertex)); };
--- a/src/octree.cc	Wed Dec 12 19:59:19 2007 +0100
+++ b/src/octree.cc	Thu Dec 13 00:08:11 2007 +0100
@@ -44,71 +44,15 @@
 
 	// distribute shapes to children
 	ShapeList::iterator sh;
-	BBox shbb;
-	int child, both;
 	unsigned int shapenum = 0;
 	for (sh = shapes->begin(); sh != shapes->end(); sh++)
 	{
-		child = 0;
-		both = 0;
-		shbb = (*sh)->get_bbox();
-
-		if (shbb.L.x >= xsplit)
-			child |= 4; //right
-		else if (shbb.H.x > xsplit)
-			both |= 4; // both
-		// for left, do nothing
-
-		if (shbb.L.y >= ysplit)
-			child |= 2;
-		else if (shbb.H.y > ysplit)
-			both |= 2;
-
-		if (shbb.L.z >= zsplit)
-			child |= 1;
-		else if (shbb.H.z > zsplit)
-			both |= 1;
-
-		if (!both)
-		{
-			getChild(child)->addShape(*sh);
-			shapenum++;
-		}
-		else
-		{
-			// shape goes to more than one child
-			if (both == 7)
+		for (int i = 0; i < 8; i++)
+			if ((*sh)->intersect_bbox(childbb[i]))
 			{
-				for (int i = 0; i < 8; i++)
-					getChild(i)->addShape(*sh);
-				shapenum += 8;
+				getChild(i)->addShape(*sh);
+				shapenum++;
 			}
-			else if (both == 3 || both >= 5)
-			{
-				if (both == 3)
-				{
-					for (int i = 0; i < 4; i++)
-						getChild(child + i)->addShape(*sh);
-				}
-				else if (both == 5)
-				{
-					for (int i = 0; i < 4; i++)
-						getChild(child + i+(i>>1<<1))->addShape(*sh);
-				}
-				else if (both == 6)
-				{
-					for (int i = 0; i < 4; i++)
-						getChild(child + (i<<1))->addShape(*sh);
-				}
-				shapenum += 4;
-			}
-			else
-			{
-				getChild(child)->addShape(*sh);
-				getChild(child+both)->addShape(*sh);
-				shapenum += 2;
-			}
-		}
 	}
 
 	if (shapes->size() <= 8 && shapenum > 2*shapes->size())
@@ -316,7 +260,6 @@
 	Float tz0 = (bbox.L.z - ro.z) / rdir.z;
 	Float tz1 = (bbox.H.z - ro.z) / rdir.z;
 
-	//Octree *node = root;
 	if (max(max(tx0,ty0),tz0) < min (min(tx1,ty1),tz1))
 		return proc_subtree(a,tx0,ty0,tz0,tx1,ty1,tz1,root,
 			origin_shape, ray, nearest_distance);
--- a/src/raytracermodule.cc	Wed Dec 12 19:59:19 2007 +0100
+++ b/src/raytracermodule.cc	Thu Dec 13 00:08:11 2007 +0100
@@ -11,7 +11,7 @@
 #include <vector>
 #include "raytracer.h"
 #include "scene.h"
-#include "kdtree.h"
+#include "octree.h"
 
 //=========================== Light Source Object ===========================
 
@@ -571,7 +571,7 @@
 	v->raytracer = new Raytracer();
 	v->children = new vector<PyObject*>();
 	v->raytracer->setCamera(new Camera());
-	v->raytracer->setTop(new KdTree());
+	v->raytracer->setTop(new Octree());
 
 	return (PyObject*)v;
 }
--- a/src/scene.cc	Wed Dec 12 19:59:19 2007 +0100
+++ b/src/scene.cc	Thu Dec 13 00:08:11 2007 +0100
@@ -329,6 +329,136 @@
 #endif
 }
 
+bool Triangle::intersect_bbox(const BBox &bbox) const
+{
+	const Vector3 boxcenter = (bbox.L+bbox.H)*0.5;
+	const Vector3 boxhalfsize = (bbox.H-bbox.L)*0.5;
+	const Vector3 v0 = A->P - boxcenter;
+	const Vector3 v1 = B->P - boxcenter;
+	const Vector3 v2 = C->P - boxcenter;
+	const Vector3 e0 = v1-v0;
+	const Vector3 e1 = v2-v1;
+	const Vector3 e2 = v0-v2;
+
+	Float fex = fabsf(e0.x);
+	Float fey = fabsf(e0.y);
+	Float fez = fabsf(e0.z);
+
+	Float p0,p1,p2,min,max,rad;
+
+	p0 = e0.z*v0.y - e0.y*v0.z;
+	p2 = e0.z*v2.y - e0.y*v2.z;
+	if(p0<p2) {min=p0; max=p2;} else {min=p2; max=p0;}
+	rad = fez * boxhalfsize.y + fey * boxhalfsize.z;
+	if(min>rad || max<-rad) return false;
+
+	p0 = -e0.z*v0.x + e0.x*v0.z;
+	p2 = -e0.z*v2.x + e0.x*v2.z;
+	if(p0<p2) {min=p0; max=p2;} else {min=p2; max=p0;}
+	rad = fez * boxhalfsize.x + fex * boxhalfsize.z;
+	if(min>rad || max<-rad) return false;
+
+	p1 = e0.y*v1.x - e0.x*v1.y;
+	p2 = e0.y*v2.x - e0.x*v2.y;
+	if(p2<p1) {min=p2; max=p1;} else {min=p1; max=p2;}
+	rad = fey * boxhalfsize.x + fex * boxhalfsize.y;
+	if(min>rad || max<-rad) return false;
+
+	fex = fabsf(e1.x);
+	fey = fabsf(e1.y);
+	fez = fabsf(e1.z);
+
+	p0 = e1.z*v0.y - e1.y*v0.z;
+	p2 = e1.z*v2.y - e1.y*v2.z;
+	if(p0<p2) {min=p0; max=p2;} else {min=p2; max=p0;}
+	rad = fez * boxhalfsize.y + fey * boxhalfsize.z;
+	if(min>rad || max<-rad) return false;
+
+	p0 = -e1.z*v0.x + e1.x*v0.z;
+	p2 = -e1.z*v2.x + e1.x*v2.z;
+	if(p0<p2) {min=p0; max=p2;} else {min=p2; max=p0;}
+	rad = fez * boxhalfsize.x + fex * boxhalfsize.z;
+	if(min>rad || max<-rad) return false;
+
+	p0 = e1.y*v0.x - e1.x*v0.y;
+	p1 = e1.y*v1.x - e1.x*v1.y;
+	if(p0<p1) {min=p0; max=p1;} else {min=p1; max=p0;}
+	rad = fey * boxhalfsize.x + fex * boxhalfsize.y;
+	if(min>rad || max<-rad) return false;
+
+	fex = fabsf(e2.x);
+	fey = fabsf(e2.y);
+	fez = fabsf(e2.z);
+
+	p0 = e2.z*v0.y - e2.y*v0.z;
+	p1 = e2.z*v1.y - e2.y*v1.z;
+	if(p0<p1) {min=p0; max=p1;} else {min=p1; max=p0;}
+	rad = fez * boxhalfsize.y + fey * boxhalfsize.z;
+	if(min>rad || max<-rad) return false;
+
+	p0 = -e2.z*v0.x + e2.x*v0.z;
+	p1 = -e2.z*v1.x + e2.x*v1.z;
+	if(p0<p1) {min=p0; max=p1;} else {min=p1; max=p0;}
+	rad = fez * boxhalfsize.x + fex * boxhalfsize.z;
+	if(min>rad || max<-rad) return false;
+
+	p1 = e2.y*v1.x - e2.x*v1.y;
+	p2 = e2.y*v2.x - e2.x*v2.y;
+	if(p2<p1) {min=p2; max=p1;} else {min=p1; max=p2;}
+	rad = fey * boxhalfsize.x + fex * boxhalfsize.y;
+	if(min>rad || max<-rad) return false;
+
+	/* test overlap in the {x,y,z}-directions */
+	/* test in X-direction */
+	min = v0.x;
+	if (v1.x < min) min = v1.x;
+	if (v2.x < min) min = v2.x;
+	max = v0.x;
+	if (v1.x > max) max = v1.x;
+	if (v2.x > max) max = v2.x;
+	if(min>boxhalfsize.x || max<-boxhalfsize.x) return false;
+
+	/* test in Y-direction */
+	min = v0.y;
+	if (v1.y < min) min = v1.y;
+	if (v2.y < min) min = v2.y;
+	max = v0.y;
+	if (v1.y > max) max = v1.y;
+	if (v2.y > max) max = v2.y;
+	if(min>boxhalfsize.y || max<-boxhalfsize.y) return false;
+
+	/* test in Z-direction */
+	min = v0.z;
+	if (v1.z < min) min = v1.z;
+	if (v2.z < min) min = v2.z;
+	max = v0.z;
+	if (v1.z > max) max = v1.z;
+	if (v2.z > max) max = v2.z;
+	if(min>boxhalfsize.z || max<-boxhalfsize.z) return false;
+
+	/*  test if the box intersects the plane of the triangle */
+	Vector3 vmin,vmax;
+	Float v;
+	for(int q=0;q<3;q++)
+	{
+		v=v0[q];
+		if(N[q]>0.0f)
+		{
+			vmin.cell[q]=-boxhalfsize[q] - v;
+			vmax.cell[q]= boxhalfsize[q] - v;
+		}
+		else
+		{
+			vmin.cell[q]= boxhalfsize[q] - v;
+			vmax.cell[q]=-boxhalfsize[q] - v;
+		}
+	}
+	if(dot(N,vmin)>0.0f) return false;
+	if(dot(N,vmax)>=0.0f) return true;
+
+	return false;
+}
+
 BBox Triangle::get_bbox() const
 {
 	BBox bbox = BBox();