Blender V2.61 - r43446
|
00001 /* 00002 * 00003 * ***** BEGIN GPL LICENSE BLOCK ***** 00004 * 00005 * This program is free software; you can redistribute it and/or 00006 * modify it under the terms of the GNU General Public License 00007 * as published by the Free Software Foundation; either version 2 00008 * of the License, or (at your option) any later version. 00009 * 00010 * This program is distributed in the hope that it will be useful, 00011 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00012 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00013 * GNU General Public License for more details. 00014 * 00015 * You should have received a copy of the GNU General Public License 00016 * along with this program; if not, write to the Free Software Foundation, 00017 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 00018 * 00019 * The Original Code is Copyright (C) 2008 Blender Foundation. 00020 * All rights reserved. 00021 * 00022 * The Original Code is: all of this file. 00023 * 00024 * Contributor(s): Brecht Van Lommel. 00025 * 00026 * ***** END GPL LICENSE BLOCK ***** 00027 */ 00028 00034 #include <math.h> 00035 #include <stdio.h> 00036 #include <stdlib.h> 00037 #include <string.h> 00038 00039 #include "MEM_guardedalloc.h" 00040 00041 #include "DNA_material_types.h" 00042 00043 #include "BLI_math.h" 00044 #include "BLI_blenlib.h" 00045 #include "BLI_memarena.h" 00046 #include "BLI_threads.h" 00047 #include "BLI_utildefines.h" 00048 00049 #include "BKE_global.h" 00050 #include "BKE_scene.h" 00051 00052 00053 #include "RE_shader_ext.h" 00054 00055 /* local includes */ 00056 #include "occlusion.h" 00057 #include "render_types.h" 00058 #include "rendercore.h" 00059 #include "renderdatabase.h" 00060 #include "pixelshading.h" 00061 #include "shading.h" 00062 #include "zbuf.h" 00063 00064 /* ------------------------- Declarations --------------------------- */ 00065 00066 #define INVALID_INDEX ((int)(~0)) 00067 #define INVPI 0.31830988618379069f 00068 #define TOTCHILD 8 00069 #define CACHE_STEP 3 00070 00071 typedef struct OcclusionCacheSample { 00072 float co[3], n[3], ao[3], env[3], indirect[3], intensity, dist2; 00073 int x, y, filled; 00074 } OcclusionCacheSample; 00075 00076 typedef struct OcclusionCache { 00077 OcclusionCacheSample *sample; 00078 int x, y, w, h, step; 00079 } OcclusionCache; 00080 00081 typedef struct OccFace { 00082 int obi; 00083 int facenr; 00084 } OccFace; 00085 00086 typedef struct OccNode { 00087 float co[3], area; 00088 float sh[9], dco; 00089 float occlusion, rad[3]; 00090 int childflag; 00091 union { 00092 //OccFace face; 00093 int face; 00094 struct OccNode *node; 00095 } child[TOTCHILD]; 00096 } OccNode; 00097 00098 typedef struct OcclusionTree { 00099 MemArena *arena; 00100 00101 float (*co)[3]; /* temporary during build */ 00102 00103 OccFace *face; /* instance and face indices */ 00104 float *occlusion; /* occlusion for faces */ 00105 float (*rad)[3]; /* radiance for faces */ 00106 00107 OccNode *root; 00108 00109 OccNode **stack[BLENDER_MAX_THREADS]; 00110 int maxdepth; 00111 00112 int totface; 00113 00114 float error; 00115 float distfac; 00116 00117 int dothreadedbuild; 00118 int totbuildthread; 00119 int doindirect; 00120 00121 OcclusionCache *cache; 00122 } OcclusionTree; 00123 00124 typedef struct OcclusionThread { 00125 Render *re; 00126 StrandSurface *mesh; 00127 float (*faceao)[3]; 00128 float (*faceenv)[3]; 00129 float (*faceindirect)[3]; 00130 int begin, end; 00131 int thread; 00132 } OcclusionThread; 00133 00134 typedef struct OcclusionBuildThread { 00135 OcclusionTree *tree; 00136 int begin, end, depth; 00137 OccNode *node; 00138 } OcclusionBuildThread; 00139 00140 /* ------------------------- Shading --------------------------- */ 00141 00142 extern Render R; // meh 00143 00144 static void occ_shade(ShadeSample *ssamp, ObjectInstanceRen *obi, VlakRen *vlr, float *rad) 00145 { 00146 ShadeInput *shi= ssamp->shi; 00147 ShadeResult *shr= ssamp->shr; 00148 float l, u, v, *v1, *v2, *v3; 00149 00150 /* init */ 00151 if(vlr->v4) { 00152 shi->u= u= 0.5f; 00153 shi->v= v= 0.5f; 00154 } 00155 else { 00156 shi->u= u= 1.0f/3.0f; 00157 shi->v= v= 1.0f/3.0f; 00158 } 00159 00160 /* setup render coordinates */ 00161 v1= vlr->v1->co; 00162 v2= vlr->v2->co; 00163 v3= vlr->v3->co; 00164 00165 /* renderco */ 00166 l= 1.0f-u-v; 00167 00168 shi->co[0]= l*v3[0]+u*v1[0]+v*v2[0]; 00169 shi->co[1]= l*v3[1]+u*v1[1]+v*v2[1]; 00170 shi->co[2]= l*v3[2]+u*v1[2]+v*v2[2]; 00171 00172 shade_input_set_triangle_i(shi, obi, vlr, 0, 1, 2); 00173 00174 /* set up view vector */ 00175 copy_v3_v3(shi->view, shi->co); 00176 normalize_v3(shi->view); 00177 00178 /* cache for shadow */ 00179 shi->samplenr++; 00180 00181 shi->xs= 0; // TODO 00182 shi->ys= 0; 00183 00184 shade_input_set_normals(shi); 00185 00186 /* no normal flip */ 00187 if(shi->flippednor) 00188 shade_input_flip_normals(shi); 00189 00190 madd_v3_v3fl(shi->co, shi->vn, 0.0001f); /* ugly.. */ 00191 00192 /* not a pretty solution, but fixes common cases */ 00193 if(shi->obr->ob && shi->obr->ob->transflag & OB_NEG_SCALE) { 00194 negate_v3(shi->vn); 00195 negate_v3(shi->vno); 00196 negate_v3(shi->nmapnorm); 00197 } 00198 00199 /* init material vars */ 00200 // note, keep this synced with render_types.h 00201 memcpy(&shi->r, &shi->mat->r, 23*sizeof(float)); 00202 shi->har= shi->mat->har; 00203 00204 /* render */ 00205 shade_input_set_shade_texco(shi); 00206 shade_material_loop(shi, shr); /* todo: nodes */ 00207 00208 copy_v3_v3(rad, shr->combined); 00209 } 00210 00211 static void occ_build_shade(Render *re, OcclusionTree *tree) 00212 { 00213 ShadeSample ssamp; 00214 ObjectInstanceRen *obi; 00215 VlakRen *vlr; 00216 int a; 00217 00218 R= *re; 00219 00220 /* setup shade sample with correct passes */ 00221 memset(&ssamp, 0, sizeof(ShadeSample)); 00222 ssamp.shi[0].lay= re->lay; 00223 ssamp.shi[0].passflag= SCE_PASS_DIFFUSE|SCE_PASS_RGBA; 00224 ssamp.shi[0].combinedflag= ~(SCE_PASS_SPEC); 00225 ssamp.tot= 1; 00226 00227 for(a=0; a<tree->totface; a++) { 00228 obi= &R.objectinstance[tree->face[a].obi]; 00229 vlr= RE_findOrAddVlak(obi->obr, tree->face[a].facenr); 00230 00231 occ_shade(&ssamp, obi, vlr, tree->rad[a]); 00232 } 00233 } 00234 00235 /* ------------------------- Spherical Harmonics --------------------------- */ 00236 00237 /* Use 2nd order SH => 9 coefficients, stored in this order: 00238 0 = (0,0), 00239 1 = (1,-1), 2 = (1,0), 3 = (1,1), 00240 4 = (2,-2), 5 = (2,-1), 6 = (2,0), 7 = (2,1), 8 = (2,2) */ 00241 00242 static void sh_copy(float *shresult, float *sh) 00243 { 00244 memcpy(shresult, sh, sizeof(float)*9); 00245 } 00246 00247 static void sh_mul(float *sh, float f) 00248 { 00249 int i; 00250 00251 for(i=0; i<9; i++) 00252 sh[i] *= f; 00253 } 00254 00255 static void sh_add(float *shresult, float *sh1, float *sh2) 00256 { 00257 int i; 00258 00259 for(i=0; i<9; i++) 00260 shresult[i]= sh1[i] + sh2[i]; 00261 } 00262 00263 static void sh_from_disc(float *n, float area, float *shresult) 00264 { 00265 /* See formula (3) in: 00266 "An Efficient Representation for Irradiance Environment Maps" */ 00267 float sh[9], x, y, z; 00268 00269 x= n[0]; 00270 y= n[1]; 00271 z= n[2]; 00272 00273 sh[0]= 0.282095f; 00274 00275 sh[1]= 0.488603f*y; 00276 sh[2]= 0.488603f*z; 00277 sh[3]= 0.488603f*x; 00278 00279 sh[4]= 1.092548f*x*y; 00280 sh[5]= 1.092548f*y*z; 00281 sh[6]= 0.315392f*(3.0f*z*z - 1.0f); 00282 sh[7]= 1.092548f*x*z; 00283 sh[8]= 0.546274f*(x*x - y*y); 00284 00285 sh_mul(sh, area); 00286 sh_copy(shresult, sh); 00287 } 00288 00289 static float sh_eval(float *sh, float *v) 00290 { 00291 /* See formula (13) in: 00292 "An Efficient Representation for Irradiance Environment Maps" */ 00293 static const float c1 = 0.429043f, c2 = 0.511664f, c3 = 0.743125f; 00294 static const float c4 = 0.886227f, c5 = 0.247708f; 00295 float x, y, z, sum; 00296 00297 x= v[0]; 00298 y= v[1]; 00299 z= v[2]; 00300 00301 sum= c1*sh[8]*(x*x - y*y); 00302 sum += c3*sh[6]*z*z; 00303 sum += c4*sh[0]; 00304 sum += -c5*sh[6]; 00305 sum += 2.0f*c1*(sh[4]*x*y + sh[7]*x*z + sh[5]*y*z); 00306 sum += 2.0f*c2*(sh[3]*x + sh[1]*y + sh[2]*z); 00307 00308 return sum; 00309 } 00310 00311 /* ------------------------------ Building --------------------------------- */ 00312 00313 static void occ_face(const OccFace *face, float co[3], float normal[3], float *area) 00314 { 00315 ObjectInstanceRen *obi; 00316 VlakRen *vlr; 00317 float v1[3], v2[3], v3[3], v4[3]; 00318 00319 obi= &R.objectinstance[face->obi]; 00320 vlr= RE_findOrAddVlak(obi->obr, face->facenr); 00321 00322 if(co) { 00323 if(vlr->v4) 00324 mid_v3_v3v3(co, vlr->v1->co, vlr->v3->co); 00325 else 00326 cent_tri_v3(co, vlr->v1->co, vlr->v2->co, vlr->v3->co); 00327 00328 if(obi->flag & R_TRANSFORMED) 00329 mul_m4_v3(obi->mat, co); 00330 } 00331 00332 if(normal) { 00333 normal[0]= -vlr->n[0]; 00334 normal[1]= -vlr->n[1]; 00335 normal[2]= -vlr->n[2]; 00336 00337 if(obi->flag & R_TRANSFORMED) 00338 mul_m3_v3(obi->nmat, normal); 00339 } 00340 00341 if(area) { 00342 copy_v3_v3(v1, vlr->v1->co); 00343 copy_v3_v3(v2, vlr->v2->co); 00344 copy_v3_v3(v3, vlr->v3->co); 00345 if(vlr->v4) copy_v3_v3(v4, vlr->v4->co); 00346 00347 if(obi->flag & R_TRANSFORMED) { 00348 mul_m4_v3(obi->mat, v1); 00349 mul_m4_v3(obi->mat, v2); 00350 mul_m4_v3(obi->mat, v3); 00351 if(vlr->v4) mul_m4_v3(obi->mat, v4); 00352 } 00353 00354 /* todo: correct area for instances */ 00355 if(vlr->v4) 00356 *area= area_quad_v3(v1, v2, v3, v4); 00357 else 00358 *area= area_tri_v3(v1, v2, v3); 00359 } 00360 } 00361 00362 static void occ_sum_occlusion(OcclusionTree *tree, OccNode *node) 00363 { 00364 OccNode *child; 00365 float occ, area, totarea, rad[3]; 00366 int a, b, indirect= tree->doindirect; 00367 00368 occ= 0.0f; 00369 totarea= 0.0f; 00370 if(indirect) zero_v3(rad); 00371 00372 for(b=0; b<TOTCHILD; b++) { 00373 if(node->childflag & (1<<b)) { 00374 a= node->child[b].face; 00375 occ_face(&tree->face[a], 0, 0, &area); 00376 occ += area*tree->occlusion[a]; 00377 if(indirect) madd_v3_v3fl(rad, tree->rad[a], area); 00378 totarea += area; 00379 } 00380 else if(node->child[b].node) { 00381 child= node->child[b].node; 00382 occ_sum_occlusion(tree, child); 00383 00384 occ += child->area*child->occlusion; 00385 if(indirect) madd_v3_v3fl(rad, child->rad, child->area); 00386 totarea += child->area; 00387 } 00388 } 00389 00390 if(totarea != 0.0f) { 00391 occ /= totarea; 00392 if(indirect) mul_v3_fl(rad, 1.0f/totarea); 00393 } 00394 00395 node->occlusion= occ; 00396 if(indirect) copy_v3_v3(node->rad, rad); 00397 } 00398 00399 static int occ_find_bbox_axis(OcclusionTree *tree, int begin, int end, float *min, float *max) 00400 { 00401 float len, maxlen= -1.0f; 00402 int a, axis = 0; 00403 00404 INIT_MINMAX(min, max); 00405 00406 for(a=begin; a<end; a++) 00407 DO_MINMAX(tree->co[a], min, max) 00408 00409 for(a=0; a<3; a++) { 00410 len= max[a] - min[a]; 00411 00412 if(len > maxlen) { 00413 maxlen= len; 00414 axis= a; 00415 } 00416 } 00417 00418 return axis; 00419 } 00420 00421 static void occ_node_from_face(OccFace *face, OccNode *node) 00422 { 00423 float n[3]; 00424 00425 occ_face(face, node->co, n, &node->area); 00426 node->dco= 0.0f; 00427 sh_from_disc(n, node->area, node->sh); 00428 } 00429 00430 static void occ_build_dco(OcclusionTree *tree, OccNode *node, const float co[3], float *dco) 00431 { 00432 int b; 00433 for(b=0; b<TOTCHILD; b++) { 00434 float dist, d[3], nco[3]; 00435 00436 if(node->childflag & (1<<b)) { 00437 occ_face(tree->face+node->child[b].face, nco, NULL, NULL); 00438 } 00439 else if(node->child[b].node) { 00440 OccNode *child= node->child[b].node; 00441 occ_build_dco(tree, child, co, dco); 00442 copy_v3_v3(nco, child->co); 00443 } 00444 else { 00445 continue; 00446 } 00447 00448 sub_v3_v3v3(d, nco, co); 00449 dist= dot_v3v3(d, d); 00450 if(dist > *dco) 00451 *dco= dist; 00452 } 00453 } 00454 00455 static void occ_build_split(OcclusionTree *tree, int begin, int end, int *split) 00456 { 00457 float min[3], max[3], mid; 00458 int axis, a, enda; 00459 00460 /* split in middle of boundbox. this seems faster than median split 00461 * on complex scenes, possibly since it avoids two distant faces to 00462 * be in the same node better? */ 00463 axis= occ_find_bbox_axis(tree, begin, end, min, max); 00464 mid= 0.5f*(min[axis]+max[axis]); 00465 00466 a= begin; 00467 enda= end; 00468 while(a<enda) { 00469 if(tree->co[a][axis] > mid) { 00470 enda--; 00471 SWAP(OccFace, tree->face[a], tree->face[enda]); 00472 SWAP(float, tree->co[a][0], tree->co[enda][0]); 00473 SWAP(float, tree->co[a][1], tree->co[enda][1]); 00474 SWAP(float, tree->co[a][2], tree->co[enda][2]); 00475 } 00476 else 00477 a++; 00478 } 00479 00480 *split= enda; 00481 } 00482 00483 static void occ_build_8_split(OcclusionTree *tree, int begin, int end, int *offset, int *count) 00484 { 00485 /* split faces into eight groups */ 00486 int b, splitx, splity[2], splitz[4]; 00487 00488 occ_build_split(tree, begin, end, &splitx); 00489 00490 /* force split if none found, to deal with degenerate geometry */ 00491 if(splitx == begin || splitx == end) 00492 splitx= (begin+end)/2; 00493 00494 occ_build_split(tree, begin, splitx, &splity[0]); 00495 occ_build_split(tree, splitx, end, &splity[1]); 00496 00497 occ_build_split(tree, begin, splity[0], &splitz[0]); 00498 occ_build_split(tree, splity[0], splitx, &splitz[1]); 00499 occ_build_split(tree, splitx, splity[1], &splitz[2]); 00500 occ_build_split(tree, splity[1], end, &splitz[3]); 00501 00502 offset[0]= begin; 00503 offset[1]= splitz[0]; 00504 offset[2]= splity[0]; 00505 offset[3]= splitz[1]; 00506 offset[4]= splitx; 00507 offset[5]= splitz[2]; 00508 offset[6]= splity[1]; 00509 offset[7]= splitz[3]; 00510 00511 for(b=0; b<7; b++) 00512 count[b]= offset[b+1] - offset[b]; 00513 count[7]= end - offset[7]; 00514 } 00515 00516 static void occ_build_recursive(OcclusionTree *tree, OccNode *node, int begin, int end, int depth); 00517 00518 static void *exec_occ_build(void *data) 00519 { 00520 OcclusionBuildThread *othread= (OcclusionBuildThread*)data; 00521 00522 occ_build_recursive(othread->tree, othread->node, othread->begin, othread->end, othread->depth); 00523 00524 return 0; 00525 } 00526 00527 static void occ_build_recursive(OcclusionTree *tree, OccNode *node, int begin, int end, int depth) 00528 { 00529 ListBase threads; 00530 OcclusionBuildThread othreads[BLENDER_MAX_THREADS]; 00531 OccNode *child, tmpnode; 00532 /* OccFace *face; */ 00533 int a, b, totthread=0, offset[TOTCHILD], count[TOTCHILD]; 00534 00535 /* add a new node */ 00536 node->occlusion= 1.0f; 00537 00538 /* leaf node with only children */ 00539 if(end - begin <= TOTCHILD) { 00540 for(a=begin, b=0; a<end; a++, b++) { 00541 /* face= &tree->face[a]; */ 00542 node->child[b].face= a; 00543 node->childflag |= (1<<b); 00544 } 00545 } 00546 else { 00547 /* order faces */ 00548 occ_build_8_split(tree, begin, end, offset, count); 00549 00550 if(depth == 1 && tree->dothreadedbuild) 00551 BLI_init_threads(&threads, exec_occ_build, tree->totbuildthread); 00552 00553 for(b=0; b<TOTCHILD; b++) { 00554 if(count[b] == 0) { 00555 node->child[b].node= NULL; 00556 } 00557 else if(count[b] == 1) { 00558 /* face= &tree->face[offset[b]]; */ 00559 node->child[b].face= offset[b]; 00560 node->childflag |= (1<<b); 00561 } 00562 else { 00563 if(tree->dothreadedbuild) 00564 BLI_lock_thread(LOCK_CUSTOM1); 00565 00566 child= BLI_memarena_alloc(tree->arena, sizeof(OccNode)); 00567 node->child[b].node= child; 00568 00569 /* keep track of maximum depth for stack */ 00570 if(depth+1 > tree->maxdepth) 00571 tree->maxdepth= depth+1; 00572 00573 if(tree->dothreadedbuild) 00574 BLI_unlock_thread(LOCK_CUSTOM1); 00575 00576 if(depth == 1 && tree->dothreadedbuild) { 00577 othreads[totthread].tree= tree; 00578 othreads[totthread].node= child; 00579 othreads[totthread].begin= offset[b]; 00580 othreads[totthread].end= offset[b]+count[b]; 00581 othreads[totthread].depth= depth+1; 00582 BLI_insert_thread(&threads, &othreads[totthread]); 00583 totthread++; 00584 } 00585 else 00586 occ_build_recursive(tree, child, offset[b], offset[b]+count[b], depth+1); 00587 } 00588 } 00589 00590 if(depth == 1 && tree->dothreadedbuild) 00591 BLI_end_threads(&threads); 00592 } 00593 00594 /* combine area, position and sh */ 00595 for(b=0; b<TOTCHILD; b++) { 00596 if(node->childflag & (1<<b)) { 00597 child= &tmpnode; 00598 occ_node_from_face(tree->face+node->child[b].face, &tmpnode); 00599 } 00600 else { 00601 child= node->child[b].node; 00602 } 00603 00604 if(child) { 00605 node->area += child->area; 00606 sh_add(node->sh, node->sh, child->sh); 00607 madd_v3_v3fl(node->co, child->co, child->area); 00608 } 00609 } 00610 00611 if(node->area != 0.0f) 00612 mul_v3_fl(node->co, 1.0f/node->area); 00613 00614 /* compute maximum distance from center */ 00615 node->dco= 0.0f; 00616 if(node->area > 0.0f) 00617 occ_build_dco(tree, node, node->co, &node->dco); 00618 } 00619 00620 static void occ_build_sh_normalize(OccNode *node) 00621 { 00622 /* normalize spherical harmonics to not include area, so 00623 * we can clamp the dot product and then mutliply by area */ 00624 int b; 00625 00626 if(node->area != 0.0f) 00627 sh_mul(node->sh, 1.0f/node->area); 00628 00629 for(b=0; b<TOTCHILD; b++) { 00630 if(node->childflag & (1<<b)); 00631 else if(node->child[b].node) 00632 occ_build_sh_normalize(node->child[b].node); 00633 } 00634 } 00635 00636 static OcclusionTree *occ_tree_build(Render *re) 00637 { 00638 OcclusionTree *tree; 00639 ObjectInstanceRen *obi; 00640 ObjectRen *obr; 00641 Material *ma; 00642 VlakRen *vlr= NULL; 00643 int a, b, c, totface; 00644 00645 /* count */ 00646 totface= 0; 00647 for(obi=re->instancetable.first; obi; obi=obi->next) { 00648 obr= obi->obr; 00649 for(a=0; a<obr->totvlak; a++) { 00650 if((a & 255)==0) vlr= obr->vlaknodes[a>>8].vlak; 00651 else vlr++; 00652 00653 ma= vlr->mat; 00654 00655 if((ma->shade_flag & MA_APPROX_OCCLUSION) && (ma->material_type == MA_TYPE_SURFACE)) 00656 totface++; 00657 } 00658 } 00659 00660 if(totface == 0) 00661 return NULL; 00662 00663 tree= MEM_callocN(sizeof(OcclusionTree), "OcclusionTree"); 00664 tree->totface= totface; 00665 00666 /* parameters */ 00667 tree->error= get_render_aosss_error(&re->r, re->wrld.ao_approx_error); 00668 tree->distfac= (re->wrld.aomode & WO_AODIST)? re->wrld.aodistfac: 0.0f; 00669 tree->doindirect= (re->wrld.ao_indirect_energy > 0.0f && re->wrld.ao_indirect_bounces > 0); 00670 00671 /* allocation */ 00672 tree->arena= BLI_memarena_new(0x8000 * sizeof(OccNode), "occ tree arena"); 00673 BLI_memarena_use_calloc(tree->arena); 00674 00675 if(re->wrld.aomode & WO_AOCACHE) 00676 tree->cache= MEM_callocN(sizeof(OcclusionCache)*BLENDER_MAX_THREADS, "OcclusionCache"); 00677 00678 tree->face= MEM_callocN(sizeof(OccFace)*totface, "OcclusionFace"); 00679 tree->co= MEM_callocN(sizeof(float)*3*totface, "OcclusionCo"); 00680 tree->occlusion= MEM_callocN(sizeof(float)*totface, "OcclusionOcclusion"); 00681 00682 if(tree->doindirect) 00683 tree->rad= MEM_callocN(sizeof(float)*3*totface, "OcclusionRad"); 00684 00685 /* make array of face pointers */ 00686 for(b=0, c=0, obi=re->instancetable.first; obi; obi=obi->next, c++) { 00687 obr= obi->obr; 00688 for(a=0; a<obr->totvlak; a++) { 00689 if((a & 255)==0) vlr= obr->vlaknodes[a>>8].vlak; 00690 else vlr++; 00691 00692 ma= vlr->mat; 00693 00694 if((ma->shade_flag & MA_APPROX_OCCLUSION) && (ma->material_type == MA_TYPE_SURFACE)) { 00695 tree->face[b].obi= c; 00696 tree->face[b].facenr= a; 00697 tree->occlusion[b]= 1.0f; 00698 occ_face(&tree->face[b], tree->co[b], NULL, NULL); 00699 b++; 00700 } 00701 } 00702 } 00703 00704 /* threads */ 00705 tree->totbuildthread= (re->r.threads > 1 && totface > 10000)? 8: 1; 00706 tree->dothreadedbuild= (tree->totbuildthread > 1); 00707 00708 /* recurse */ 00709 tree->root= BLI_memarena_alloc(tree->arena, sizeof(OccNode)); 00710 tree->maxdepth= 1; 00711 occ_build_recursive(tree, tree->root, 0, totface, 1); 00712 00713 if(tree->doindirect) { 00714 occ_build_shade(re, tree); 00715 occ_sum_occlusion(tree, tree->root); 00716 } 00717 00718 MEM_freeN(tree->co); 00719 tree->co= NULL; 00720 00721 occ_build_sh_normalize(tree->root); 00722 00723 for(a=0; a<BLENDER_MAX_THREADS; a++) 00724 tree->stack[a]= MEM_callocN(sizeof(OccNode)*TOTCHILD*(tree->maxdepth+1), "OccStack"); 00725 00726 return tree; 00727 } 00728 00729 static void occ_free_tree(OcclusionTree *tree) 00730 { 00731 int a; 00732 00733 if(tree) { 00734 if(tree->arena) BLI_memarena_free(tree->arena); 00735 for(a=0; a<BLENDER_MAX_THREADS; a++) 00736 if(tree->stack[a]) 00737 MEM_freeN(tree->stack[a]); 00738 if(tree->occlusion) MEM_freeN(tree->occlusion); 00739 if(tree->cache) MEM_freeN(tree->cache); 00740 if(tree->face) MEM_freeN(tree->face); 00741 if(tree->rad) MEM_freeN(tree->rad); 00742 MEM_freeN(tree); 00743 } 00744 } 00745 00746 /* ------------------------- Traversal --------------------------- */ 00747 00748 static float occ_solid_angle(OccNode *node, const float v[3], float d2, float invd2, const float receivenormal[3]) 00749 { 00750 float dotreceive, dotemit; 00751 float ev[3]; 00752 00753 ev[0]= -v[0]*invd2; 00754 ev[1]= -v[1]*invd2; 00755 ev[2]= -v[2]*invd2; 00756 dotemit= sh_eval(node->sh, ev); 00757 dotreceive= dot_v3v3(receivenormal, v)*invd2; 00758 00759 CLAMP(dotemit, 0.0f, 1.0f); 00760 CLAMP(dotreceive, 0.0f, 1.0f); 00761 00762 return ((node->area*dotemit*dotreceive)/(d2 + node->area*INVPI))*INVPI; 00763 } 00764 00765 static void VecAddDir(float result[3], const float v1[3], const float v2[3], const float fac) 00766 { 00767 result[0]= v1[0] + fac*(v2[0] - v1[0]); 00768 result[1]= v1[1] + fac*(v2[1] - v1[1]); 00769 result[2]= v1[2] + fac*(v2[2] - v1[2]); 00770 } 00771 00772 static int occ_visible_quad(float *p, const float n[3], const float v0[3], const float *v1, const float *v2, float q0[3], float q1[3], float q2[3], float q3[3]) 00773 { 00774 static const float epsilon = 1e-6f; 00775 float c, sd[3]; 00776 00777 c= dot_v3v3(n, p); 00778 00779 /* signed distances from the vertices to the plane. */ 00780 sd[0]= dot_v3v3(n, v0) - c; 00781 sd[1]= dot_v3v3(n, v1) - c; 00782 sd[2]= dot_v3v3(n, v2) - c; 00783 00784 if(fabsf(sd[0]) < epsilon) sd[0] = 0.0f; 00785 if(fabsf(sd[1]) < epsilon) sd[1] = 0.0f; 00786 if(fabsf(sd[2]) < epsilon) sd[2] = 0.0f; 00787 00788 if(sd[0] > 0) { 00789 if(sd[1] > 0) { 00790 if(sd[2] > 0) { 00791 // +++ 00792 copy_v3_v3(q0, v0); 00793 copy_v3_v3(q1, v1); 00794 copy_v3_v3(q2, v2); 00795 copy_v3_v3(q3, q2); 00796 } 00797 else if(sd[2] < 0) { 00798 // ++- 00799 copy_v3_v3(q0, v0); 00800 copy_v3_v3(q1, v1); 00801 VecAddDir(q2, v1, v2, (sd[1]/(sd[1]-sd[2]))); 00802 VecAddDir(q3, v0, v2, (sd[0]/(sd[0]-sd[2]))); 00803 } 00804 else { 00805 // ++0 00806 copy_v3_v3(q0, v0); 00807 copy_v3_v3(q1, v1); 00808 copy_v3_v3(q2, v2); 00809 copy_v3_v3(q3, q2); 00810 } 00811 } 00812 else if(sd[1] < 0) { 00813 if(sd[2] > 0) { 00814 // +-+ 00815 copy_v3_v3(q0, v0); 00816 VecAddDir(q1, v0, v1, (sd[0]/(sd[0]-sd[1]))); 00817 VecAddDir(q2, v1, v2, (sd[1]/(sd[1]-sd[2]))); 00818 copy_v3_v3(q3, v2); 00819 } 00820 else if(sd[2] < 0) { 00821 // +-- 00822 copy_v3_v3(q0, v0); 00823 VecAddDir(q1, v0, v1, (sd[0]/(sd[0]-sd[1]))); 00824 VecAddDir(q2, v0, v2, (sd[0]/(sd[0]-sd[2]))); 00825 copy_v3_v3(q3, q2); 00826 } 00827 else { 00828 // +-0 00829 copy_v3_v3(q0, v0); 00830 VecAddDir(q1, v0, v1, (sd[0]/(sd[0]-sd[1]))); 00831 copy_v3_v3(q2, v2); 00832 copy_v3_v3(q3, q2); 00833 } 00834 } 00835 else { 00836 if(sd[2] > 0) { 00837 // +0+ 00838 copy_v3_v3(q0, v0); 00839 copy_v3_v3(q1, v1); 00840 copy_v3_v3(q2, v2); 00841 copy_v3_v3(q3, q2); 00842 } 00843 else if(sd[2] < 0) { 00844 // +0- 00845 copy_v3_v3(q0, v0); 00846 copy_v3_v3(q1, v1); 00847 VecAddDir(q2, v0, v2, (sd[0]/(sd[0]-sd[2]))); 00848 copy_v3_v3(q3, q2); 00849 } 00850 else { 00851 // +00 00852 copy_v3_v3(q0, v0); 00853 copy_v3_v3(q1, v1); 00854 copy_v3_v3(q2, v2); 00855 copy_v3_v3(q3, q2); 00856 } 00857 } 00858 } 00859 else if(sd[0] < 0) { 00860 if(sd[1] > 0) { 00861 if(sd[2] > 0) { 00862 // -++ 00863 VecAddDir(q0, v0, v1, (sd[0]/(sd[0]-sd[1]))); 00864 copy_v3_v3(q1, v1); 00865 copy_v3_v3(q2, v2); 00866 VecAddDir(q3, v0, v2, (sd[0]/(sd[0]-sd[2]))); 00867 } 00868 else if(sd[2] < 0) { 00869 // -+- 00870 VecAddDir(q0, v0, v1, (sd[0]/(sd[0]-sd[1]))); 00871 copy_v3_v3(q1, v1); 00872 VecAddDir(q2, v1, v2, (sd[1]/(sd[1]-sd[2]))); 00873 copy_v3_v3(q3, q2); 00874 } 00875 else { 00876 // -+0 00877 VecAddDir(q0, v0, v1, (sd[0]/(sd[0]-sd[1]))); 00878 copy_v3_v3(q1, v1); 00879 copy_v3_v3(q2, v2); 00880 copy_v3_v3(q3, q2); 00881 } 00882 } 00883 else if(sd[1] < 0) { 00884 if(sd[2] > 0) { 00885 // --+ 00886 VecAddDir(q0, v0, v2, (sd[0]/(sd[0]-sd[2]))); 00887 VecAddDir(q1, v1, v2, (sd[1]/(sd[1]-sd[2]))); 00888 copy_v3_v3(q2, v2); 00889 copy_v3_v3(q3, q2); 00890 } 00891 else if(sd[2] < 0) { 00892 // --- 00893 return 0; 00894 } 00895 else { 00896 // --0 00897 return 0; 00898 } 00899 } 00900 else { 00901 if(sd[2] > 0) { 00902 // -0+ 00903 VecAddDir(q0, v0, v2, (sd[0]/(sd[0]-sd[2]))); 00904 copy_v3_v3(q1, v1); 00905 copy_v3_v3(q2, v2); 00906 copy_v3_v3(q3, q2); 00907 } 00908 else if(sd[2] < 0) { 00909 // -0- 00910 return 0; 00911 } 00912 else { 00913 // -00 00914 return 0; 00915 } 00916 } 00917 } 00918 else { 00919 if(sd[1] > 0) { 00920 if(sd[2] > 0) { 00921 // 0++ 00922 copy_v3_v3(q0, v0); 00923 copy_v3_v3(q1, v1); 00924 copy_v3_v3(q2, v2); 00925 copy_v3_v3(q3, q2); 00926 } 00927 else if(sd[2] < 0) { 00928 // 0+- 00929 copy_v3_v3(q0, v0); 00930 copy_v3_v3(q1, v1); 00931 VecAddDir(q2, v1, v2, (sd[1]/(sd[1]-sd[2]))); 00932 copy_v3_v3(q3, q2); 00933 } 00934 else { 00935 // 0+0 00936 copy_v3_v3(q0, v0); 00937 copy_v3_v3(q1, v1); 00938 copy_v3_v3(q2, v2); 00939 copy_v3_v3(q3, q2); 00940 } 00941 } 00942 else if(sd[1] < 0) { 00943 if(sd[2] > 0) { 00944 // 0-+ 00945 copy_v3_v3(q0, v0); 00946 VecAddDir(q1, v1, v2, (sd[1]/(sd[1]-sd[2]))); 00947 copy_v3_v3(q2, v2); 00948 copy_v3_v3(q3, q2); 00949 } 00950 else if(sd[2] < 0) { 00951 // 0-- 00952 return 0; 00953 } 00954 else { 00955 // 0-0 00956 return 0; 00957 } 00958 } 00959 else { 00960 if(sd[2] > 0) { 00961 // 00+ 00962 copy_v3_v3(q0, v0); 00963 copy_v3_v3(q1, v1); 00964 copy_v3_v3(q2, v2); 00965 copy_v3_v3(q3, q2); 00966 } 00967 else if(sd[2] < 0) { 00968 // 00- 00969 return 0; 00970 } 00971 else { 00972 // 000 00973 return 0; 00974 } 00975 } 00976 } 00977 00978 return 1; 00979 } 00980 00981 /* altivec optimization, this works, but is unused */ 00982 00983 #if 0 00984 #include <Accelerate/Accelerate.h> 00985 00986 typedef union { 00987 vFloat v; 00988 float f[4]; 00989 } vFloatResult; 00990 00991 static vFloat vec_splat_float(float val) 00992 { 00993 return (vFloat){val, val, val, val}; 00994 } 00995 00996 static float occ_quad_form_factor(float *p, float *n, float *q0, float *q1, float *q2, float *q3) 00997 { 00998 vFloat vcos, rlen, vrx, vry, vrz, vsrx, vsry, vsrz, gx, gy, gz, vangle; 00999 vUInt8 rotate = (vUInt8){4,5,6,7,8,9,10,11,12,13,14,15,0,1,2,3}; 01000 vFloatResult vresult; 01001 float result; 01002 01003 /* compute r* */ 01004 vrx = (vFloat){q0[0], q1[0], q2[0], q3[0]} - vec_splat_float(p[0]); 01005 vry = (vFloat){q0[1], q1[1], q2[1], q3[1]} - vec_splat_float(p[1]); 01006 vrz = (vFloat){q0[2], q1[2], q2[2], q3[2]} - vec_splat_float(p[2]); 01007 01008 /* normalize r* */ 01009 rlen = vec_rsqrte(vrx*vrx + vry*vry + vrz*vrz + vec_splat_float(1e-16f)); 01010 vrx = vrx*rlen; 01011 vry = vry*rlen; 01012 vrz = vrz*rlen; 01013 01014 /* rotate r* for cross and dot */ 01015 vsrx= vec_perm(vrx, vrx, rotate); 01016 vsry= vec_perm(vry, vry, rotate); 01017 vsrz= vec_perm(vrz, vrz, rotate); 01018 01019 /* cross product */ 01020 gx = vsry*vrz - vsrz*vry; 01021 gy = vsrz*vrx - vsrx*vrz; 01022 gz = vsrx*vry - vsry*vrx; 01023 01024 /* normalize */ 01025 rlen = vec_rsqrte(gx*gx + gy*gy + gz*gz + vec_splat_float(1e-16f)); 01026 gx = gx*rlen; 01027 gy = gy*rlen; 01028 gz = gz*rlen; 01029 01030 /* angle */ 01031 vcos = vrx*vsrx + vry*vsry + vrz*vsrz; 01032 vcos= vec_max(vec_min(vcos, vec_splat_float(1.0f)), vec_splat_float(-1.0f)); 01033 vangle= vacosf(vcos); 01034 01035 /* dot */ 01036 vresult.v = (vec_splat_float(n[0])*gx + 01037 vec_splat_float(n[1])*gy + 01038 vec_splat_float(n[2])*gz)*vangle; 01039 01040 result= (vresult.f[0] + vresult.f[1] + vresult.f[2] + vresult.f[3])*(0.5f/(float)M_PI); 01041 result= MAX2(result, 0.0f); 01042 01043 return result; 01044 } 01045 01046 #endif 01047 01048 /* SSE optimization, acos code doesn't work */ 01049 01050 #if 0 01051 01052 #include <xmmintrin.h> 01053 01054 static __m128 sse_approx_acos(__m128 x) 01055 { 01056 /* needs a better approximation than taylor expansion of acos, since that 01057 * gives big erros for near 1.0 values, sqrt(2*x)*acos(1-x) should work 01058 * better, see http://www.tom.womack.net/projects/sse-fast-arctrig.html */ 01059 01060 return _mm_set_ps1(1.0f); 01061 } 01062 01063 static float occ_quad_form_factor(float *p, float *n, float *q0, float *q1, float *q2, float *q3) 01064 { 01065 float r0[3], r1[3], r2[3], r3[3], g0[3], g1[3], g2[3], g3[3]; 01066 float a1, a2, a3, a4, dot1, dot2, dot3, dot4, result; 01067 float fresult[4] __attribute__((aligned(16))); 01068 __m128 qx, qy, qz, rx, ry, rz, rlen, srx, sry, srz, gx, gy, gz, glen, rcos, angle, aresult; 01069 01070 /* compute r */ 01071 qx = _mm_set_ps(q3[0], q2[0], q1[0], q0[0]); 01072 qy = _mm_set_ps(q3[1], q2[1], q1[1], q0[1]); 01073 qz = _mm_set_ps(q3[2], q2[2], q1[2], q0[2]); 01074 01075 rx = qx - _mm_set_ps1(p[0]); 01076 ry = qy - _mm_set_ps1(p[1]); 01077 rz = qz - _mm_set_ps1(p[2]); 01078 01079 /* normalize r */ 01080 rlen = _mm_rsqrt_ps(rx*rx + ry*ry + rz*rz + _mm_set_ps1(1e-16f)); 01081 rx = rx*rlen; 01082 ry = ry*rlen; 01083 rz = rz*rlen; 01084 01085 /* cross product */ 01086 srx = _mm_shuffle_ps(rx, rx, _MM_SHUFFLE(0,3,2,1)); 01087 sry = _mm_shuffle_ps(ry, ry, _MM_SHUFFLE(0,3,2,1)); 01088 srz = _mm_shuffle_ps(rz, rz, _MM_SHUFFLE(0,3,2,1)); 01089 01090 gx = sry*rz - srz*ry; 01091 gy = srz*rx - srx*rz; 01092 gz = srx*ry - sry*rx; 01093 01094 /* normalize g */ 01095 glen = _mm_rsqrt_ps(gx*gx + gy*gy + gz*gz + _mm_set_ps1(1e-16f)); 01096 gx = gx*glen; 01097 gy = gy*glen; 01098 gz = gz*glen; 01099 01100 /* compute angle */ 01101 rcos = rx*srx + ry*sry + rz*srz; 01102 rcos= _mm_max_ps(_mm_min_ps(rcos, _mm_set_ps1(1.0f)), _mm_set_ps1(-1.0f)); 01103 01104 angle = sse_approx_cos(rcos); 01105 aresult = (_mm_set_ps1(n[0])*gx + _mm_set_ps1(n[1])*gy + _mm_set_ps1(n[2])*gz)*angle; 01106 01107 /* sum together */ 01108 result= (fresult[0] + fresult[1] + fresult[2] + fresult[3])*(0.5f/(float)M_PI); 01109 result= MAX2(result, 0.0f); 01110 01111 return result; 01112 } 01113 01114 #endif 01115 01116 static void normalizef(float *n) 01117 { 01118 float d; 01119 01120 d= dot_v3v3(n, n); 01121 01122 if(d > 1.0e-35F) { 01123 d= 1.0f/sqrtf(d); 01124 01125 n[0] *= d; 01126 n[1] *= d; 01127 n[2] *= d; 01128 } 01129 } 01130 01131 static float occ_quad_form_factor(const float p[3], const float n[3], const float q0[3], const float q1[3], const float q2[3], const float q3[3]) 01132 { 01133 float r0[3], r1[3], r2[3], r3[3], g0[3], g1[3], g2[3], g3[3]; 01134 float a1, a2, a3, a4, dot1, dot2, dot3, dot4, result; 01135 01136 sub_v3_v3v3(r0, q0, p); 01137 sub_v3_v3v3(r1, q1, p); 01138 sub_v3_v3v3(r2, q2, p); 01139 sub_v3_v3v3(r3, q3, p); 01140 01141 normalizef(r0); 01142 normalizef(r1); 01143 normalizef(r2); 01144 normalizef(r3); 01145 01146 cross_v3_v3v3(g0, r1, r0); normalizef(g0); 01147 cross_v3_v3v3(g1, r2, r1); normalizef(g1); 01148 cross_v3_v3v3(g2, r3, r2); normalizef(g2); 01149 cross_v3_v3v3(g3, r0, r3); normalizef(g3); 01150 01151 a1= saacosf(dot_v3v3(r0, r1)); 01152 a2= saacosf(dot_v3v3(r1, r2)); 01153 a3= saacosf(dot_v3v3(r2, r3)); 01154 a4= saacosf(dot_v3v3(r3, r0)); 01155 01156 dot1= dot_v3v3(n, g0); 01157 dot2= dot_v3v3(n, g1); 01158 dot3= dot_v3v3(n, g2); 01159 dot4= dot_v3v3(n, g3); 01160 01161 result= (a1*dot1 + a2*dot2 + a3*dot3 + a4*dot4)*0.5f/(float)M_PI; 01162 result= MAX2(result, 0.0f); 01163 01164 return result; 01165 } 01166 01167 static float occ_form_factor(OccFace *face, float *p, float *n) 01168 { 01169 ObjectInstanceRen *obi; 01170 VlakRen *vlr; 01171 float v1[3], v2[3], v3[3], v4[3], q0[3], q1[3], q2[3], q3[3], contrib= 0.0f; 01172 01173 obi= &R.objectinstance[face->obi]; 01174 vlr= RE_findOrAddVlak(obi->obr, face->facenr); 01175 01176 copy_v3_v3(v1, vlr->v1->co); 01177 copy_v3_v3(v2, vlr->v2->co); 01178 copy_v3_v3(v3, vlr->v3->co); 01179 01180 if(obi->flag & R_TRANSFORMED) { 01181 mul_m4_v3(obi->mat, v1); 01182 mul_m4_v3(obi->mat, v2); 01183 mul_m4_v3(obi->mat, v3); 01184 } 01185 01186 if(occ_visible_quad(p, n, v1, v2, v3, q0, q1, q2, q3)) 01187 contrib += occ_quad_form_factor(p, n, q0, q1, q2, q3); 01188 01189 if(vlr->v4) { 01190 copy_v3_v3(v4, vlr->v4->co); 01191 if(obi->flag & R_TRANSFORMED) 01192 mul_m4_v3(obi->mat, v4); 01193 01194 if(occ_visible_quad(p, n, v1, v3, v4, q0, q1, q2, q3)) 01195 contrib += occ_quad_form_factor(p, n, q0, q1, q2, q3); 01196 } 01197 01198 return contrib; 01199 } 01200 01201 static void occ_lookup(OcclusionTree *tree, int thread, OccFace *exclude, float *pp, float *pn, float *occ, float rad[3], float bentn[3]) 01202 { 01203 OccNode *node, **stack; 01204 OccFace *face; 01205 float resultocc, resultrad[3], v[3], p[3], n[3], co[3], invd2; 01206 float distfac, fac, error, d2, weight, emitarea; 01207 int b, f, totstack; 01208 01209 /* init variables */ 01210 copy_v3_v3(p, pp); 01211 copy_v3_v3(n, pn); 01212 madd_v3_v3fl(p, n, 1e-4f); 01213 01214 if(bentn) 01215 copy_v3_v3(bentn, n); 01216 01217 error= tree->error; 01218 distfac= tree->distfac; 01219 01220 resultocc= 0.0f; 01221 zero_v3(resultrad); 01222 01223 /* init stack */ 01224 stack= tree->stack[thread]; 01225 stack[0]= tree->root; 01226 totstack= 1; 01227 01228 while(totstack) { 01229 /* pop point off the stack */ 01230 node= stack[--totstack]; 01231 01232 sub_v3_v3v3(v, node->co, p); 01233 d2= dot_v3v3(v, v) + 1e-16f; 01234 emitarea= MAX2(node->area, node->dco); 01235 01236 if(d2*error > emitarea) { 01237 if(distfac != 0.0f) { 01238 fac= 1.0f/(1.0f + distfac*d2); 01239 if(fac < 0.01f) 01240 continue; 01241 } 01242 else 01243 fac= 1.0f; 01244 01245 /* accumulate occlusion from spherical harmonics */ 01246 invd2 = 1.0f/sqrtf(d2); 01247 weight= occ_solid_angle(node, v, d2, invd2, n); 01248 01249 if(rad) 01250 madd_v3_v3fl(resultrad, node->rad, weight*fac); 01251 01252 weight *= node->occlusion; 01253 01254 if(bentn) { 01255 bentn[0] -= weight*invd2*v[0]; 01256 bentn[1] -= weight*invd2*v[1]; 01257 bentn[2] -= weight*invd2*v[2]; 01258 } 01259 01260 resultocc += weight*fac; 01261 } 01262 else { 01263 /* traverse into children */ 01264 for(b=0; b<TOTCHILD; b++) { 01265 if(node->childflag & (1<<b)) { 01266 f= node->child[b].face; 01267 face= &tree->face[f]; 01268 01269 /* accumulate occlusion with face form factor */ 01270 if(!exclude || !(face->obi == exclude->obi && face->facenr == exclude->facenr)) { 01271 if(bentn || distfac != 0.0f) { 01272 occ_face(face, co, NULL, NULL); 01273 sub_v3_v3v3(v, co, p); 01274 d2= dot_v3v3(v, v) + 1e-16f; 01275 01276 fac= (distfac == 0.0f)? 1.0f: 1.0f/(1.0f + distfac*d2); 01277 if(fac < 0.01f) 01278 continue; 01279 } 01280 else 01281 fac= 1.0f; 01282 01283 weight= occ_form_factor(face, p, n); 01284 01285 if(rad) 01286 madd_v3_v3fl(resultrad, tree->rad[f], weight*fac); 01287 01288 weight *= tree->occlusion[f]; 01289 01290 if(bentn) { 01291 invd2= 1.0f/sqrtf(d2); 01292 bentn[0] -= weight*invd2*v[0]; 01293 bentn[1] -= weight*invd2*v[1]; 01294 bentn[2] -= weight*invd2*v[2]; 01295 } 01296 01297 resultocc += weight*fac; 01298 } 01299 } 01300 else if(node->child[b].node) { 01301 /* push child on the stack */ 01302 stack[totstack++]= node->child[b].node; 01303 } 01304 } 01305 } 01306 } 01307 01308 if(occ) *occ= resultocc; 01309 if(rad) copy_v3_v3(rad, resultrad); 01310 /*if(rad && exclude) { 01311 int a; 01312 for(a=0; a<tree->totface; a++) 01313 if((tree->face[a].obi == exclude->obi && tree->face[a].facenr == exclude->facenr)) 01314 copy_v3_v3(rad, tree->rad[a]); 01315 }*/ 01316 if(bentn) normalize_v3(bentn); 01317 } 01318 01319 static void occ_compute_bounces(Render *re, OcclusionTree *tree, int totbounce) 01320 { 01321 float (*rad)[3], (*sum)[3], (*tmp)[3], co[3], n[3], occ; 01322 int bounce, i; 01323 01324 rad= MEM_callocN(sizeof(float)*3*tree->totface, "OcclusionBounceRad"); 01325 sum= MEM_dupallocN(tree->rad); 01326 01327 for(bounce=1; bounce<totbounce; bounce++) { 01328 for(i=0; i<tree->totface; i++) { 01329 occ_face(&tree->face[i], co, n, NULL); 01330 madd_v3_v3fl(co, n, 1e-8f); 01331 01332 occ_lookup(tree, 0, &tree->face[i], co, n, &occ, rad[i], NULL); 01333 rad[i][0]= MAX2(rad[i][0], 0.0f); 01334 rad[i][1]= MAX2(rad[i][1], 0.0f); 01335 rad[i][2]= MAX2(rad[i][2], 0.0f); 01336 add_v3_v3(sum[i], rad[i]); 01337 01338 if(re->test_break(re->tbh)) 01339 break; 01340 } 01341 01342 if(re->test_break(re->tbh)) 01343 break; 01344 01345 tmp= tree->rad; 01346 tree->rad= rad; 01347 rad= tmp; 01348 01349 occ_sum_occlusion(tree, tree->root); 01350 } 01351 01352 MEM_freeN(rad); 01353 MEM_freeN(tree->rad); 01354 tree->rad= sum; 01355 01356 if(!re->test_break(re->tbh)) 01357 occ_sum_occlusion(tree, tree->root); 01358 } 01359 01360 static void occ_compute_passes(Render *re, OcclusionTree *tree, int totpass) 01361 { 01362 float *occ, co[3], n[3]; 01363 int pass, i; 01364 01365 occ= MEM_callocN(sizeof(float)*tree->totface, "OcclusionPassOcc"); 01366 01367 for(pass=0; pass<totpass; pass++) { 01368 for(i=0; i<tree->totface; i++) { 01369 occ_face(&tree->face[i], co, n, NULL); 01370 negate_v3(n); 01371 madd_v3_v3fl(co, n, 1e-8f); 01372 01373 occ_lookup(tree, 0, &tree->face[i], co, n, &occ[i], NULL, NULL); 01374 if(re->test_break(re->tbh)) 01375 break; 01376 } 01377 01378 if(re->test_break(re->tbh)) 01379 break; 01380 01381 for(i=0; i<tree->totface; i++) { 01382 tree->occlusion[i] -= occ[i]; //MAX2(1.0f-occ[i], 0.0f); 01383 if(tree->occlusion[i] < 0.0f) 01384 tree->occlusion[i]= 0.0f; 01385 } 01386 01387 occ_sum_occlusion(tree, tree->root); 01388 } 01389 01390 MEM_freeN(occ); 01391 } 01392 01393 static void sample_occ_tree(Render *re, OcclusionTree *tree, OccFace *exclude, float *co, float *n, int thread, int onlyshadow, float *ao, float *env, float *indirect) 01394 { 01395 float nn[3], bn[3], fac, occ, occlusion, correction, rad[3]; 01396 int envcolor; 01397 01398 envcolor= re->wrld.aocolor; 01399 if(onlyshadow) 01400 envcolor= WO_AOPLAIN; 01401 01402 negate_v3_v3(nn, n); 01403 01404 occ_lookup(tree, thread, exclude, co, nn, &occ, (tree->doindirect)? rad: NULL, (env && envcolor)? bn: NULL); 01405 01406 correction= re->wrld.ao_approx_correction; 01407 01408 occlusion= (1.0f-correction)*(1.0f-occ); 01409 CLAMP(occlusion, 0.0f, 1.0f); 01410 if(correction != 0.0f) 01411 occlusion += correction*exp(-occ); 01412 01413 if(env) { 01414 /* sky shading using bent normal */ 01415 if(ELEM(envcolor, WO_AOSKYCOL, WO_AOSKYTEX)) { 01416 fac= 0.5f*(1.0f+bn[0]*re->grvec[0]+ bn[1]*re->grvec[1]+ bn[2]*re->grvec[2]); 01417 env[0]= (1.0f-fac)*re->wrld.horr + fac*re->wrld.zenr; 01418 env[1]= (1.0f-fac)*re->wrld.horg + fac*re->wrld.zeng; 01419 env[2]= (1.0f-fac)*re->wrld.horb + fac*re->wrld.zenb; 01420 01421 mul_v3_fl(env, occlusion); 01422 } 01423 else { 01424 env[0]= occlusion; 01425 env[1]= occlusion; 01426 env[2]= occlusion; 01427 } 01428 #if 0 01429 else { /* WO_AOSKYTEX */ 01430 float dxyview[3]; 01431 bn[0]= -bn[0]; 01432 bn[1]= -bn[1]; 01433 bn[2]= -bn[2]; 01434 dxyview[0]= 1.0f; 01435 dxyview[1]= 1.0f; 01436 dxyview[2]= 0.0f; 01437 shadeSkyView(ao, co, bn, dxyview); 01438 } 01439 #endif 01440 } 01441 01442 if(ao) { 01443 ao[0]= occlusion; 01444 ao[1]= occlusion; 01445 ao[2]= occlusion; 01446 } 01447 01448 if(tree->doindirect) copy_v3_v3(indirect, rad); 01449 else zero_v3(indirect); 01450 } 01451 01452 /* ---------------------------- Caching ------------------------------- */ 01453 01454 static OcclusionCacheSample *find_occ_sample(OcclusionCache *cache, int x, int y) 01455 { 01456 x -= cache->x; 01457 y -= cache->y; 01458 01459 x /= cache->step; 01460 y /= cache->step; 01461 x *= cache->step; 01462 y *= cache->step; 01463 01464 if(x < 0 || x >= cache->w || y < 0 || y >= cache->h) 01465 return NULL; 01466 else 01467 return &cache->sample[y*cache->w + x]; 01468 } 01469 01470 static int sample_occ_cache(OcclusionTree *tree, float *co, float *n, int x, int y, int thread, float *ao, float *env, float *indirect) 01471 { 01472 OcclusionCache *cache; 01473 OcclusionCacheSample *samples[4], *sample; 01474 float wn[4], wz[4], wb[4], tx, ty, w, totw, mino, maxo; 01475 float d[3], dist2; 01476 int i, x1, y1, x2, y2; 01477 01478 if(!tree->cache) 01479 return 0; 01480 01481 /* first try to find a sample in the same pixel */ 01482 cache= &tree->cache[thread]; 01483 01484 if(cache->sample && cache->step) { 01485 sample= &cache->sample[(y-cache->y)*cache->w + (x-cache->x)]; 01486 if(sample->filled) { 01487 sub_v3_v3v3(d, sample->co, co); 01488 dist2= dot_v3v3(d, d); 01489 if(dist2 < 0.5f*sample->dist2 && dot_v3v3(sample->n, n) > 0.98f) { 01490 copy_v3_v3(ao, sample->ao); 01491 copy_v3_v3(env, sample->env); 01492 copy_v3_v3(indirect, sample->indirect); 01493 return 1; 01494 } 01495 } 01496 } 01497 else 01498 return 0; 01499 01500 /* try to interpolate between 4 neighbouring pixels */ 01501 samples[0]= find_occ_sample(cache, x, y); 01502 samples[1]= find_occ_sample(cache, x+cache->step, y); 01503 samples[2]= find_occ_sample(cache, x, y+cache->step); 01504 samples[3]= find_occ_sample(cache, x+cache->step, y+cache->step); 01505 01506 for(i=0; i<4; i++) 01507 if(!samples[i] || !samples[i]->filled) 01508 return 0; 01509 01510 /* require intensities not being too different */ 01511 mino= MIN4(samples[0]->intensity, samples[1]->intensity, samples[2]->intensity, samples[3]->intensity); 01512 maxo= MAX4(samples[0]->intensity, samples[1]->intensity, samples[2]->intensity, samples[3]->intensity); 01513 01514 if(maxo - mino > 0.05f) 01515 return 0; 01516 01517 /* compute weighted interpolation between samples */ 01518 zero_v3(ao); 01519 zero_v3(env); 01520 zero_v3(indirect); 01521 totw= 0.0f; 01522 01523 x1= samples[0]->x; 01524 y1= samples[0]->y; 01525 x2= samples[3]->x; 01526 y2= samples[3]->y; 01527 01528 tx= (float)(x2 - x)/(float)(x2 - x1); 01529 ty= (float)(y2 - y)/(float)(y2 - y1); 01530 01531 wb[3]= (1.0f-tx)*(1.0f-ty); 01532 wb[2]= (tx)*(1.0f-ty); 01533 wb[1]= (1.0f-tx)*(ty); 01534 wb[0]= tx*ty; 01535 01536 for(i=0; i<4; i++) { 01537 sub_v3_v3v3(d, samples[i]->co, co); 01538 //dist2= dot_v3v3(d, d); 01539 01540 wz[i]= 1.0f; //(samples[i]->dist2/(1e-4f + dist2)); 01541 wn[i]= pow(dot_v3v3(samples[i]->n, n), 32.0f); 01542 01543 w= wb[i]*wn[i]*wz[i]; 01544 01545 totw += w; 01546 madd_v3_v3fl(ao, samples[i]->ao, w); 01547 madd_v3_v3fl(env, samples[i]->env, w); 01548 madd_v3_v3fl(indirect, samples[i]->indirect, w); 01549 } 01550 01551 if(totw >= 0.9f) { 01552 totw= 1.0f/totw; 01553 mul_v3_fl(ao, totw); 01554 mul_v3_fl(env, totw); 01555 mul_v3_fl(indirect, totw); 01556 return 1; 01557 } 01558 01559 return 0; 01560 } 01561 01562 static void sample_occ_surface(ShadeInput *shi) 01563 { 01564 StrandRen *strand= shi->strand; 01565 StrandSurface *mesh= strand->buffer->surface; 01566 int *face, *index = RE_strandren_get_face(shi->obr, strand, 0); 01567 float w[4], *co1, *co2, *co3, *co4; 01568 01569 if(mesh && mesh->face && mesh->co && mesh->ao && index) { 01570 face= mesh->face[*index]; 01571 01572 co1= mesh->co[face[0]]; 01573 co2= mesh->co[face[1]]; 01574 co3= mesh->co[face[2]]; 01575 co4= (face[3])? mesh->co[face[3]]: NULL; 01576 01577 interp_weights_face_v3(w, co1, co2, co3, co4, strand->vert->co); 01578 01579 zero_v3(shi->ao); 01580 zero_v3(shi->env); 01581 zero_v3(shi->indirect); 01582 01583 madd_v3_v3fl(shi->ao, mesh->ao[face[0]], w[0]); 01584 madd_v3_v3fl(shi->env, mesh->env[face[0]], w[0]); 01585 madd_v3_v3fl(shi->indirect, mesh->indirect[face[0]], w[0]); 01586 madd_v3_v3fl(shi->ao, mesh->ao[face[1]], w[1]); 01587 madd_v3_v3fl(shi->env, mesh->env[face[1]], w[1]); 01588 madd_v3_v3fl(shi->indirect, mesh->indirect[face[1]], w[1]); 01589 madd_v3_v3fl(shi->ao, mesh->ao[face[2]], w[2]); 01590 madd_v3_v3fl(shi->env, mesh->env[face[2]], w[2]); 01591 madd_v3_v3fl(shi->indirect, mesh->indirect[face[2]], w[2]); 01592 if(face[3]) { 01593 madd_v3_v3fl(shi->ao, mesh->ao[face[3]], w[3]); 01594 madd_v3_v3fl(shi->env, mesh->env[face[3]], w[3]); 01595 madd_v3_v3fl(shi->indirect, mesh->indirect[face[3]], w[3]); 01596 } 01597 } 01598 else { 01599 shi->ao[0]= 1.0f; 01600 shi->ao[1]= 1.0f; 01601 shi->ao[2]= 1.0f; 01602 zero_v3(shi->env); 01603 zero_v3(shi->indirect); 01604 } 01605 } 01606 01607 /* ------------------------- External Functions --------------------------- */ 01608 01609 static void *exec_strandsurface_sample(void *data) 01610 { 01611 OcclusionThread *othread= (OcclusionThread*)data; 01612 Render *re= othread->re; 01613 StrandSurface *mesh= othread->mesh; 01614 float ao[3], env[3], indirect[3], co[3], n[3], *co1, *co2, *co3, *co4; 01615 int a, *face; 01616 01617 for(a=othread->begin; a<othread->end; a++) { 01618 face= mesh->face[a]; 01619 co1= mesh->co[face[0]]; 01620 co2= mesh->co[face[1]]; 01621 co3= mesh->co[face[2]]; 01622 01623 if(face[3]) { 01624 co4= mesh->co[face[3]]; 01625 01626 mid_v3_v3v3(co, co1, co3); 01627 normal_quad_v3( n,co1, co2, co3, co4); 01628 } 01629 else { 01630 cent_tri_v3(co, co1, co2, co3); 01631 normal_tri_v3( n,co1, co2, co3); 01632 } 01633 negate_v3(n); 01634 01635 sample_occ_tree(re, re->occlusiontree, NULL, co, n, othread->thread, 0, ao, env, indirect); 01636 copy_v3_v3(othread->faceao[a], ao); 01637 copy_v3_v3(othread->faceenv[a], env); 01638 copy_v3_v3(othread->faceindirect[a], indirect); 01639 } 01640 01641 return 0; 01642 } 01643 01644 void make_occ_tree(Render *re) 01645 { 01646 OcclusionThread othreads[BLENDER_MAX_THREADS]; 01647 OcclusionTree *tree; 01648 StrandSurface *mesh; 01649 ListBase threads; 01650 float ao[3], env[3], indirect[3], (*faceao)[3], (*faceenv)[3], (*faceindirect)[3]; 01651 int a, totface, totthread, *face, *count; 01652 01653 /* ugly, needed for occ_face */ 01654 R= *re; 01655 01656 re->i.infostr= "Occlusion preprocessing"; 01657 re->stats_draw(re->sdh, &re->i); 01658 01659 re->occlusiontree= tree= occ_tree_build(re); 01660 01661 if(tree) { 01662 if(re->wrld.ao_approx_passes > 0) 01663 occ_compute_passes(re, tree, re->wrld.ao_approx_passes); 01664 if(tree->doindirect && (re->wrld.mode & WO_INDIRECT_LIGHT)) 01665 occ_compute_bounces(re, tree, re->wrld.ao_indirect_bounces); 01666 01667 for(mesh=re->strandsurface.first; mesh; mesh=mesh->next) { 01668 if(!mesh->face || !mesh->co || !mesh->ao) 01669 continue; 01670 01671 count= MEM_callocN(sizeof(int)*mesh->totvert, "OcclusionCount"); 01672 faceao= MEM_callocN(sizeof(float)*3*mesh->totface, "StrandSurfFaceAO"); 01673 faceenv= MEM_callocN(sizeof(float)*3*mesh->totface, "StrandSurfFaceEnv"); 01674 faceindirect= MEM_callocN(sizeof(float)*3*mesh->totface, "StrandSurfFaceIndirect"); 01675 01676 totthread= (mesh->totface > 10000)? re->r.threads: 1; 01677 totface= mesh->totface/totthread; 01678 for(a=0; a<totthread; a++) { 01679 othreads[a].re= re; 01680 othreads[a].faceao= faceao; 01681 othreads[a].faceenv= faceenv; 01682 othreads[a].faceindirect= faceindirect; 01683 othreads[a].thread= a; 01684 othreads[a].mesh= mesh; 01685 othreads[a].begin= a*totface; 01686 othreads[a].end= (a == totthread-1)? mesh->totface: (a+1)*totface; 01687 } 01688 01689 if(totthread == 1) { 01690 exec_strandsurface_sample(&othreads[0]); 01691 } 01692 else { 01693 BLI_init_threads(&threads, exec_strandsurface_sample, totthread); 01694 01695 for(a=0; a<totthread; a++) 01696 BLI_insert_thread(&threads, &othreads[a]); 01697 01698 BLI_end_threads(&threads); 01699 } 01700 01701 for(a=0; a<mesh->totface; a++) { 01702 face= mesh->face[a]; 01703 01704 copy_v3_v3(ao, faceao[a]); 01705 copy_v3_v3(env, faceenv[a]); 01706 copy_v3_v3(indirect, faceindirect[a]); 01707 01708 add_v3_v3(mesh->ao[face[0]], ao); 01709 add_v3_v3(mesh->env[face[0]], env); 01710 add_v3_v3(mesh->indirect[face[0]], indirect); 01711 count[face[0]]++; 01712 add_v3_v3(mesh->ao[face[1]], ao); 01713 add_v3_v3(mesh->env[face[1]], env); 01714 add_v3_v3(mesh->indirect[face[1]], indirect); 01715 count[face[1]]++; 01716 add_v3_v3(mesh->ao[face[2]], ao); 01717 add_v3_v3(mesh->env[face[2]], env); 01718 add_v3_v3(mesh->indirect[face[2]], indirect); 01719 count[face[2]]++; 01720 01721 if(face[3]) { 01722 add_v3_v3(mesh->ao[face[3]], ao); 01723 add_v3_v3(mesh->env[face[3]], env); 01724 add_v3_v3(mesh->indirect[face[3]], indirect); 01725 count[face[3]]++; 01726 } 01727 } 01728 01729 for(a=0; a<mesh->totvert; a++) { 01730 if(count[a]) { 01731 mul_v3_fl(mesh->ao[a], 1.0f/count[a]); 01732 mul_v3_fl(mesh->env[a], 1.0f/count[a]); 01733 mul_v3_fl(mesh->indirect[a], 1.0f/count[a]); 01734 } 01735 } 01736 01737 MEM_freeN(count); 01738 MEM_freeN(faceao); 01739 MEM_freeN(faceenv); 01740 MEM_freeN(faceindirect); 01741 } 01742 } 01743 } 01744 01745 void free_occ(Render *re) 01746 { 01747 if(re->occlusiontree) { 01748 occ_free_tree(re->occlusiontree); 01749 re->occlusiontree = NULL; 01750 } 01751 } 01752 01753 void sample_occ(Render *re, ShadeInput *shi) 01754 { 01755 OcclusionTree *tree= re->occlusiontree; 01756 OcclusionCache *cache; 01757 OcclusionCacheSample *sample; 01758 OccFace exclude; 01759 int onlyshadow; 01760 01761 if(tree) { 01762 if(shi->strand) { 01763 sample_occ_surface(shi); 01764 } 01765 /* try to get result from the cache if possible */ 01766 else if(shi->depth!=0 || !sample_occ_cache(tree, shi->co, shi->vno, shi->xs, shi->ys, shi->thread, shi->ao, shi->env, shi->indirect)) { 01767 /* no luck, let's sample the occlusion */ 01768 exclude.obi= shi->obi - re->objectinstance; 01769 exclude.facenr= shi->vlr->index; 01770 onlyshadow= (shi->mat->mode & MA_ONLYSHADOW); 01771 sample_occ_tree(re, tree, &exclude, shi->co, shi->vno, shi->thread, onlyshadow, shi->ao, shi->env, shi->indirect); 01772 01773 /* fill result into sample, each time */ 01774 if(tree->cache) { 01775 cache= &tree->cache[shi->thread]; 01776 01777 if(cache->sample && cache->step) { 01778 sample= &cache->sample[(shi->ys-cache->y)*cache->w + (shi->xs-cache->x)]; 01779 copy_v3_v3(sample->co, shi->co); 01780 copy_v3_v3(sample->n, shi->vno); 01781 copy_v3_v3(sample->ao, shi->ao); 01782 copy_v3_v3(sample->env, shi->env); 01783 copy_v3_v3(sample->indirect, shi->indirect); 01784 sample->intensity= MAX3(sample->ao[0], sample->ao[1], sample->ao[2]); 01785 sample->intensity= MAX2(sample->intensity, MAX3(sample->env[0], sample->env[1], sample->env[2])); 01786 sample->intensity= MAX2(sample->intensity, MAX3(sample->indirect[0], sample->indirect[1], sample->indirect[2])); 01787 sample->dist2= dot_v3v3(shi->dxco, shi->dxco) + dot_v3v3(shi->dyco, shi->dyco); 01788 sample->filled= 1; 01789 } 01790 } 01791 } 01792 } 01793 else { 01794 shi->ao[0]= 1.0f; 01795 shi->ao[1]= 1.0f; 01796 shi->ao[2]= 1.0f; 01797 01798 shi->env[0]= 0.0f; 01799 shi->env[1]= 0.0f; 01800 shi->env[2]= 0.0f; 01801 01802 shi->indirect[0]= 0.0f; 01803 shi->indirect[1]= 0.0f; 01804 shi->indirect[2]= 0.0f; 01805 } 01806 } 01807 01808 void cache_occ_samples(Render *re, RenderPart *pa, ShadeSample *ssamp) 01809 { 01810 OcclusionTree *tree= re->occlusiontree; 01811 PixStr ps; 01812 OcclusionCache *cache; 01813 OcclusionCacheSample *sample; 01814 OccFace exclude; 01815 ShadeInput *shi; 01816 intptr_t *rd=NULL; 01817 int *ro=NULL, *rp=NULL, *rz=NULL, onlyshadow; 01818 int x, y, step = CACHE_STEP; 01819 01820 if(!tree->cache) 01821 return; 01822 01823 cache= &tree->cache[pa->thread]; 01824 cache->w= pa->rectx; 01825 cache->h= pa->recty; 01826 cache->x= pa->disprect.xmin; 01827 cache->y= pa->disprect.ymin; 01828 cache->step= step; 01829 cache->sample= MEM_callocN(sizeof(OcclusionCacheSample)*cache->w*cache->h, "OcclusionCacheSample"); 01830 sample= cache->sample; 01831 01832 if(re->osa) { 01833 rd= pa->rectdaps; 01834 } 01835 else { 01836 /* fake pixel struct for non-osa */ 01837 ps.next= NULL; 01838 ps.mask= 0xFFFF; 01839 01840 ro= pa->recto; 01841 rp= pa->rectp; 01842 rz= pa->rectz; 01843 } 01844 01845 /* compute a sample at every step pixels */ 01846 for(y=pa->disprect.ymin; y<pa->disprect.ymax; y++) { 01847 for(x=pa->disprect.xmin; x<pa->disprect.xmax; x++, sample++, rd++, ro++, rp++, rz++) { 01848 if(!(((x - pa->disprect.xmin + step) % step) == 0 || x == pa->disprect.xmax-1)) 01849 continue; 01850 if(!(((y - pa->disprect.ymin + step) % step) == 0 || y == pa->disprect.ymax-1)) 01851 continue; 01852 01853 if(re->osa) { 01854 if(!*rd) continue; 01855 01856 shade_samples_fill_with_ps(ssamp, (PixStr *)(*rd), x, y); 01857 } 01858 else { 01859 if(!*rp) continue; 01860 01861 ps.obi= *ro; 01862 ps.facenr= *rp; 01863 ps.z= *rz; 01864 shade_samples_fill_with_ps(ssamp, &ps, x, y); 01865 } 01866 01867 shi= ssamp->shi; 01868 if(shi->vlr) { 01869 onlyshadow= (shi->mat->mode & MA_ONLYSHADOW); 01870 exclude.obi= shi->obi - re->objectinstance; 01871 exclude.facenr= shi->vlr->index; 01872 sample_occ_tree(re, tree, &exclude, shi->co, shi->vno, shi->thread, onlyshadow, shi->ao, shi->env, shi->indirect); 01873 01874 copy_v3_v3(sample->co, shi->co); 01875 copy_v3_v3(sample->n, shi->vno); 01876 copy_v3_v3(sample->ao, shi->ao); 01877 copy_v3_v3(sample->env, shi->env); 01878 copy_v3_v3(sample->indirect, shi->indirect); 01879 sample->intensity= MAX3(sample->ao[0], sample->ao[1], sample->ao[2]); 01880 sample->intensity= MAX2(sample->intensity, MAX3(sample->env[0], sample->env[1], sample->env[2])); 01881 sample->intensity= MAX2(sample->intensity, MAX3(sample->indirect[0], sample->indirect[1], sample->indirect[2])); 01882 sample->dist2= dot_v3v3(shi->dxco, shi->dxco) + dot_v3v3(shi->dyco, shi->dyco); 01883 sample->x= shi->xs; 01884 sample->y= shi->ys; 01885 sample->filled= 1; 01886 } 01887 01888 if(re->test_break(re->tbh)) 01889 break; 01890 } 01891 } 01892 } 01893 01894 void free_occ_samples(Render *re, RenderPart *pa) 01895 { 01896 OcclusionTree *tree= re->occlusiontree; 01897 OcclusionCache *cache; 01898 01899 if(tree->cache) { 01900 cache= &tree->cache[pa->thread]; 01901 01902 if(cache->sample) 01903 MEM_freeN(cache->sample); 01904 01905 cache->w= 0; 01906 cache->h= 0; 01907 cache->step= 0; 01908 } 01909 } 01910