clray

changeset 27:8b2f2ad14ae7

semi-fixed the kdtree construction
author John Tsiombikas <nuclear@member.fsf.org>
date Tue, 17 Aug 2010 20:35:00 +0100
parents c740ae431d51
children 97cfd9675310
files src/clray.cc src/rt.cc src/rt.h src/scene.cc src/scene.h
diffstat 5 files changed, 229 insertions(+), 40 deletions(-) [+]
line diff
     1.1 --- a/src/clray.cc	Tue Aug 17 01:19:43 2010 +0100
     1.2 +++ b/src/clray.cc	Tue Aug 17 20:35:00 2010 +0100
     1.3 @@ -1,6 +1,7 @@
     1.4  #include <stdio.h>
     1.5  #include <stdlib.h>
     1.6  #include <string.h>
     1.7 +#include <ctype.h>
     1.8  #include <errno.h>
     1.9  #ifndef __APPLE__
    1.10  #include <GL/glut.h>
    1.11 @@ -25,7 +26,9 @@
    1.12  static float cam_theta, cam_phi = 25.0;
    1.13  static float cam_dist = 10.0;
    1.14  
    1.15 -static bool dbg_glrender = false;
    1.16 +static bool dbg_glrender = true;
    1.17 +static bool dbg_show_kdtree = false;
    1.18 +static bool dbg_show_obj = true;
    1.19  
    1.20  static Scene scn;
    1.21  
    1.22 @@ -36,11 +39,46 @@
    1.23  
    1.24  	int loaded = 0;
    1.25  	for(int i=1; i<argc; i++) {
    1.26 -		if(!scn.load(argv[i])) {
    1.27 -			fprintf(stderr, "failed to load scene: %s\n", argv[i]);
    1.28 -			return false;
    1.29 +		if(argv[i][0] == '-' && argv[i][2] == 0) {
    1.30 +			switch(argv[i][1]) {
    1.31 +			case 'i':
    1.32 +				if(!argv[++i] || !isdigit(argv[i][0])) {
    1.33 +					fprintf(stderr, "-i must be followed by the intersection cost\n");
    1.34 +					return 1;
    1.35 +				}
    1.36 +
    1.37 +				set_accel_param(ACCEL_PARAM_COST_INTERSECT, atoi(argv[i]));
    1.38 +				break;
    1.39 +
    1.40 +			case 't':
    1.41 +				if(!argv[++i] || !isdigit(argv[i][0])) {
    1.42 +					fprintf(stderr, "-t must be followed by the traversal cost\n");
    1.43 +					return 1;
    1.44 +				}
    1.45 +
    1.46 +				set_accel_param(ACCEL_PARAM_COST_TRAVERSE, atoi(argv[i]));
    1.47 +				break;
    1.48 +
    1.49 +			case 'c':
    1.50 +				if(!argv[++i] || !isdigit(argv[i][0])) {
    1.51 +					fprintf(stderr, "-c must be followed by the max number of items per leaf node\n");
    1.52 +					return 1;
    1.53 +				}
    1.54 +
    1.55 +				set_accel_param(ACCEL_PARAM_MAX_NODE_ITEMS, atoi(argv[i]));
    1.56 +				break;
    1.57 +
    1.58 +			default:
    1.59 +				fprintf(stderr, "unrecognized option: %s\n", argv[i]);
    1.60 +				return 1;
    1.61 +			}
    1.62 +		} else {
    1.63 +			if(!scn.load(argv[i])) {
    1.64 +				fprintf(stderr, "failed to load scene: %s\n", argv[i]);
    1.65 +				return false;
    1.66 +			}
    1.67 +			loaded++;
    1.68  		}
    1.69 -		loaded++;
    1.70  	}
    1.71  
    1.72  	if(!loaded) {
    1.73 @@ -69,6 +107,11 @@
    1.74  	}
    1.75  	atexit(cleanup);
    1.76  
    1.77 +	if(!scn.build_kdtree()) {
    1.78 +		return 1;
    1.79 +	}
    1.80 +
    1.81 +
    1.82  	/*glGenTextures(1, &tex);
    1.83  	glBindTexture(GL_TEXTURE_2D, tex);*/
    1.84  	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
    1.85 @@ -125,7 +168,7 @@
    1.86  	if(dbg_glrender) {
    1.87  		glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    1.88  		glLoadMatrixf(inv_mat.m);
    1.89 -		dbg_render_gl(&scn);
    1.90 +		dbg_render_gl(&scn, dbg_show_kdtree, dbg_show_obj);
    1.91  	} else {
    1.92  		glEnable(GL_TEXTURE_2D);
    1.93  		glDisable(GL_LIGHTING);
    1.94 @@ -175,6 +218,20 @@
    1.95  		glutPostRedisplay();
    1.96  		break;
    1.97  
    1.98 +	case 'k':
    1.99 +		dbg_show_kdtree = !dbg_show_kdtree;
   1.100 +		if(dbg_glrender) {
   1.101 +			glutPostRedisplay();
   1.102 +		}
   1.103 +		break;
   1.104 +
   1.105 +	case 'o':
   1.106 +		dbg_show_obj = !dbg_show_obj;
   1.107 +		if(dbg_glrender) {
   1.108 +			glutPostRedisplay();
   1.109 +		}
   1.110 +		break;
   1.111 +
   1.112  	default:
   1.113  		break;
   1.114  	}
     2.1 --- a/src/rt.cc	Tue Aug 17 01:19:43 2010 +0100
     2.2 +++ b/src/rt.cc	Tue Aug 17 20:35:00 2010 +0100
     2.3 @@ -135,6 +135,7 @@
     2.4  	return true;
     2.5  }
     2.6  
     2.7 +#define MIN(a, b)	((a) < (b) ? (a) : (b))
     2.8  static void dbg_set_gl_material(Material *mat)
     2.9  {
    2.10  	static Material def_mat = {{0.7, 0.7, 0.7, 1}, {0, 0, 0, 0}, 0, 0, 0};
    2.11 @@ -143,10 +144,10 @@
    2.12  
    2.13  	glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, mat->kd);
    2.14  	glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, mat->ks);
    2.15 -	glMaterialf(GL_FRONT_AND_BACK, GL_SHININESS, mat->spow);
    2.16 +	glMaterialf(GL_FRONT_AND_BACK, GL_SHININESS, MIN(mat->spow, 128.0f));
    2.17  }
    2.18  
    2.19 -void dbg_render_gl(Scene *scn)
    2.20 +void dbg_render_gl(Scene *scn, bool show_tree, bool show_obj)
    2.21  {
    2.22  	glPushAttrib(GL_ENABLE_BIT | GL_TRANSFORM_BIT | GL_LIGHTING_BIT);
    2.23  
    2.24 @@ -170,27 +171,33 @@
    2.25  	glLoadIdentity();
    2.26  	gluPerspective(45.0, (float)rinf.xsz / (float)rinf.ysz, 0.5, 1000.0);
    2.27  
    2.28 -	Material *materials = scn->get_materials();
    2.29 +	if(show_obj) {
    2.30 +		Material *materials = scn->get_materials();
    2.31  
    2.32 -	int num_faces = scn->get_num_faces();
    2.33 -	int cur_mat = -1;
    2.34 +		int num_faces = scn->get_num_faces();
    2.35 +		int cur_mat = -1;
    2.36  
    2.37 -	for(int i=0; i<num_faces; i++) {
    2.38 -		if(faces[i].matid != cur_mat) {
    2.39 -			if(cur_mat != -1) {
    2.40 -				glEnd();
    2.41 +		for(int i=0; i<num_faces; i++) {
    2.42 +			if(faces[i].matid != cur_mat) {
    2.43 +				if(cur_mat != -1) {
    2.44 +					glEnd();
    2.45 +				}
    2.46 +				dbg_set_gl_material(materials ? materials + faces[i].matid : 0);
    2.47 +				cur_mat = faces[i].matid;
    2.48 +				glBegin(GL_TRIANGLES);
    2.49  			}
    2.50 -			dbg_set_gl_material(materials ? materials + faces[i].matid : 0);
    2.51 -			cur_mat = faces[i].matid;
    2.52 -			glBegin(GL_TRIANGLES);
    2.53 +
    2.54 +			for(int j=0; j<3; j++) {
    2.55 +				glNormal3fv(faces[i].v[j].normal);
    2.56 +				glVertex3fv(faces[i].v[j].pos);
    2.57 +			}
    2.58  		}
    2.59 +		glEnd();
    2.60 +	}
    2.61  
    2.62 -		for(int j=0; j<3; j++) {
    2.63 -			glNormal3fv(faces[i].v[j].normal);
    2.64 -			glVertex3fv(faces[i].v[j].pos);
    2.65 -		}
    2.66 +	if(show_tree) {
    2.67 +		scn->draw_kdtree();
    2.68  	}
    2.69 -	glEnd();
    2.70  
    2.71  	glPopMatrix();
    2.72  	glPopAttrib();
     3.1 --- a/src/rt.h	Tue Aug 17 01:19:43 2010 +0100
     3.2 +++ b/src/rt.h	Tue Aug 17 20:35:00 2010 +0100
     3.3 @@ -8,6 +8,6 @@
     3.4  bool render();
     3.5  void set_xform(float *matrix, float *invtrans);
     3.6  
     3.7 -void dbg_render_gl(Scene *scn);
     3.8 +void dbg_render_gl(Scene *scn, bool show_tree = false, bool show_obj = true);
     3.9  
    3.10  #endif	/* RT_H_ */
     4.1 --- a/src/scene.cc	Tue Aug 17 01:19:43 2010 +0100
     4.2 +++ b/src/scene.cc	Tue Aug 17 20:35:00 2010 +0100
     4.3 @@ -2,11 +2,15 @@
     4.4  #include <float.h>
     4.5  #include <assert.h>
     4.6  #include "scene.h"
     4.7 +#include "ogl.h"
     4.8  
     4.9  
    4.10 -static int build_kdtree(KDNode *kd);
    4.11 -static float eval_cost(const std::list<const Face*> &faces, const AABBox &aabb, int axis);
    4.12 +static void draw_kdtree(const KDNode *node, int level = 0);
    4.13 +static bool build_kdtree(KDNode *kd, int level = 0);
    4.14 +static float eval_cost(const std::list<const Face*> &faces, const AABBox &aabb, int axis, float par_sarea = 1.0);
    4.15  static void free_kdtree(KDNode *node);
    4.16 +static int kdtree_depth(const KDNode *node);
    4.17 +static void print_item_counts(const KDNode *node, int level);
    4.18  
    4.19  
    4.20  static int accel_param[NUM_ACCEL_PARAMS] = {
    4.21 @@ -155,13 +159,91 @@
    4.22  }
    4.23  
    4.24  
    4.25 -void Scene::build_kdtree()
    4.26 +void Scene::draw_kdtree() const
    4.27 +{
    4.28 +	glPushAttrib(GL_ENABLE_BIT);
    4.29 +	glDisable(GL_LIGHTING);
    4.30 +	glDepthMask(0);
    4.31 +
    4.32 +	glBegin(GL_LINES);
    4.33 +	::draw_kdtree(kdtree, 0);
    4.34 +	glEnd();
    4.35 +
    4.36 +	glDepthMask(1);
    4.37 +	glPopAttrib();
    4.38 +}
    4.39 +
    4.40 +static float palette[][3] = {
    4.41 +	{0, 1, 0},
    4.42 +	{0, 1, 0},
    4.43 +	{0, 1, 0},
    4.44 +	{1, 0, 0},
    4.45 +	{1, 0, 0},
    4.46 +	{1, 0, 0},
    4.47 +	{0, 0, 1},
    4.48 +	{0, 0, 1},
    4.49 +	{0, 0, 1},
    4.50 +	{1, 1, 0},
    4.51 +	{1, 1, 0},
    4.52 +	{1, 1, 0},
    4.53 +	{0, 0, 1},
    4.54 +	{0, 0, 1},
    4.55 +	{0, 0, 1},
    4.56 +	{1, 0, 1},
    4.57 +	{1, 0, 1},
    4.58 +	{1, 0, 1}
    4.59 +};
    4.60 +static int pal_size = sizeof palette / sizeof *palette;
    4.61 +
    4.62 +static void draw_kdtree(const KDNode *node, int level)
    4.63 +{
    4.64 +	if(!node) return;
    4.65 +
    4.66 +	draw_kdtree(node->left, level + 1);
    4.67 +	draw_kdtree(node->right, level + 1);
    4.68 +
    4.69 +	glColor3fv(palette[level % pal_size]);
    4.70 +
    4.71 +	glVertex3fv(node->aabb.min);
    4.72 +	glVertex3f(node->aabb.max[0], node->aabb.min[1], node->aabb.min[2]);
    4.73 +	glVertex3f(node->aabb.max[0], node->aabb.min[1], node->aabb.min[2]);
    4.74 +	glVertex3f(node->aabb.max[0], node->aabb.max[1], node->aabb.min[2]);
    4.75 +	glVertex3f(node->aabb.max[0], node->aabb.max[1], node->aabb.min[2]);
    4.76 +	glVertex3f(node->aabb.min[0], node->aabb.max[1], node->aabb.min[2]);
    4.77 +	glVertex3f(node->aabb.min[0], node->aabb.max[1], node->aabb.min[2]);
    4.78 +	glVertex3fv(node->aabb.min);
    4.79 +
    4.80 +	glVertex3f(node->aabb.min[0], node->aabb.min[1], node->aabb.max[2]);
    4.81 +	glVertex3f(node->aabb.max[0], node->aabb.min[1], node->aabb.max[2]);
    4.82 +	glVertex3f(node->aabb.max[0], node->aabb.min[1], node->aabb.max[2]);
    4.83 +	glVertex3fv(node->aabb.max);
    4.84 +	glVertex3fv(node->aabb.max);
    4.85 +	glVertex3f(node->aabb.min[0], node->aabb.max[1], node->aabb.max[2]);
    4.86 +	glVertex3f(node->aabb.min[0], node->aabb.max[1], node->aabb.max[2]);
    4.87 +	glVertex3f(node->aabb.min[0], node->aabb.min[1], node->aabb.max[2]);
    4.88 +
    4.89 +	glVertex3fv(node->aabb.min);
    4.90 +	glVertex3f(node->aabb.min[0], node->aabb.min[1], node->aabb.max[2]);
    4.91 +	glVertex3f(node->aabb.max[0], node->aabb.min[1], node->aabb.min[2]);
    4.92 +	glVertex3f(node->aabb.max[0], node->aabb.min[1], node->aabb.max[2]);
    4.93 +	glVertex3f(node->aabb.max[0], node->aabb.max[1], node->aabb.min[2]);
    4.94 +	glVertex3fv(node->aabb.max);
    4.95 +	glVertex3f(node->aabb.min[0], node->aabb.max[1], node->aabb.min[2]);
    4.96 +	glVertex3f(node->aabb.min[0], node->aabb.max[1], node->aabb.max[2]);
    4.97 +}
    4.98 +
    4.99 +bool Scene::build_kdtree()
   4.100  {
   4.101  	const Face *faces = get_face_buffer();
   4.102  	int num_faces = get_num_faces();
   4.103  
   4.104  	printf("Constructing kd-tree out of %d faces ...\n", num_faces);
   4.105  
   4.106 +	int icost = accel_param[ACCEL_PARAM_COST_INTERSECT];
   4.107 +	int tcost = accel_param[ACCEL_PARAM_COST_TRAVERSE];
   4.108 +	printf("  max items per leaf: %d\n", accel_param[ACCEL_PARAM_MAX_NODE_ITEMS]);
   4.109 +	printf("  SAH parameters - tcost: %d - icost: %d\n", tcost, icost);
   4.110 +
   4.111  	free_kdtree(kdtree);
   4.112  	kdtree = new KDNode;
   4.113  
   4.114 @@ -197,17 +279,27 @@
   4.115  	kdtree->cost = eval_cost(kdtree->faces, kdtree->aabb, kdtree->axis);
   4.116  
   4.117  	// now proceed splitting the root recursively
   4.118 -	::build_kdtree(kdtree);
   4.119 +	if(!::build_kdtree(kdtree)) {
   4.120 +		fprintf(stderr, "failed to build kdtree\n");
   4.121 +		return false;
   4.122 +	}
   4.123 +
   4.124 +	printf("  tree depth: %d\n", kdtree_depth(kdtree));
   4.125 +	print_item_counts(kdtree, 0);
   4.126 +	return true;
   4.127  }
   4.128  
   4.129 -static int build_kdtree(KDNode *kd)
   4.130 +static bool build_kdtree(KDNode *kd, int level)
   4.131  {
   4.132  	int opt_max_items = accel_param[ACCEL_PARAM_MAX_NODE_ITEMS];
   4.133 -	if(kd->num_faces == 0 || (opt_max_items > 1 && kd->num_faces < opt_max_items)) {
   4.134 -		return 0;
   4.135 +	int tcost = accel_param[ACCEL_PARAM_COST_TRAVERSE];
   4.136 +
   4.137 +	if(kd->num_faces == 0) {
   4.138 +		return true;
   4.139  	}
   4.140  
   4.141 -	int axis = (kd->axis + 1) % 3;
   4.142 +	int axis = level % 3;
   4.143 +	//float parent_sa = kd->aabb.calc_surface_area();
   4.144  
   4.145  	float best_cost[2], best_sum_cost = FLT_MAX;
   4.146  	float best_split;
   4.147 @@ -226,7 +318,7 @@
   4.148  
   4.149  			float left_cost = eval_cost(kd->faces, aabb_left, axis);
   4.150  			float right_cost = eval_cost(kd->faces, aabb_right, axis);
   4.151 -			float sum_cost = left_cost + right_cost;
   4.152 +			float sum_cost = left_cost + right_cost - tcost;	// tcost is added twice
   4.153  
   4.154  			if(sum_cost < best_sum_cost) {
   4.155  				best_cost[0] = left_cost;
   4.156 @@ -237,8 +329,9 @@
   4.157  		}
   4.158  	}
   4.159  
   4.160 -	if(best_sum_cost >= kd->cost) {
   4.161 -		return 0;	// stop splitting if it doesn't reduce the cost
   4.162 +	printf("current cost: %f,   best_cost: %f\n", kd->cost, best_sum_cost);
   4.163 +	if(best_sum_cost > kd->cost && (opt_max_items == 0 || kd->num_faces <= opt_max_items)) {
   4.164 +		return true;	// stop splitting if it doesn't reduce the cost
   4.165  	}
   4.166  	kd->pt = best_split;
   4.167  
   4.168 @@ -247,7 +340,6 @@
   4.169  	kdleft = new KDNode;
   4.170  	kdright = new KDNode;
   4.171  
   4.172 -	kdleft->axis = kdright->axis = axis;
   4.173  	kdleft->aabb = kdright->aabb = kd->aabb;
   4.174  
   4.175  	kdleft->aabb.max[axis] = best_split;
   4.176 @@ -256,6 +348,8 @@
   4.177  	kdleft->cost = best_cost[0];
   4.178  	kdright->cost = best_cost[1];
   4.179  
   4.180 +	//kdleft->axis = kdright->axis = (axis + 1) % 3;
   4.181 +
   4.182  	it = kd->faces.begin();
   4.183  	while(it != kd->faces.end()) {
   4.184  		const Face *face = *it++;
   4.185 @@ -273,13 +367,15 @@
   4.186  			kdright->num_faces++;
   4.187  		}
   4.188  	}
   4.189 +	kd->faces.clear();	// only leaves have faces
   4.190  
   4.191  	kd->left = kdleft;
   4.192  	kd->right = kdright;
   4.193 -	return 0;
   4.194 +
   4.195 +	return build_kdtree(kd->left, level + 1) && build_kdtree(kd->right, level + 1);
   4.196  }
   4.197  
   4.198 -static float eval_cost(const std::list<const Face*> &faces, const AABBox &aabb, int axis)
   4.199 +static float eval_cost(const std::list<const Face*> &faces, const AABBox &aabb, int axis, float par_sarea)
   4.200  {
   4.201  	int num_inside = 0;
   4.202  	int tcost = accel_param[ACCEL_PARAM_COST_TRAVERSE];
   4.203 @@ -297,7 +393,12 @@
   4.204  		}
   4.205  	}
   4.206  
   4.207 -	return tcost + aabb.calc_surface_area() * num_inside * icost;
   4.208 +	float sarea = aabb.calc_surface_area();
   4.209 +	if(sarea < 1e-8) {
   4.210 +		return FLT_MAX;	// heavily penalize 0-area voxels
   4.211 +	}
   4.212 +
   4.213 +	return tcost + (sarea / par_sarea) * num_inside * icost;
   4.214  }
   4.215  
   4.216  static void free_kdtree(KDNode *node)
   4.217 @@ -308,3 +409,25 @@
   4.218  		delete node;
   4.219  	}
   4.220  }
   4.221 +
   4.222 +static int kdtree_depth(const KDNode *node)
   4.223 +{
   4.224 +	if(!node) return 0;
   4.225 +
   4.226 +	int left = kdtree_depth(node->left);
   4.227 +	int right = kdtree_depth(node->right);
   4.228 +	return (left > right ? left : right) + 1;
   4.229 +}
   4.230 +
   4.231 +static void print_item_counts(const KDNode *node, int level)
   4.232 +{
   4.233 +	if(!node) return;
   4.234 +
   4.235 +	for(int i=0; i<level; i++) {
   4.236 +		fputs("   ", stdout);
   4.237 +	}
   4.238 +	printf("- %d (cost: %f)\n", node->num_faces, node->cost);
   4.239 +
   4.240 +	print_item_counts(node->left, level + 1);
   4.241 +	print_item_counts(node->right, level + 1);
   4.242 +}
     5.1 --- a/src/scene.h	Tue Aug 17 01:19:43 2010 +0100
     5.2 +++ b/src/scene.h	Tue Aug 17 20:35:00 2010 +0100
     5.3 @@ -98,7 +98,9 @@
     5.4  	bool load(FILE *fp);
     5.5  
     5.6  	const Face *get_face_buffer() const;
     5.7 -	void build_kdtree();
     5.8 +
     5.9 +	void draw_kdtree() const;
    5.10 +	bool build_kdtree();
    5.11  };
    5.12  
    5.13  enum {