clray

annotate src/scene.cc @ 37:ca445da26588

out of resources?!
author John Tsiombikas <nuclear@member.fsf.org>
date Fri, 27 Aug 2010 01:00:04 +0100
parents 4dec8853bf75
children 4bcf78e572d6
rev   line source
nuclear@35 1 #include <stdlib.h>
John@15 2 #include <math.h>
nuclear@25 3 #include <float.h>
nuclear@26 4 #include <assert.h>
nuclear@35 5 #include <map>
nuclear@22 6 #include "scene.h"
nuclear@27 7 #include "ogl.h"
nuclear@6 8
nuclear@26 9
nuclear@37 10 #define MIN(a, b) ((a) < (b) ? (a) : (b))
nuclear@37 11 #define MAX(a, b) ((a) > (b) ? (a) : (b))
nuclear@37 12
nuclear@37 13
nuclear@35 14 static void flatten_kdtree(const KDNode *node, KDNodeGPU *kdbuf, int *count, std::map<const KDNode*, int> *flatmap);
nuclear@35 15 static void fix_child_links(const KDNode *node, KDNodeGPU *kdbuf, const std::map<const KDNode*, int> &flatmap);
nuclear@27 16 static void draw_kdtree(const KDNode *node, int level = 0);
nuclear@32 17 static bool build_kdtree(KDNode *kd, const Face *faces, int level = 0);
nuclear@32 18 static float eval_cost(const Face *faces, const int *face_idx, int num_faces, const AABBox &aabb, int axis);
nuclear@26 19 static void free_kdtree(KDNode *node);
nuclear@27 20 static void print_item_counts(const KDNode *node, int level);
nuclear@26 21
nuclear@26 22
nuclear@26 23 static int accel_param[NUM_ACCEL_PARAMS] = {
nuclear@28 24 40, // max tree depth
nuclear@26 25 0, // max items per node (0 means ignore limit)
nuclear@26 26 5, // estimated traversal cost
nuclear@26 27 15 // estimated interseciton cost
nuclear@26 28 };
nuclear@26 29
nuclear@26 30
nuclear@26 31 void set_accel_param(int p, int v)
nuclear@26 32 {
nuclear@26 33 assert(p >= 0 && p < NUM_ACCEL_PARAMS);
nuclear@26 34 accel_param[p] = v;
nuclear@26 35 }
nuclear@26 36
nuclear@26 37
John@15 38 #define FEQ(a, b) (fabs((a) - (b)) < 1e-8)
John@15 39 bool Face::operator ==(const Face &f) const
John@15 40 {
John@15 41 for(int i=0; i<3; i++) {
John@15 42 for(int j=0; j<3; j++) {
John@15 43 if(!FEQ(v[i].pos[j], f.v[i].pos[j])) {
John@15 44 return false;
John@15 45 }
John@15 46 if(!FEQ(v[i].normal[j], f.v[i].normal[j])) {
John@15 47 return false;
John@15 48 }
John@15 49 }
John@15 50 if(!FEQ(normal[i], f.normal[i])) {
John@15 51 return false;
John@15 52 }
John@15 53 }
John@15 54 return true;
John@15 55 }
John@15 56
nuclear@25 57 float AABBox::calc_surface_area() const
nuclear@25 58 {
nuclear@25 59 float area1 = (max[0] - min[0]) * (max[1] - min[1]);
nuclear@25 60 float area2 = (max[3] - min[3]) * (max[1] - min[1]);
nuclear@25 61 float area3 = (max[0] - min[0]) * (max[3] - min[3]);
nuclear@25 62
nuclear@25 63 return 2.0f * (area1 + area2 + area3);
nuclear@25 64 }
nuclear@25 65
nuclear@26 66 KDNode::KDNode()
nuclear@26 67 {
nuclear@26 68 left = right = 0;
nuclear@32 69 cost = 0.0;
nuclear@26 70 }
nuclear@26 71
nuclear@25 72
nuclear@24 73 Scene::Scene()
nuclear@24 74 {
nuclear@24 75 facebuf = 0;
nuclear@24 76 num_faces = -1;
nuclear@24 77 kdtree = 0;
nuclear@28 78 kdbuf = 0;
nuclear@24 79 }
nuclear@24 80
nuclear@24 81 Scene::~Scene()
nuclear@24 82 {
nuclear@24 83 delete [] facebuf;
nuclear@28 84 delete [] kdbuf;
nuclear@28 85 free_kdtree(kdtree);
nuclear@24 86 }
nuclear@24 87
nuclear@13 88 bool Scene::add_mesh(Mesh *m)
nuclear@13 89 {
nuclear@13 90 // make sure triangles have material ids
nuclear@13 91 for(size_t i=0; i<m->faces.size(); i++) {
nuclear@13 92 m->faces[i].matid = m->matid;
nuclear@13 93 }
nuclear@24 94
nuclear@24 95 try {
nuclear@24 96 meshes.push_back(m);
nuclear@24 97 }
nuclear@24 98 catch(...) {
nuclear@24 99 return false;
nuclear@24 100 }
nuclear@24 101
nuclear@24 102 // invalidate facebuffer and count
nuclear@24 103 delete [] facebuf;
nuclear@24 104 facebuf = 0;
nuclear@24 105 num_faces = -1;
nuclear@24 106
nuclear@13 107 return true;
nuclear@13 108 }
nuclear@13 109
John@14 110 int Scene::get_num_meshes() const
John@14 111 {
John@14 112 return (int)meshes.size();
John@14 113 }
John@14 114
nuclear@13 115 int Scene::get_num_faces() const
nuclear@13 116 {
nuclear@24 117 if(num_faces >= 0) {
nuclear@24 118 return num_faces;
nuclear@24 119 }
nuclear@24 120
nuclear@24 121 num_faces = 0;
nuclear@13 122 for(size_t i=0; i<meshes.size(); i++) {
nuclear@13 123 num_faces += meshes[i]->faces.size();
nuclear@13 124 }
nuclear@13 125 return num_faces;
nuclear@13 126 }
nuclear@13 127
John@14 128 int Scene::get_num_materials() const
John@14 129 {
John@14 130 return (int)matlib.size();
John@14 131 }
John@14 132
nuclear@35 133 int Scene::get_num_kdnodes() const
nuclear@35 134 {
nuclear@35 135 return kdtree_nodes(kdtree);
nuclear@35 136 }
nuclear@35 137
John@14 138 Material *Scene::get_materials()
John@14 139 {
John@14 140 if(matlib.empty()) {
John@14 141 return 0;
John@14 142 }
John@14 143 return &matlib[0];
John@14 144 }
John@14 145
John@14 146 const Material *Scene::get_materials() const
John@14 147 {
John@14 148 if(matlib.empty()) {
John@14 149 return 0;
John@14 150 }
John@14 151 return &matlib[0];
John@14 152 }
nuclear@24 153
nuclear@24 154 const Face *Scene::get_face_buffer() const
nuclear@24 155 {
nuclear@24 156 if(facebuf) {
nuclear@24 157 return facebuf;
nuclear@24 158 }
nuclear@24 159
nuclear@24 160 int num_meshes = get_num_meshes();
nuclear@24 161
nuclear@24 162 printf("constructing face buffer with %d faces (out of %d meshes)\n", get_num_faces(), num_meshes);
nuclear@24 163 facebuf = new Face[num_faces];
nuclear@24 164 Face *fptr = facebuf;
nuclear@24 165
nuclear@24 166 for(int i=0; i<num_meshes; i++) {
nuclear@24 167 for(size_t j=0; j<meshes[i]->faces.size(); j++) {
nuclear@24 168 *fptr++ = meshes[i]->faces[j];
nuclear@24 169 }
nuclear@24 170 }
nuclear@24 171 return facebuf;
nuclear@24 172 }
nuclear@24 173
nuclear@35 174 static int find_node_index(const KDNode *node, const std::map<const KDNode*, int> &flatmap);
nuclear@35 175
nuclear@35 176 static bool validate_flat_tree(const KDNode *node, const KDNodeGPU *kdbuf, int count, const std::map<const KDNode*, int> &flatmap)
nuclear@35 177 {
nuclear@35 178 if(!node) return true;
nuclear@35 179
nuclear@35 180 int idx = find_node_index(node, flatmap);
nuclear@35 181 int left_idx = find_node_index(node->left, flatmap);
nuclear@35 182 int right_idx = find_node_index(node->right, flatmap);
nuclear@35 183
nuclear@35 184 if(kdbuf[idx].left != left_idx) {
nuclear@35 185 fprintf(stderr, "%d's left should be %d. it's: %d\n", idx, left_idx, kdbuf[idx].left);
nuclear@35 186 return false;
nuclear@35 187 }
nuclear@35 188 if(kdbuf[idx].right != right_idx) {
nuclear@35 189 fprintf(stderr, "%d's right should be %d. it's: %d\n", idx, right_idx, kdbuf[idx].right);
nuclear@35 190 return false;
nuclear@35 191 }
nuclear@35 192 return validate_flat_tree(node->left, kdbuf, count, flatmap) && validate_flat_tree(node->right, kdbuf, count, flatmap);
nuclear@35 193 }
nuclear@35 194
nuclear@28 195 const KDNodeGPU *Scene::get_kdtree_buffer() const
nuclear@28 196 {
nuclear@28 197 if(kdbuf) {
nuclear@28 198 return kdbuf;
nuclear@28 199 }
nuclear@28 200
nuclear@28 201 if(!kdtree) {
nuclear@28 202 ((Scene*)this)->build_kdtree();
nuclear@28 203 }
nuclear@28 204
nuclear@35 205 /* we'll associate kdnodes with flattened array indices through this map as
nuclear@35 206 * we add them so that the second child-index pass, will be able to find
nuclear@35 207 * the children indices of each node.
nuclear@35 208 */
nuclear@35 209 std::map<const KDNode*, int> flatmap;
nuclear@35 210 flatmap[0] = -1;
nuclear@28 211
nuclear@35 212 int num_nodes = get_num_kdnodes();
nuclear@35 213 kdbuf = new KDNodeGPU[num_nodes];
nuclear@35 214
nuclear@35 215 int count = 0;
nuclear@35 216
nuclear@35 217 // first arrange the kdnodes into an array (flatten)
nuclear@35 218 flatten_kdtree(kdtree, kdbuf, &count, &flatmap);
nuclear@35 219
nuclear@35 220 // then fix all the left/right links to point to the correct nodes
nuclear@35 221 fix_child_links(kdtree, kdbuf, flatmap);
nuclear@35 222
nuclear@35 223 assert(validate_flat_tree(kdtree, kdbuf, count, flatmap));
nuclear@35 224
nuclear@28 225 return kdbuf;
nuclear@28 226 }
nuclear@28 227
nuclear@35 228 static void flatten_kdtree(const KDNode *node, KDNodeGPU *kdbuf, int *count, std::map<const KDNode*, int> *flatmap)
nuclear@28 229 {
nuclear@35 230 int idx = (*count)++;
nuclear@29 231
nuclear@35 232 // copy the node
nuclear@35 233 kdbuf[idx].aabb = node->aabb;
nuclear@35 234 for(size_t i=0; i<node->face_idx.size(); i++) {
nuclear@35 235 kdbuf[idx].face_idx[i] = node->face_idx[i];
nuclear@28 236 }
nuclear@35 237 kdbuf[idx].num_faces = node->face_idx.size();
nuclear@35 238
nuclear@35 239 // update the node* -> array-position mapping
nuclear@35 240 (*flatmap)[node] = idx;
nuclear@35 241
nuclear@35 242 // recurse to the left/right (if we're not in a leaf node)
nuclear@35 243 if(node->left) {
nuclear@35 244 assert(node->right);
nuclear@35 245
nuclear@35 246 flatten_kdtree(node->left, kdbuf, count, flatmap);
nuclear@35 247 flatten_kdtree(node->right, kdbuf, count, flatmap);
nuclear@35 248 }
nuclear@28 249 }
nuclear@28 250
nuclear@35 251 static int find_node_index(const KDNode *node, const std::map<const KDNode*, int> &flatmap)
nuclear@29 252 {
nuclear@35 253 std::map<const KDNode*, int>::const_iterator it = flatmap.find(node);
nuclear@35 254 assert(it != flatmap.end());
nuclear@35 255 return it->second;
nuclear@35 256 }
nuclear@35 257
nuclear@35 258 static void fix_child_links(const KDNode *node, KDNodeGPU *kdbuf, const std::map<const KDNode*, int> &flatmap)
nuclear@35 259 {
nuclear@35 260 if(!node) return;
nuclear@35 261
nuclear@35 262 int idx = find_node_index(node, flatmap);
nuclear@35 263
nuclear@35 264 kdbuf[idx].left = find_node_index(node->left, flatmap);
nuclear@35 265 if(!node->left && kdbuf[idx].left != -1) abort();
nuclear@35 266 kdbuf[idx].right = find_node_index(node->right, flatmap);
nuclear@35 267 if(!node->right && kdbuf[idx].right != -1) abort();
nuclear@35 268
nuclear@35 269 fix_child_links(node->left, kdbuf, flatmap);
nuclear@35 270 fix_child_links(node->right, kdbuf, flatmap);
nuclear@29 271 }
nuclear@24 272
nuclear@27 273 void Scene::draw_kdtree() const
nuclear@27 274 {
nuclear@27 275 glPushAttrib(GL_ENABLE_BIT);
nuclear@27 276 glDisable(GL_LIGHTING);
nuclear@27 277 glDepthMask(0);
nuclear@27 278
nuclear@27 279 glBegin(GL_LINES);
nuclear@27 280 ::draw_kdtree(kdtree, 0);
nuclear@27 281 glEnd();
nuclear@27 282
nuclear@27 283 glDepthMask(1);
nuclear@27 284 glPopAttrib();
nuclear@27 285 }
nuclear@27 286
nuclear@27 287 static float palette[][3] = {
nuclear@27 288 {0, 1, 0},
nuclear@27 289 {1, 0, 0},
nuclear@27 290 {0, 0, 1},
nuclear@27 291 {1, 1, 0},
nuclear@27 292 {0, 0, 1},
nuclear@27 293 {1, 0, 1}
nuclear@27 294 };
nuclear@27 295 static int pal_size = sizeof palette / sizeof *palette;
nuclear@27 296
nuclear@27 297 static void draw_kdtree(const KDNode *node, int level)
nuclear@27 298 {
nuclear@27 299 if(!node) return;
nuclear@27 300
nuclear@27 301 draw_kdtree(node->left, level + 1);
nuclear@27 302 draw_kdtree(node->right, level + 1);
nuclear@27 303
nuclear@27 304 glColor3fv(palette[level % pal_size]);
nuclear@27 305
nuclear@27 306 glVertex3fv(node->aabb.min);
nuclear@27 307 glVertex3f(node->aabb.max[0], node->aabb.min[1], node->aabb.min[2]);
nuclear@27 308 glVertex3f(node->aabb.max[0], node->aabb.min[1], node->aabb.min[2]);
nuclear@27 309 glVertex3f(node->aabb.max[0], node->aabb.max[1], node->aabb.min[2]);
nuclear@27 310 glVertex3f(node->aabb.max[0], node->aabb.max[1], node->aabb.min[2]);
nuclear@27 311 glVertex3f(node->aabb.min[0], node->aabb.max[1], node->aabb.min[2]);
nuclear@27 312 glVertex3f(node->aabb.min[0], node->aabb.max[1], node->aabb.min[2]);
nuclear@27 313 glVertex3fv(node->aabb.min);
nuclear@27 314
nuclear@27 315 glVertex3f(node->aabb.min[0], node->aabb.min[1], node->aabb.max[2]);
nuclear@27 316 glVertex3f(node->aabb.max[0], node->aabb.min[1], node->aabb.max[2]);
nuclear@27 317 glVertex3f(node->aabb.max[0], node->aabb.min[1], node->aabb.max[2]);
nuclear@27 318 glVertex3fv(node->aabb.max);
nuclear@27 319 glVertex3fv(node->aabb.max);
nuclear@27 320 glVertex3f(node->aabb.min[0], node->aabb.max[1], node->aabb.max[2]);
nuclear@27 321 glVertex3f(node->aabb.min[0], node->aabb.max[1], node->aabb.max[2]);
nuclear@27 322 glVertex3f(node->aabb.min[0], node->aabb.min[1], node->aabb.max[2]);
nuclear@27 323
nuclear@27 324 glVertex3fv(node->aabb.min);
nuclear@27 325 glVertex3f(node->aabb.min[0], node->aabb.min[1], node->aabb.max[2]);
nuclear@27 326 glVertex3f(node->aabb.max[0], node->aabb.min[1], node->aabb.min[2]);
nuclear@27 327 glVertex3f(node->aabb.max[0], node->aabb.min[1], node->aabb.max[2]);
nuclear@27 328 glVertex3f(node->aabb.max[0], node->aabb.max[1], node->aabb.min[2]);
nuclear@27 329 glVertex3fv(node->aabb.max);
nuclear@27 330 glVertex3f(node->aabb.min[0], node->aabb.max[1], node->aabb.min[2]);
nuclear@27 331 glVertex3f(node->aabb.min[0], node->aabb.max[1], node->aabb.max[2]);
nuclear@34 332 /*if(!node->left) return;
nuclear@34 333
nuclear@34 334 AABBox *bleft = &node->left->aabb;
nuclear@34 335
nuclear@34 336 int axis = level % 3;
nuclear@34 337 switch(axis) {
nuclear@34 338 case 0:
nuclear@34 339 glVertex3f(bleft->max[0], bleft->min[1], bleft->min[2]);
nuclear@34 340 glVertex3f(bleft->max[0], bleft->max[1], bleft->min[2]);
nuclear@34 341 glVertex3f(bleft->max[0], bleft->max[1], bleft->min[2]);
nuclear@34 342 glVertex3f(bleft->max[0], bleft->max[1], bleft->max[2]);
nuclear@34 343 glVertex3f(bleft->max[0], bleft->max[1], bleft->max[2]);
nuclear@34 344 glVertex3f(bleft->max[0], bleft->min[1], bleft->max[2]);
nuclear@34 345 glVertex3f(bleft->max[0], bleft->min[1], bleft->max[2]);
nuclear@34 346 glVertex3f(bleft->max[0], bleft->min[1], bleft->min[2]);
nuclear@34 347 break;
nuclear@37 348
nuclear@34 349 case 1:
nuclear@34 350 glVertex3f(bleft->min[0], bleft->min[1], bleft->max[2]);
nuclear@34 351 glVertex3f(bleft->min[0], bleft->max[1], bleft->max[2]);
nuclear@34 352 glVertex3f(bleft->min[0], bleft->max[1], bleft->max[2]);
nuclear@34 353 glVertex3f(bleft->max[0], bleft->max[1], bleft->max[2]);
nuclear@34 354 glVertex3f(bleft->max[0], bleft->max[1], bleft->max[2]);
nuclear@34 355 glVertex3f(bleft->max[0], bleft->min[1], bleft->max[2]);
nuclear@34 356 glVertex3f(bleft->max[0], bleft->min[1], bleft->max[2]);
nuclear@34 357 glVertex3f(bleft->min[0], bleft->min[1], bleft->max[2]);
nuclear@34 358 break;
nuclear@37 359
nuclear@34 360 case 2:
nuclear@34 361 glVertex3f(bleft->min[0], bleft->max[1], bleft->min[2]);
nuclear@34 362 glVertex3f(bleft->max[0], bleft->max[1], bleft->min[2]);
nuclear@34 363 glVertex3f(bleft->max[0], bleft->max[1], bleft->min[2]);
nuclear@34 364 glVertex3f(bleft->max[0], bleft->max[1], bleft->max[2]);
nuclear@34 365 glVertex3f(bleft->max[0], bleft->max[1], bleft->max[2]);
nuclear@34 366 glVertex3f(bleft->min[0], bleft->max[1], bleft->max[2]);
nuclear@34 367 glVertex3f(bleft->min[0], bleft->max[1], bleft->max[2]);
nuclear@34 368 glVertex3f(bleft->min[0], bleft->max[1], bleft->min[2]);
nuclear@34 369 break;
nuclear@34 370
nuclear@34 371 default:
nuclear@34 372 break;
nuclear@34 373 }*/
nuclear@27 374 }
nuclear@27 375
nuclear@27 376 bool Scene::build_kdtree()
nuclear@24 377 {
nuclear@29 378 assert(kdtree == 0);
nuclear@29 379
nuclear@24 380 const Face *faces = get_face_buffer();
nuclear@24 381 int num_faces = get_num_faces();
nuclear@24 382
nuclear@25 383 printf("Constructing kd-tree out of %d faces ...\n", num_faces);
nuclear@25 384
nuclear@27 385 int icost = accel_param[ACCEL_PARAM_COST_INTERSECT];
nuclear@27 386 int tcost = accel_param[ACCEL_PARAM_COST_TRAVERSE];
nuclear@27 387 printf(" max items per leaf: %d\n", accel_param[ACCEL_PARAM_MAX_NODE_ITEMS]);
nuclear@27 388 printf(" SAH parameters - tcost: %d - icost: %d\n", tcost, icost);
nuclear@27 389
nuclear@25 390 free_kdtree(kdtree);
nuclear@25 391 kdtree = new KDNode;
nuclear@25 392
nuclear@25 393 /* Start the construction of the kdtree by adding all faces of the scene
nuclear@25 394 * to the new root node. At the same time calculate the root's AABB.
nuclear@25 395 */
nuclear@25 396 kdtree->aabb.min[0] = kdtree->aabb.min[1] = kdtree->aabb.min[2] = FLT_MAX;
nuclear@25 397 kdtree->aabb.max[0] = kdtree->aabb.max[1] = kdtree->aabb.max[2] = -FLT_MAX;
nuclear@25 398
nuclear@24 399 for(int i=0; i<num_faces; i++) {
nuclear@25 400 const Face *face = faces + i;
nuclear@25 401
nuclear@25 402 // for each vertex of the face ...
nuclear@25 403 for(int j=0; j<3; j++) {
nuclear@25 404 const float *pos = face->v[j].pos;
nuclear@25 405
nuclear@25 406 // for each element (xyz) of the position vector ...
nuclear@25 407 for(int k=0; k<3; k++) {
nuclear@25 408 if(pos[k] < kdtree->aabb.min[k]) {
nuclear@25 409 kdtree->aabb.min[k] = pos[k];
nuclear@25 410 }
nuclear@25 411 if(pos[k] > kdtree->aabb.max[k]) {
nuclear@25 412 kdtree->aabb.max[k] = pos[k];
nuclear@25 413 }
nuclear@25 414 }
nuclear@25 415 }
nuclear@25 416
nuclear@32 417 kdtree->face_idx.push_back(i); // add the face
nuclear@24 418 }
nuclear@24 419
nuclear@26 420 // calculate the heuristic for the root
nuclear@32 421 kdtree->cost = eval_cost(faces, &kdtree->face_idx[0], kdtree->face_idx.size(), kdtree->aabb, 0);
nuclear@26 422
nuclear@25 423 // now proceed splitting the root recursively
nuclear@32 424 if(!::build_kdtree(kdtree, faces)) {
nuclear@27 425 fprintf(stderr, "failed to build kdtree\n");
nuclear@27 426 return false;
nuclear@27 427 }
nuclear@27 428
nuclear@27 429 printf(" tree depth: %d\n", kdtree_depth(kdtree));
nuclear@27 430 print_item_counts(kdtree, 0);
nuclear@27 431 return true;
nuclear@24 432 }
nuclear@24 433
nuclear@37 434 struct Split {
nuclear@37 435 int axis;
nuclear@37 436 float pos;
nuclear@37 437 float sum_cost;
nuclear@37 438 float cost_left, cost_right;
nuclear@37 439 };
nuclear@37 440
nuclear@37 441 static void find_best_split(const KDNode *node, int axis, const Face *faces, Split *split)
nuclear@37 442 {
nuclear@37 443 Split best_split;
nuclear@37 444 best_split.sum_cost = FLT_MAX;
nuclear@37 445
nuclear@37 446 for(size_t i=0; i<node->face_idx.size(); i++) {
nuclear@37 447 const Face *face = faces + node->face_idx[i];
nuclear@37 448
nuclear@37 449 float splitpt[2];
nuclear@37 450 splitpt[0] = MIN(face->v[0].pos[axis], MIN(face->v[1].pos[axis], face->v[2].pos[axis]));
nuclear@37 451 splitpt[1] = MAX(face->v[0].pos[axis], MAX(face->v[1].pos[axis], face->v[2].pos[axis]));
nuclear@37 452
nuclear@37 453 for(int j=0; j<2; j++) {
nuclear@37 454 AABBox aabb_left, aabb_right;
nuclear@37 455 aabb_left = aabb_right = node->aabb;
nuclear@37 456 aabb_left.max[axis] = splitpt[j];
nuclear@37 457 aabb_right.min[axis] = splitpt[j];
nuclear@37 458
nuclear@37 459 float left_cost = eval_cost(faces, &node->face_idx[0], node->face_idx.size(), aabb_left, axis);
nuclear@37 460 float right_cost = eval_cost(faces, &node->face_idx[0], node->face_idx.size(), aabb_right, axis);
nuclear@37 461 float sum_cost = left_cost + right_cost - accel_param[ACCEL_PARAM_COST_TRAVERSE]; // tcost is added twice
nuclear@37 462
nuclear@37 463 if(sum_cost < best_split.sum_cost) {
nuclear@37 464 best_split.cost_left = left_cost;
nuclear@37 465 best_split.cost_right = right_cost;
nuclear@37 466 best_split.sum_cost = sum_cost;
nuclear@37 467 best_split.pos = splitpt[j];
nuclear@37 468 }
nuclear@37 469 }
nuclear@37 470 }
nuclear@37 471
nuclear@37 472 assert(split);
nuclear@37 473 *split = best_split;
nuclear@37 474 split->axis = axis;
nuclear@37 475 }
nuclear@37 476
nuclear@32 477 static bool build_kdtree(KDNode *kd, const Face *faces, int level)
nuclear@24 478 {
nuclear@28 479 int opt_max_depth = accel_param[ACCEL_PARAM_MAX_TREE_DEPTH];
nuclear@26 480 int opt_max_items = accel_param[ACCEL_PARAM_MAX_NODE_ITEMS];
nuclear@27 481
nuclear@32 482 if(kd->face_idx.empty() || level >= opt_max_depth) {
nuclear@27 483 return true;
nuclear@25 484 }
nuclear@25 485
nuclear@37 486 Split best_split;
nuclear@37 487 best_split.sum_cost = FLT_MAX;
nuclear@26 488
nuclear@37 489 for(int i=0; i<1; i++) {
nuclear@37 490 Split split;
nuclear@37 491 find_best_split(kd, i, faces, &split);
nuclear@26 492
nuclear@37 493 if(split.sum_cost < best_split.sum_cost) {
nuclear@37 494 best_split = split;
nuclear@26 495 }
nuclear@26 496 }
nuclear@26 497
nuclear@37 498 kd->axis = best_split.axis;
nuclear@37 499
nuclear@29 500 //printf("current cost: %f, best_cost: %f\n", kd->cost, best_sum_cost);
nuclear@37 501 if(best_split.sum_cost > kd->cost && (opt_max_items == 0 || (int)kd->face_idx.size() <= opt_max_items)) {
nuclear@27 502 return true; // stop splitting if it doesn't reduce the cost
nuclear@26 503 }
nuclear@26 504
nuclear@26 505 // create the two children
nuclear@26 506 KDNode *kdleft, *kdright;
nuclear@26 507 kdleft = new KDNode;
nuclear@26 508 kdright = new KDNode;
nuclear@26 509
nuclear@26 510 kdleft->aabb = kdright->aabb = kd->aabb;
nuclear@26 511
nuclear@37 512 kdleft->aabb.max[kd->axis] = best_split.pos;
nuclear@37 513 kdright->aabb.min[kd->axis] = best_split.pos;
nuclear@26 514
nuclear@37 515 kdleft->cost = best_split.cost_left;
nuclear@37 516 kdright->cost = best_split.cost_right;
nuclear@26 517
nuclear@34 518 // TODO would it be much better if we actually split faces that straddle the splitting plane?
nuclear@32 519 for(size_t i=0; i<kd->face_idx.size(); i++) {
nuclear@32 520 int fidx = kd->face_idx[i];
nuclear@32 521 const Face *face = faces + fidx;
nuclear@26 522
nuclear@37 523 if(face->v[0].pos[kd->axis] < best_split.pos ||
nuclear@37 524 face->v[1].pos[kd->axis] < best_split.pos ||
nuclear@37 525 face->v[2].pos[kd->axis] < best_split.pos) {
nuclear@32 526 kdleft->face_idx.push_back(fidx);
nuclear@26 527 }
nuclear@37 528 if(face->v[0].pos[kd->axis] >= best_split.pos ||
nuclear@37 529 face->v[1].pos[kd->axis] >= best_split.pos ||
nuclear@37 530 face->v[2].pos[kd->axis] >= best_split.pos) {
nuclear@32 531 kdright->face_idx.push_back(fidx);
nuclear@26 532 }
nuclear@26 533 }
nuclear@32 534 kd->face_idx.clear(); // only leaves have faces
nuclear@26 535
nuclear@26 536 kd->left = kdleft;
nuclear@26 537 kd->right = kdright;
nuclear@27 538
nuclear@32 539 return build_kdtree(kd->left, faces, level + 1) && build_kdtree(kd->right, faces, level + 1);
nuclear@26 540 }
nuclear@26 541
nuclear@32 542 static float eval_cost(const Face *faces, const int *face_idx, int num_faces, const AABBox &aabb, int axis)
nuclear@26 543 {
nuclear@26 544 int num_inside = 0;
nuclear@26 545 int tcost = accel_param[ACCEL_PARAM_COST_TRAVERSE];
nuclear@26 546 int icost = accel_param[ACCEL_PARAM_COST_INTERSECT];
nuclear@26 547
nuclear@32 548 for(int i=0; i<num_faces; i++) {
nuclear@32 549 const Face *face = faces + face_idx[i];
nuclear@26 550
nuclear@32 551 for(int j=0; j<3; j++) {
nuclear@32 552 if(face->v[j].pos[axis] >= aabb.min[axis] && face->v[j].pos[axis] < aabb.max[axis]) {
nuclear@26 553 num_inside++;
nuclear@26 554 break;
nuclear@26 555 }
nuclear@26 556 }
nuclear@26 557 }
nuclear@26 558
nuclear@27 559 float sarea = aabb.calc_surface_area();
nuclear@34 560 if(sarea < 1e-6) {
nuclear@27 561 return FLT_MAX; // heavily penalize 0-area voxels
nuclear@27 562 }
nuclear@27 563
nuclear@32 564 return tcost + sarea * num_inside * icost;
nuclear@24 565 }
nuclear@25 566
nuclear@25 567 static void free_kdtree(KDNode *node)
nuclear@25 568 {
nuclear@25 569 if(node) {
nuclear@25 570 free_kdtree(node->left);
nuclear@25 571 free_kdtree(node->right);
nuclear@25 572 delete node;
nuclear@25 573 }
nuclear@25 574 }
nuclear@27 575
nuclear@28 576 int kdtree_depth(const KDNode *node)
nuclear@27 577 {
nuclear@27 578 if(!node) return 0;
nuclear@27 579
nuclear@27 580 int left = kdtree_depth(node->left);
nuclear@27 581 int right = kdtree_depth(node->right);
nuclear@27 582 return (left > right ? left : right) + 1;
nuclear@27 583 }
nuclear@27 584
nuclear@28 585 int kdtree_nodes(const KDNode *node)
nuclear@28 586 {
nuclear@28 587 if(!node) return 0;
nuclear@28 588 return kdtree_nodes(node->left) + kdtree_nodes(node->right) + 1;
nuclear@28 589 }
nuclear@28 590
nuclear@27 591 static void print_item_counts(const KDNode *node, int level)
nuclear@27 592 {
nuclear@27 593 if(!node) return;
nuclear@27 594
nuclear@30 595 for(int i=0; i<level; i++) {
nuclear@27 596 fputs(" ", stdout);
nuclear@27 597 }
nuclear@32 598 printf("- %d (cost: %f)\n", (int)node->face_idx.size(), node->cost);
nuclear@27 599
nuclear@27 600 print_item_counts(node->left, level + 1);
nuclear@27 601 print_item_counts(node->right, level + 1);
nuclear@27 602 }