clray

changeset 26:c740ae431d51

continuing with the kdtree construction
author John Tsiombikas <nuclear@member.fsf.org>
date Tue, 17 Aug 2010 01:19:43 +0100
parents 58642a8316b7
children 8b2f2ad14ae7
files src/scene.cc src/scene.h
diffstat 2 files changed, 142 insertions(+), 6 deletions(-) [+]
line diff
     1.1 --- a/src/scene.cc	Sat Aug 14 07:00:04 2010 +0100
     1.2 +++ b/src/scene.cc	Tue Aug 17 01:19:43 2010 +0100
     1.3 @@ -1,7 +1,29 @@
     1.4  #include <math.h>
     1.5  #include <float.h>
     1.6 +#include <assert.h>
     1.7  #include "scene.h"
     1.8  
     1.9 +
    1.10 +static int build_kdtree(KDNode *kd);
    1.11 +static float eval_cost(const std::list<const Face*> &faces, const AABBox &aabb, int axis);
    1.12 +static void free_kdtree(KDNode *node);
    1.13 +
    1.14 +
    1.15 +static int accel_param[NUM_ACCEL_PARAMS] = {
    1.16 +	75,	// max tree depth
    1.17 +	0,	// max items per node (0 means ignore limit)
    1.18 +	5,	// estimated traversal cost
    1.19 +	15	// estimated interseciton cost
    1.20 +};
    1.21 +
    1.22 +
    1.23 +void set_accel_param(int p, int v)
    1.24 +{
    1.25 +	assert(p >= 0 && p < NUM_ACCEL_PARAMS);
    1.26 +	accel_param[p] = v;
    1.27 +}
    1.28 +
    1.29 +
    1.30  #define FEQ(a, b)	(fabs((a) - (b)) < 1e-8)
    1.31  bool Face::operator ==(const Face &f) const
    1.32  {
    1.33 @@ -30,6 +52,14 @@
    1.34  	return 2.0f * (area1 + area2 + area3);
    1.35  }
    1.36  
    1.37 +KDNode::KDNode()
    1.38 +{
    1.39 +	axis = 0;
    1.40 +	pt = 0.0;
    1.41 +	left = right = 0;
    1.42 +	num_faces = 0;
    1.43 +}
    1.44 +
    1.45  
    1.46  Scene::Scene()
    1.47  {
    1.48 @@ -124,8 +154,6 @@
    1.49  	return facebuf;
    1.50  }
    1.51  
    1.52 -static int build_kdtree(KDNode *kd);
    1.53 -static void free_kdtree(KDNode *node);
    1.54  
    1.55  void Scene::build_kdtree()
    1.56  {
    1.57 @@ -136,7 +164,6 @@
    1.58  
    1.59  	free_kdtree(kdtree);
    1.60  	kdtree = new KDNode;
    1.61 -	kdtree->left = kdtree->right = 0;
    1.62  
    1.63  	/* Start the construction of the kdtree by adding all faces of the scene
    1.64  	 * to the new root node. At the same time calculate the root's AABB.
    1.65 @@ -163,20 +190,114 @@
    1.66  		}
    1.67  
    1.68  		kdtree->faces.push_back(face);	// add the face
    1.69 +		kdtree->num_faces++;
    1.70  	}
    1.71  
    1.72 +	// calculate the heuristic for the root
    1.73 +	kdtree->cost = eval_cost(kdtree->faces, kdtree->aabb, kdtree->axis);
    1.74 +
    1.75  	// now proceed splitting the root recursively
    1.76  	::build_kdtree(kdtree);
    1.77  }
    1.78  
    1.79  static int build_kdtree(KDNode *kd)
    1.80  {
    1.81 -	if(kd->faces.empty()) {
    1.82 +	int opt_max_items = accel_param[ACCEL_PARAM_MAX_NODE_ITEMS];
    1.83 +	if(kd->num_faces == 0 || (opt_max_items > 1 && kd->num_faces < opt_max_items)) {
    1.84  		return 0;
    1.85  	}
    1.86  
    1.87 -	// XXX cont.
    1.88 -	return -1;
    1.89 +	int axis = (kd->axis + 1) % 3;
    1.90 +
    1.91 +	float best_cost[2], best_sum_cost = FLT_MAX;
    1.92 +	float best_split;
    1.93 +
    1.94 +	std::list<const Face*>::iterator it = kd->faces.begin();
    1.95 +	while(it != kd->faces.end()) {
    1.96 +		const Face *face = *it++;
    1.97 +
    1.98 +		for(int i=0; i<3; i++) {
    1.99 +			AABBox aabb_left, aabb_right;
   1.100 +			const float *split = face->v[i].pos;
   1.101 +
   1.102 +			aabb_left = aabb_right = kd->aabb;
   1.103 +			aabb_left.max[axis] = split[axis];
   1.104 +			aabb_right.min[axis] = split[axis];
   1.105 +
   1.106 +			float left_cost = eval_cost(kd->faces, aabb_left, axis);
   1.107 +			float right_cost = eval_cost(kd->faces, aabb_right, axis);
   1.108 +			float sum_cost = left_cost + right_cost;
   1.109 +
   1.110 +			if(sum_cost < best_sum_cost) {
   1.111 +				best_cost[0] = left_cost;
   1.112 +				best_cost[1] = right_cost;
   1.113 +				best_sum_cost = sum_cost;
   1.114 +				best_split = split[axis];
   1.115 +			}
   1.116 +		}
   1.117 +	}
   1.118 +
   1.119 +	if(best_sum_cost >= kd->cost) {
   1.120 +		return 0;	// stop splitting if it doesn't reduce the cost
   1.121 +	}
   1.122 +	kd->pt = best_split;
   1.123 +
   1.124 +	// create the two children
   1.125 +	KDNode *kdleft, *kdright;
   1.126 +	kdleft = new KDNode;
   1.127 +	kdright = new KDNode;
   1.128 +
   1.129 +	kdleft->axis = kdright->axis = axis;
   1.130 +	kdleft->aabb = kdright->aabb = kd->aabb;
   1.131 +
   1.132 +	kdleft->aabb.max[axis] = best_split;
   1.133 +	kdright->aabb.min[axis] = best_split;
   1.134 +
   1.135 +	kdleft->cost = best_cost[0];
   1.136 +	kdright->cost = best_cost[1];
   1.137 +
   1.138 +	it = kd->faces.begin();
   1.139 +	while(it != kd->faces.end()) {
   1.140 +		const Face *face = *it++;
   1.141 +
   1.142 +		if(face->v[0].pos[axis] < best_split ||
   1.143 +				face->v[1].pos[axis] < best_split ||
   1.144 +				face->v[2].pos[axis] < best_split) {
   1.145 +			kdleft->faces.push_back(face);
   1.146 +			kdleft->num_faces++;
   1.147 +		}
   1.148 +		if(face->v[0].pos[axis] >= best_split ||
   1.149 +				face->v[1].pos[axis] >= best_split ||
   1.150 +				face->v[2].pos[axis] >= best_split) {
   1.151 +			kdright->faces.push_back(face);
   1.152 +			kdright->num_faces++;
   1.153 +		}
   1.154 +	}
   1.155 +
   1.156 +	kd->left = kdleft;
   1.157 +	kd->right = kdright;
   1.158 +	return 0;
   1.159 +}
   1.160 +
   1.161 +static float eval_cost(const std::list<const Face*> &faces, const AABBox &aabb, int axis)
   1.162 +{
   1.163 +	int num_inside = 0;
   1.164 +	int tcost = accel_param[ACCEL_PARAM_COST_TRAVERSE];
   1.165 +	int icost = accel_param[ACCEL_PARAM_COST_INTERSECT];
   1.166 +
   1.167 +	std::list<const Face*>::const_iterator it = faces.begin();
   1.168 +	while(it != faces.end()) {
   1.169 +		const Face *face = *it++;
   1.170 +
   1.171 +		for(int i=0; i<3; i++) {
   1.172 +			if(face->v[i].pos[axis] >= aabb.min[axis] && face->v[i].pos[axis] < aabb.max[axis]) {
   1.173 +				num_inside++;
   1.174 +				break;
   1.175 +			}
   1.176 +		}
   1.177 +	}
   1.178 +
   1.179 +	return tcost + aabb.calc_surface_area() * num_inside * icost;
   1.180  }
   1.181  
   1.182  static void free_kdtree(KDNode *node)
     2.1 --- a/src/scene.h	Sat Aug 14 07:00:04 2010 +0100
     2.2 +++ b/src/scene.h	Tue Aug 17 01:19:43 2010 +0100
     2.3 @@ -56,9 +56,13 @@
     2.4  	int axis;
     2.5  	float pt;
     2.6  	AABBox aabb;
     2.7 +	float cost;
     2.8  
     2.9  	KDNode *left, *right;
    2.10 +	int num_faces;	// cause on some implementations list::size() is O(n)
    2.11  	std::list<const Face*> faces;
    2.12 +
    2.13 +	KDNode();
    2.14  };
    2.15  
    2.16  struct KDNodeGPU {
    2.17 @@ -97,4 +101,15 @@
    2.18  	void build_kdtree();
    2.19  };
    2.20  
    2.21 +enum {
    2.22 +	ACCEL_PARAM_MAX_TREE_DEPTH,
    2.23 +	ACCEL_PARAM_MAX_NODE_ITEMS,
    2.24 +	ACCEL_PARAM_COST_TRAVERSE,
    2.25 +	ACCEL_PARAM_COST_INTERSECT,
    2.26 +
    2.27 +	NUM_ACCEL_PARAMS
    2.28 +};
    2.29 +
    2.30 +void set_accel_param(int p, int v);
    2.31 +
    2.32  #endif	/* MESH_H_ */