src/kdtree.cc
branchpyrit
changeset 21 79b516a3803d
parent 20 f22952603f29
child 22 76b7bd51d64a
equal deleted inserted replaced
20:f22952603f29 21:79b516a3803d
    48 class SplitList: public vector<SplitPos>
    48 class SplitList: public vector<SplitPos>
    49 {
    49 {
    50 };
    50 };
    51 
    51 
    52 // stack element for kd-tree traversal
    52 // stack element for kd-tree traversal
    53 struct StackElem
    53 class StackElem
    54 {
    54 {
       
    55 public:
    55 	KdNode* node; /* pointer to far child */
    56 	KdNode* node; /* pointer to far child */
    56 	float t; /* the entry/exit signed distance */
    57 	float t; /* the entry/exit signed distance */
    57 	Vector3 pb; /* the coordinates of entry/exit point */
    58 	Vector3 pb; /* the coordinates of entry/exit point */
       
    59 	StackElem(KdNode *anode, const float &at, const Vector3 &apb):
       
    60 		node(anode), t(at), pb(apb) {};
    58 };
    61 };
    59 
    62 
    60 // ----------------------------------------
    63 // ----------------------------------------
    61 
    64 
    62 void Container::addShape(Shape* aShape)
    65 void Container::addShape(Shape* aShape)
    94 		delete shapes;
    97 		delete shapes;
    95 	else
    98 	else
    96 		delete[] children;
    99 		delete[] children;
    97 }
   100 }
    98 
   101 
    99 void KdNode::subdivide(BBox bbox, int depth)
   102 void KdNode::subdivide(BBox bbox, int maxdepth)
   100 {
   103 {
   101 	if (depth >= 20 || shapes->size() <= 4)
   104 	if (maxdepth <= 0 || shapes->size() <= 2)
   102 	{
   105 	{
   103 		setLeaf();
   106 		setLeaf();
   104 		return;
   107 		return;
   105 	}
   108 	}
   106 
   109 
   293 	}
   296 	}
   294 
   297 
   295 	lbb.H.cell[axis] = split;
   298 	lbb.H.cell[axis] = split;
   296 	rbb.L.cell[axis] = split;
   299 	rbb.L.cell[axis] = split;
   297 
   300 
   298 	children[0].subdivide(lbb, depth+1);
   301 	children[0].subdivide(lbb, maxdepth-1);
   299 	children[1].subdivide(rbb, depth+1);
   302 	children[1].subdivide(rbb, maxdepth-1);
   300 }
   303 }
   301 
   304 
   302 void KdTree::build()
   305 void KdTree::build()
   303 {
   306 {
   304 	infomsg("* building kd-tree\n");
   307 	infomsg("* building kd-tree\n");
   305 	root = new KdNode();
   308 	root = new KdNode();
   306 	ShapeList::iterator shape;
   309 	ShapeList::iterator shape;
   307 	for (shape = shapes.begin(); shape != shapes.end(); shape++)
   310 	for (shape = shapes.begin(); shape != shapes.end(); shape++)
   308 		root->addShape(*shape);
   311 		root->addShape(*shape);
   309 	root->subdivide(bbox, 0);
   312 	root->subdivide(bbox, max_depth);
   310 	built = true;
   313 	built = true;
   311 }
   314 }
   312 
   315 
   313 /* algorithm by Vlastimil Havran, Heuristic Ray Shooting Algorithms, appendix C */
   316 /* algorithm by Vlastimil Havran, Heuristic Ray Shooting Algorithms, appendix C */
   314 Shape *KdTree::nearest_intersection(const Shape *origin_shape, const Ray &ray,
   317 Shape *KdTree::nearest_intersection(const Shape *origin_shape, const Ray &ray,
   326 
   329 
   327 	/* pointers to the far child node and current node */
   330 	/* pointers to the far child node and current node */
   328 	KdNode *farchild, *node;
   331 	KdNode *farchild, *node;
   329 	node = root; /* start from the kd-tree root node */
   332 	node = root; /* start from the kd-tree root node */
   330 
   333 
   331 	stack<StackElem*> st;
   334 	/* std vector is much faster than stack */
   332 
   335 	vector<StackElem*> st;
   333 	StackElem *enPt = new StackElem();
   336 
   334 	enPt->t = a; /* set the signed distance */
   337 	StackElem *enPt = new StackElem(NULL, a,
   335 	enPt->node = NULL;
   338 		/* distinguish between internal and external origin of a ray*/
   336 
   339 		a >= 0.0 ?
   337 	/* distinguish between internal and external origin */
   340 			ray.o + ray.dir * a : /* external */
   338 	if (a >= 0.0) /* a ray with external origin */
   341 			ray.o);               /* internal */
   339 		enPt->pb = ray.o + ray.dir * a;
       
   340 	else /* a ray with internal origin */
       
   341 		enPt->pb = ray.o;
       
   342 
   342 
   343 	/* setup initial exit point in the stack */
   343 	/* setup initial exit point in the stack */
   344 	StackElem *exPt = new StackElem();
   344 	StackElem *exPt = new StackElem(NULL, b, ray.o + ray.dir * b);
   345 	exPt->t = b;
   345 	st.push_back(exPt);
   346 	exPt->pb = ray.o + ray.dir * b;
       
   347 	exPt->node = NULL; /* set termination flag */
       
   348 	st.push(exPt);
       
   349 
   346 
   350 	/* loop, traverse through the whole kd-tree, until an object is intersected or ray leaves the scene */
   347 	/* loop, traverse through the whole kd-tree, until an object is intersected or ray leaves the scene */
   351 	while (node)
   348 	while (node)
   352 	{
   349 	{
   353 		exPt = st.top();
   350 		exPt = st.back();
   354 		/* loop until a leaf is found */
   351 		/* loop until a leaf is found */
   355 		while (!node->isLeaf())
   352 		while (!node->isLeaf())
   356 		{
   353 		{
   357 			/* retrieve position of splitting plane */
   354 			/* retrieve position of splitting plane */
   358 			float splitVal = node->getSplit();
   355 			float splitVal = node->getSplit();
   391 
   388 
   392 			/* signed distance to the splitting plane */
   389 			/* signed distance to the splitting plane */
   393 			t = (splitVal - ray.o.cell[axis]) / ray.dir.cell[axis];
   390 			t = (splitVal - ray.o.cell[axis]) / ray.dir.cell[axis];
   394 
   391 
   395 			/* setup the new exit point and push it onto stack */
   392 			/* setup the new exit point and push it onto stack */
   396 			exPt = new StackElem();
   393 			exPt = new StackElem(farchild, t, Vector3());
   397 			exPt->t = t;
       
   398 			exPt->node = farchild;
       
   399 			exPt->pb[axis] = splitVal;
   394 			exPt->pb[axis] = splitVal;
   400 			exPt->pb[(axis+1)%3] = ray.o.cell[(axis+1)%3] + t * ray.dir.cell[(axis+1)%3];
   395 			exPt->pb[(axis+1)%3] = ray.o.cell[(axis+1)%3] + t * ray.dir.cell[(axis+1)%3];
   401 			exPt->pb[(axis+2)%3] = ray.o.cell[(axis+2)%3] + t * ray.dir.cell[(axis+2)%3];
   396 			exPt->pb[(axis+2)%3] = ray.o.cell[(axis+2)%3] + t * ray.dir.cell[(axis+2)%3];
   402 			st.push(exPt);
   397 			st.push_back(exPt);
   403 		} /* while */
   398 		} /* while */
   404 
   399 
   405 		/* current node is the leaf . . . empty or full */
   400 		/* current node is the leaf . . . empty or full */
   406 		/* "intersect ray with each object in the object list, discarding "
   401 		/* "intersect ray with each object in the object list, discarding "
   407 		"those lying before stack[enPt].t or farther than stack[exPt].t" */
   402 		"those lying before stack[enPt].t or farther than stack[exPt].t" */
   417 
   412 
   418 		if (nearest_shape)
   413 		if (nearest_shape)
   419 		{
   414 		{
   420 			while (!st.empty())
   415 			while (!st.empty())
   421 			{
   416 			{
   422 				delete st.top();
   417 				delete st.back();
   423 				st.pop();
   418 				st.pop_back();
   424 			}
   419 			}
   425 			nearest_distance = dist;
   420 			nearest_distance = dist;
   426 			return nearest_shape;
   421 			return nearest_shape;
   427 		}
   422 		}
   428 
   423 
   429 		enPt = exPt;
   424 		enPt = exPt;
   430 
   425 
   431 		/* retrieve the pointer to the next node, it is possible that ray traversal terminates */
   426 		/* retrieve the pointer to the next node, it is possible that ray traversal terminates */
   432 		node = enPt->node;
   427 		node = enPt->node;
   433 		st.pop();
   428 		st.pop_back();
   434 	} /* while */
   429 	} /* while */
   435 
   430 
   436 	delete enPt;
   431 	delete enPt;
   437 
   432 
   438 	/* ray leaves the scene */
   433 	/* ray leaves the scene */