diff options
-rw-r--r-- | release/scripts/ui/properties_world.py | 1 | ||||
-rw-r--r-- | source/blender/makesdna/DNA_world_types.h | 1 | ||||
-rw-r--r-- | source/blender/makesrna/intern/rna_world.c | 6 | ||||
-rw-r--r-- | source/blender/render/extern/include/RE_shader_ext.h | 2 | ||||
-rw-r--r-- | source/blender/render/intern/include/render_types.h | 3 | ||||
-rw-r--r-- | source/blender/render/intern/source/occlusion.c | 221 | ||||
-rw-r--r-- | source/blender/render/intern/source/shadeoutput.c | 1 | ||||
-rw-r--r-- | source/blender/render/intern/source/strand.c | 6 |
8 files changed, 164 insertions, 77 deletions
diff --git a/release/scripts/ui/properties_world.py b/release/scripts/ui/properties_world.py index 4f662df8cc8..ec0e1c42add 100644 --- a/release/scripts/ui/properties_world.py +++ b/release/scripts/ui/properties_world.py @@ -219,6 +219,7 @@ class WORLD_PT_ambient_occlusion(WorldButtonsPanel): col = split.column() col.prop(ao, "energy") + col.prop(ao, "indirect_energy") if wide_ui: col = split.column() diff --git a/source/blender/makesdna/DNA_world_types.h b/source/blender/makesdna/DNA_world_types.h index 64ff23dd1a8..11ecbf97d97 100644 --- a/source/blender/makesdna/DNA_world_types.h +++ b/source/blender/makesdna/DNA_world_types.h @@ -107,6 +107,7 @@ typedef struct World { short aomode, aosamp, aomix, aocolor; float ao_adapt_thresh, ao_adapt_speed_fac; float ao_approx_error, ao_approx_correction; + float ao_indirect_energy, aopad; short ao_samp_method, ao_gather_method, ao_approx_passes; /* assorted settings (in the middle of ambient occlusion settings for padding reasons) */ diff --git a/source/blender/makesrna/intern/rna_world.c b/source/blender/makesrna/intern/rna_world.c index c0c9c1d6568..88992387148 100644 --- a/source/blender/makesrna/intern/rna_world.c +++ b/source/blender/makesrna/intern/rna_world.c @@ -312,6 +312,12 @@ static void rna_def_ambient_occlusion(BlenderRNA *brna) RNA_def_property_range(prop, 0, 10); RNA_def_property_ui_text(prop, "Passes", "Number of preprocessing passes to reduce overocclusion (for Approximate)."); RNA_def_property_update(prop, 0, "rna_World_update"); + + prop= RNA_def_property(srna, "indirect_energy", PROP_FLOAT, PROP_UNSIGNED); + RNA_def_property_float_sdna(prop, NULL, "ao_indirect_energy"); + RNA_def_property_ui_range(prop, 0, 10, 0.1, 3); + RNA_def_property_ui_text(prop, "Indirect", "Use approximate ambient occlusion for indirect diffuse lighting."); + RNA_def_property_update(prop, 0, "rna_World_update"); } static void rna_def_world_mist(BlenderRNA *brna) diff --git a/source/blender/render/extern/include/RE_shader_ext.h b/source/blender/render/extern/include/RE_shader_ext.h index b36163f57c0..2615be1440a 100644 --- a/source/blender/render/extern/include/RE_shader_ext.h +++ b/source/blender/render/extern/include/RE_shader_ext.h @@ -153,7 +153,7 @@ typedef struct ShadeInput float dxstrand, dystrand; /* AO is a pre-process now */ - float ao[3]; + float ao[3], indirect[3]; int xs, ys; /* pixel to be rendered */ int mask; /* subsample mask */ diff --git a/source/blender/render/intern/include/render_types.h b/source/blender/render/intern/include/render_types.h index 48bf34d0696..d41851db5ff 100644 --- a/source/blender/render/intern/include/render_types.h +++ b/source/blender/render/intern/include/render_types.h @@ -398,7 +398,8 @@ typedef struct StrandSurface { int (*face)[4]; float (*co)[3]; /* for occlusion caching */ - float (*col)[3]; + float (*ao)[3]; + float (*indirect)[3]; /* for speedvectors */ float (*prevco)[3], (*nextco)[3]; int totvert, totface; diff --git a/source/blender/render/intern/source/occlusion.c b/source/blender/render/intern/source/occlusion.c index f62668b84c0..90929db2f74 100644 --- a/source/blender/render/intern/source/occlusion.c +++ b/source/blender/render/intern/source/occlusion.c @@ -64,7 +64,7 @@ #define CACHE_STEP 3 typedef struct OcclusionCacheSample { - float co[3], n[3], col[3], intensity, dist2; + float co[3], n[3], ao[3], indirect[3], intensity, dist2; int x, y, filled; } OcclusionCacheSample; @@ -81,7 +81,7 @@ typedef struct OccFace { typedef struct OccNode { float co[3], area; float sh[9], dco; - float occlusion; + float occlusion, rad[3]; int childflag; union { //OccFace face; @@ -97,6 +97,7 @@ typedef struct OcclusionTree { OccFace *face; /* instance and face indices */ float *occlusion; /* occlusion for faces */ + float (*rad)[3]; /* radiance for faces */ OccNode *root; @@ -117,7 +118,8 @@ typedef struct OcclusionTree { typedef struct OcclusionThread { Render *re; StrandSurface *mesh; - float (*facecol)[3]; + float (*faceao)[3]; + float (*faceindirect)[3]; int begin, end; int thread; } OcclusionThread; @@ -132,7 +134,6 @@ typedef struct OcclusionBuildThread { extern Render R; // meh -#if 0 static void occ_shade(ShadeSample *ssamp, ObjectInstanceRen *obi, VlakRen *vlr, float *rad) { ShadeInput *shi= ssamp->shi; @@ -160,7 +161,7 @@ static void occ_shade(ShadeSample *ssamp, ObjectInstanceRen *obi, VlakRen *vlr, shi->co[0]= l*v3[0]+u*v1[0]+v*v2[0]; shi->co[1]= l*v3[1]+u*v1[1]+v*v2[1]; shi->co[2]= l*v3[2]+u*v1[2]+v*v2[2]; - + shade_input_set_triangle_i(shi, obi, vlr, 0, 1, 2); /* set up view vector */ @@ -179,6 +180,8 @@ static void occ_shade(ShadeSample *ssamp, ObjectInstanceRen *obi, VlakRen *vlr, if(shi->flippednor) shade_input_flip_normals(shi); + madd_v3_v3fl(shi->co, shi->vn, 0.0001f); /* ugly.. */ + /* not a pretty solution, but fixes common cases */ if(shi->obr->ob && shi->obr->ob->transflag & OB_NEG_SCALE) { negate_v3(shi->vn); @@ -215,12 +218,11 @@ static void occ_build_shade(Render *re, OcclusionTree *tree) for(a=0; a<tree->totface; a++) { obi= &R.objectinstance[tree->face[a].obi]; - vlr= RE_findOrAddVlak(obi->obr, tree->face[a].vlr); + vlr= RE_findOrAddVlak(obi->obr, tree->face[a].facenr); occ_shade(&ssamp, obi, vlr, tree->rad[a]); } } -#endif /* ------------------------- Spherical Harmonics --------------------------- */ @@ -352,17 +354,19 @@ static void occ_face(const OccFace *face, float *co, float *normal, float *area) static void occ_sum_occlusion(OcclusionTree *tree, OccNode *node) { OccNode *child; - float occ, area, totarea; + float occ, area, totarea, rad[3]; int a, b; occ= 0.0f; totarea= 0.0f; + zero_v3(rad); for(b=0; b<TOTCHILD; b++) { if(node->childflag & (1<<b)) { a= node->child[b].face; occ_face(&tree->face[a], 0, 0, &area); occ += area*tree->occlusion[a]; + madd_v3_v3fl(rad, tree->rad[a], area); totarea += area; } else if(node->child[b].node) { @@ -370,14 +374,18 @@ static void occ_sum_occlusion(OcclusionTree *tree, OccNode *node) occ_sum_occlusion(tree, child); occ += child->area*child->occlusion; + madd_v3_v3fl(rad, child->rad, child->area); totarea += child->area; } } - if(totarea != 0.0f) + if(totarea != 0.0f) { occ /= totarea; + mul_v3_fl(rad, 1.0f/totarea); + } node->occlusion= occ; + copy_v3_v3(node->rad, rad); } static int occ_find_bbox_axis(OcclusionTree *tree, int begin, int end, float *min, float *max) @@ -656,6 +664,9 @@ static OcclusionTree *occ_tree_build(Render *re) tree->co= MEM_callocN(sizeof(float)*3*totface, "OcclusionCo"); tree->occlusion= MEM_callocN(sizeof(float)*totface, "OcclusionOcclusion"); + if(re->wrld.ao_indirect_energy != 0.0f) + tree->rad= MEM_callocN(sizeof(float)*3*totface, "OcclusionRad"); + /* make array of face pointers */ for(b=0, c=0, obi=re->instancetable.first; obi; obi=obi->next, c++) { obr= obi->obr; @@ -682,12 +693,10 @@ static OcclusionTree *occ_tree_build(Render *re) tree->maxdepth= 1; occ_build_recursive(tree, tree->root, 0, totface, 1); -#if 0 - if(tree->doindirect) { + if(re->wrld.ao_indirect_energy != 0.0f) { occ_build_shade(re, tree); occ_sum_occlusion(tree, tree->root); } -#endif MEM_freeN(tree->co); tree->co= NULL; @@ -710,8 +719,9 @@ static void occ_free_tree(OcclusionTree *tree) if(tree->stack[a]) MEM_freeN(tree->stack[a]); if(tree->occlusion) MEM_freeN(tree->occlusion); - if(tree->face) MEM_freeN(tree->face); if(tree->cache) MEM_freeN(tree->cache); + if(tree->face) MEM_freeN(tree->face); + if(tree->rad) MEM_freeN(tree->rad); MEM_freeN(tree); } } @@ -1171,13 +1181,13 @@ static float occ_form_factor(OccFace *face, float *p, float *n) return contrib; } -static void occ_lookup(OcclusionTree *tree, int thread, OccFace *exclude, float *pp, float *pn, float *occ, float *bentn) +static void occ_lookup(OcclusionTree *tree, int thread, OccFace *exclude, float *pp, float *pn, float *occ, float rad[3], float bentn[3]) { OccNode *node, **stack; OccFace *face; - float resultocc, v[3], p[3], n[3], co[3], invd2; + float resultocc, resultrad[3], v[3], p[3], n[3], co[3], invd2; float distfac, fac, error, d2, weight, emitarea; - int b, totstack; + int b, f, totstack; /* init variables */ VECCOPY(p, pp); @@ -1185,12 +1195,13 @@ static void occ_lookup(OcclusionTree *tree, int thread, OccFace *exclude, float VECADDFAC(p, p, n, 1e-4f); if(bentn) - VECCOPY(bentn, n); + copy_v3_v3(bentn, n); error= tree->error; distfac= tree->distfac; resultocc= 0.0f; + zero_v3(resultrad); /* init stack */ stack= tree->stack[thread]; @@ -1217,6 +1228,10 @@ static void occ_lookup(OcclusionTree *tree, int thread, OccFace *exclude, float /* accumulate occlusion from spherical harmonics */ invd2 = 1.0f/sqrtf(d2); weight= occ_solid_angle(node, v, d2, invd2, n); + + if(rad) + madd_v3_v3fl(resultrad, node->rad, weight*fac); + weight *= node->occlusion; if(bentn) { @@ -1231,7 +1246,8 @@ static void occ_lookup(OcclusionTree *tree, int thread, OccFace *exclude, float /* traverse into children */ for(b=0; b<TOTCHILD; b++) { if(node->childflag & (1<<b)) { - face= tree->face+node->child[b].face; + f= node->child[b].face; + face= &tree->face[f]; /* accumulate occlusion with face form factor */ if(!exclude || !(face->obi == exclude->obi && face->facenr == exclude->facenr)) { @@ -1248,7 +1264,11 @@ static void occ_lookup(OcclusionTree *tree, int thread, OccFace *exclude, float fac= 1.0f; weight= occ_form_factor(face, p, n); - weight *= tree->occlusion[node->child[b].face]; + + if(rad) + madd_v3_v3fl(resultrad, tree->rad[f], weight*fac); + + weight *= tree->occlusion[f]; if(bentn) { invd2= 1.0f/sqrtf(d2); @@ -1269,15 +1289,24 @@ static void occ_lookup(OcclusionTree *tree, int thread, OccFace *exclude, float } if(occ) *occ= resultocc; + if(rad) copy_v3_v3(rad, resultrad); + /*if(rad && exclude) { + int a; + for(a=0; a<tree->totface; a++) + if((tree->face[a].obi == exclude->obi && tree->face[a].facenr == exclude->facenr)) + copy_v3_v3(rad, tree->rad[a]); + }*/ if(bentn) normalize_v3(bentn); } static void occ_compute_passes(Render *re, OcclusionTree *tree, int totpass) { - float *occ, co[3], n[3]; + float *occ, (*rad)[3]= NULL, co[3], n[3]; int pass, i; occ= MEM_callocN(sizeof(float)*tree->totface, "OcclusionPassOcc"); + if(tree->rad) + rad= MEM_callocN(sizeof(float)*3*tree->totface, "OcclusionPassRad"); for(pass=0; pass<totpass; pass++) { for(i=0; i<tree->totface; i++) { @@ -1285,7 +1314,7 @@ static void occ_compute_passes(Render *re, OcclusionTree *tree, int totpass) negate_v3(n); VECADDFAC(co, co, n, 1e-8f); - occ_lookup(tree, 0, &tree->face[i], co, n, &occ[i], NULL); + occ_lookup(tree, 0, &tree->face[i], co, n, &occ[i], NULL, (rad)? rad[i]: NULL); if(re->test_break(re->tbh)) break; } @@ -1297,27 +1326,41 @@ static void occ_compute_passes(Render *re, OcclusionTree *tree, int totpass) tree->occlusion[i] -= occ[i]; //MAX2(1.0f-occ[i], 0.0f); if(tree->occlusion[i] < 0.0f) tree->occlusion[i]= 0.0f; + + if(rad) { + sub_v3_v3(tree->rad[i], rad[i]); + + if(tree->rad[i][0] < 0.0f) + tree->rad[i][0]= 0.0f; + if(tree->rad[i][1] < 0.0f) + tree->rad[i][1]= 0.0f; + if(tree->rad[i][2] < 0.0f) + tree->rad[i][2]= 0.0f; + } } occ_sum_occlusion(tree, tree->root); } MEM_freeN(occ); + if(rad) + MEM_freeN(rad); } -static void sample_occ_tree(Render *re, OcclusionTree *tree, OccFace *exclude, float *co, float *n, int thread, int onlyshadow, float *skycol) +static void sample_occ_tree(Render *re, OcclusionTree *tree, OccFace *exclude, float *co, float *n, int thread, int onlyshadow, float *ao, float *indirect) { - float nn[3], bn[3], fac, occ, occlusion, correction; - int aocolor; + float nn[3], bn[3], fac, occ, occlusion, correction, rad[3]; + int aocolor, aorad; aocolor= re->wrld.aocolor; if(onlyshadow) aocolor= WO_AOPLAIN; + aorad= (re->wrld.ao_indirect_energy != 0.0f); VECCOPY(nn, n); negate_v3(nn); - occ_lookup(tree, thread, exclude, co, nn, &occ, (aocolor)? bn: NULL); + occ_lookup(tree, thread, exclude, co, nn, &occ, (aorad)? rad: NULL, (aocolor)? bn: NULL); correction= re->wrld.ao_approx_correction; @@ -1330,9 +1373,9 @@ static void sample_occ_tree(Render *re, OcclusionTree *tree, OccFace *exclude, f /* sky shading using bent normal */ if(ELEM(aocolor, WO_AOSKYCOL, WO_AOSKYTEX)) { fac= 0.5*(1.0f+bn[0]*re->grvec[0]+ bn[1]*re->grvec[1]+ bn[2]*re->grvec[2]); - skycol[0]= (1.0f-fac)*re->wrld.horr + fac*re->wrld.zenr; - skycol[1]= (1.0f-fac)*re->wrld.horg + fac*re->wrld.zeng; - skycol[2]= (1.0f-fac)*re->wrld.horb + fac*re->wrld.zenb; + ao[0]= (1.0f-fac)*re->wrld.horr + fac*re->wrld.zenr; + ao[1]= (1.0f-fac)*re->wrld.horg + fac*re->wrld.zeng; + ao[2]= (1.0f-fac)*re->wrld.horb + fac*re->wrld.zenb; } #if 0 else { /* WO_AOSKYTEX */ @@ -1343,17 +1386,20 @@ static void sample_occ_tree(Render *re, OcclusionTree *tree, OccFace *exclude, f dxyview[0]= 1.0f; dxyview[1]= 1.0f; dxyview[2]= 0.0f; - shadeSkyView(skycol, co, bn, dxyview); + shadeSkyView(ao, co, bn, dxyview); } #endif - mul_v3_fl(skycol, occlusion); + mul_v3_fl(ao, occlusion); } else { - skycol[0]= occlusion; - skycol[1]= occlusion; - skycol[2]= occlusion; + ao[0]= occlusion; + ao[1]= occlusion; + ao[2]= occlusion; } + + if(aorad) copy_v3_v3(indirect, rad); + else zero_v3(indirect); } /* ---------------------------- Caching ------------------------------- */ @@ -1374,7 +1420,7 @@ static OcclusionCacheSample *find_occ_sample(OcclusionCache *cache, int x, int y return &cache->sample[y*cache->w + x]; } -static int sample_occ_cache(OcclusionTree *tree, float *co, float *n, int x, int y, int thread, float *col) +static int sample_occ_cache(OcclusionTree *tree, float *co, float *n, int x, int y, int thread, float *ao, float *indirect) { OcclusionCache *cache; OcclusionCacheSample *samples[4], *sample; @@ -1394,7 +1440,8 @@ static int sample_occ_cache(OcclusionTree *tree, float *co, float *n, int x, int VECSUB(d, sample->co, co); dist2= INPR(d, d); if(dist2 < 0.5f*sample->dist2 && INPR(sample->n, n) > 0.98f) { - VECCOPY(col, sample->col); + VECCOPY(ao, sample->ao); + VECCOPY(indirect, sample->indirect); return 1; } } @@ -1420,7 +1467,8 @@ static int sample_occ_cache(OcclusionTree *tree, float *co, float *n, int x, int return 0; /* compute weighted interpolation between samples */ - col[0]= col[1]= col[2]= 0.0f; + zero_v3(ao); + zero_v3(indirect); totw= 0.0f; x1= samples[0]->x; @@ -1446,16 +1494,14 @@ static int sample_occ_cache(OcclusionTree *tree, float *co, float *n, int x, int w= wb[i]*wn[i]*wz[i]; totw += w; - col[0] += w*samples[i]->col[0]; - col[1] += w*samples[i]->col[1]; - col[2] += w*samples[i]->col[2]; + madd_v3_v3fl(ao, samples[i]->ao, w); + madd_v3_v3fl(indirect, samples[i]->indirect, w); } if(totw >= 0.9f) { totw= 1.0f/totw; - col[0] *= totw; - col[1] *= totw; - col[2] *= totw; + mul_v3_fl(ao, totw); + mul_v3_fl(indirect, totw); return 1; } @@ -1469,7 +1515,7 @@ static void sample_occ_surface(ShadeInput *shi) int *face, *index = RE_strandren_get_face(shi->obr, strand, 0); float w[4], *co1, *co2, *co3, *co4; - if(mesh && mesh->face && mesh->co && mesh->col && index) { + if(mesh && mesh->face && mesh->co && mesh->ao && index) { face= mesh->face[*index]; co1= mesh->co[face[0]]; @@ -1477,19 +1523,27 @@ static void sample_occ_surface(ShadeInput *shi) co3= mesh->co[face[2]]; co4= (face[3])? mesh->co[face[3]]: NULL; - interp_weights_face_v3( w,co1, co2, co3, co4, strand->vert->co); + interp_weights_face_v3(w, co1, co2, co3, co4, strand->vert->co); + + zero_v3(shi->ao); + zero_v3(shi->indirect); - shi->ao[0]= shi->ao[1]= shi->ao[2]= 0.0f; - VECADDFAC(shi->ao, shi->ao, mesh->col[face[0]], w[0]); - VECADDFAC(shi->ao, shi->ao, mesh->col[face[1]], w[1]); - VECADDFAC(shi->ao, shi->ao, mesh->col[face[2]], w[2]); - if(face[3]) - VECADDFAC(shi->ao, shi->ao, mesh->col[face[3]], w[3]); + madd_v3_v3fl(shi->ao, mesh->ao[face[0]], w[0]); + madd_v3_v3fl(shi->indirect, mesh->indirect[face[0]], w[0]); + madd_v3_v3fl(shi->ao, mesh->ao[face[1]], w[1]); + madd_v3_v3fl(shi->indirect, mesh->indirect[face[1]], w[1]); + madd_v3_v3fl(shi->ao, mesh->ao[face[2]], w[2]); + madd_v3_v3fl(shi->indirect, mesh->indirect[face[2]], w[2]); + if(face[3]) { + madd_v3_v3fl(shi->ao, mesh->ao[face[3]], w[3]); + madd_v3_v3fl(shi->indirect, mesh->indirect[face[3]], w[3]); + } } else { shi->ao[0]= 1.0f; shi->ao[1]= 1.0f; shi->ao[2]= 1.0f; + zero_v3(shi->indirect); } } @@ -1500,7 +1554,7 @@ static void *exec_strandsurface_sample(void *data) OcclusionThread *othread= (OcclusionThread*)data; Render *re= othread->re; StrandSurface *mesh= othread->mesh; - float col[3], co[3], n[3], *co1, *co2, *co3, *co4; + float ao[3], indirect[3], co[3], n[3], *co1, *co2, *co3, *co4; int a, *face; for(a=othread->begin; a<othread->end; a++) { @@ -1521,8 +1575,9 @@ static void *exec_strandsurface_sample(void *data) } negate_v3(n); - sample_occ_tree(re, re->occlusiontree, NULL, co, n, othread->thread, 0, col); - VECCOPY(othread->facecol[a], col); + sample_occ_tree(re, re->occlusiontree, NULL, co, n, othread->thread, 0, ao, indirect); + VECCOPY(othread->faceao[a], ao); + VECCOPY(othread->faceindirect[a], indirect); } return 0; @@ -1533,7 +1588,7 @@ void make_occ_tree(Render *re) OcclusionThread othreads[BLENDER_MAX_THREADS]; StrandSurface *mesh; ListBase threads; - float col[3], (*facecol)[3]; + float ao[3], indirect[3], (*faceao)[3], (*faceindirect)[3]; int a, totface, totthread, *face, *count; /* ugly, needed for occ_face */ @@ -1549,17 +1604,19 @@ void make_occ_tree(Render *re) occ_compute_passes(re, re->occlusiontree, re->wrld.ao_approx_passes); for(mesh=re->strandsurface.first; mesh; mesh=mesh->next) { - if(!mesh->face || !mesh->co || !mesh->col) + if(!mesh->face || !mesh->co || !mesh->ao) continue; count= MEM_callocN(sizeof(int)*mesh->totvert, "OcclusionCount"); - facecol= MEM_callocN(sizeof(float)*3*mesh->totface, "StrandSurfFaceCol"); + faceao= MEM_callocN(sizeof(float)*3*mesh->totface, "StrandSurfFaceAO"); + faceindirect= MEM_callocN(sizeof(float)*3*mesh->totface, "StrandSurfFaceIndirect"); totthread= (mesh->totface > 10000)? re->r.threads: 1; totface= mesh->totface/totthread; for(a=0; a<totthread; a++) { othreads[a].re= re; - othreads[a].facecol= facecol; + othreads[a].faceao= faceao; + othreads[a].faceindirect= faceindirect; othreads[a].thread= a; othreads[a].mesh= mesh; othreads[a].begin= a*totface; @@ -1581,26 +1638,36 @@ void make_occ_tree(Render *re) for(a=0; a<mesh->totface; a++) { face= mesh->face[a]; - VECCOPY(col, facecol[a]); - VECADD(mesh->col[face[0]], mesh->col[face[0]], col); + VECCOPY(ao, faceao[a]); + VECCOPY(indirect, faceindirect[a]); + + VECADD(mesh->ao[face[0]], mesh->ao[face[0]], ao); + VECADD(mesh->indirect[face[0]], mesh->indirect[face[0]], indirect); count[face[0]]++; - VECADD(mesh->col[face[1]], mesh->col[face[1]], col); + VECADD(mesh->ao[face[1]], mesh->ao[face[1]], ao); + VECADD(mesh->indirect[face[1]], mesh->indirect[face[1]], indirect); count[face[1]]++; - VECADD(mesh->col[face[2]], mesh->col[face[2]], col); + VECADD(mesh->ao[face[2]], mesh->ao[face[2]], ao); + VECADD(mesh->indirect[face[2]], mesh->indirect[face[2]], indirect); count[face[2]]++; if(face[3]) { - VECADD(mesh->col[face[3]], mesh->col[face[3]], col); + VECADD(mesh->ao[face[3]], mesh->ao[face[3]], ao); + VECADD(mesh->indirect[face[3]], mesh->indirect[face[3]], indirect); count[face[3]]++; } } - for(a=0; a<mesh->totvert; a++) - if(count[a]) - mul_v3_fl(mesh->col[a], 1.0f/count[a]); + for(a=0; a<mesh->totvert; a++) { + if(count[a]) { + mul_v3_fl(mesh->ao[a], 1.0f/count[a]); + mul_v3_fl(mesh->indirect[a], 1.0f/count[a]); + } + } MEM_freeN(count); - MEM_freeN(facecol); + MEM_freeN(faceao); + MEM_freeN(faceindirect); } } } @@ -1626,12 +1693,12 @@ void sample_occ(Render *re, ShadeInput *shi) sample_occ_surface(shi); } /* try to get result from the cache if possible */ - else if(shi->depth!=0 || !sample_occ_cache(tree, shi->co, shi->vno, shi->xs, shi->ys, shi->thread, shi->ao)) { + else if(shi->depth!=0 || !sample_occ_cache(tree, shi->co, shi->vno, shi->xs, shi->ys, shi->thread, shi->ao, shi->indirect)) { /* no luck, let's sample the occlusion */ exclude.obi= shi->obi - re->objectinstance; exclude.facenr= shi->vlr->index; onlyshadow= (shi->mat->mode & MA_ONLYSHADOW); - sample_occ_tree(re, tree, &exclude, shi->co, shi->vno, shi->thread, onlyshadow, shi->ao); + sample_occ_tree(re, tree, &exclude, shi->co, shi->vno, shi->thread, onlyshadow, shi->ao, shi->indirect); /* fill result into sample, each time */ if(tree->cache) { @@ -1641,8 +1708,10 @@ void sample_occ(Render *re, ShadeInput *shi) sample= &cache->sample[(shi->ys-cache->y)*cache->w + (shi->xs-cache->x)]; VECCOPY(sample->co, shi->co); VECCOPY(sample->n, shi->vno); - VECCOPY(sample->col, shi->ao); - sample->intensity= MAX3(sample->col[0], sample->col[1], sample->col[2]); + VECCOPY(sample->ao, shi->ao); + VECCOPY(sample->indirect, shi->indirect); + sample->intensity= MAX3(sample->ao[0], sample->ao[1], sample->ao[2]); + sample->intensity= MAX2(sample->intensity, MAX3(sample->indirect[0], sample->indirect[1], sample->indirect[2])); sample->dist2= INPR(shi->dxco, shi->dxco) + INPR(shi->dyco, shi->dyco); sample->filled= 1; } @@ -1653,6 +1722,10 @@ void sample_occ(Render *re, ShadeInput *shi) shi->ao[0]= 1.0f; shi->ao[1]= 1.0f; shi->ao[2]= 1.0f; + + shi->indirect[0]= 0.0f; + shi->indirect[1]= 0.0f; + shi->indirect[2]= 0.0f; } } @@ -1720,12 +1793,14 @@ void cache_occ_samples(Render *re, RenderPart *pa, ShadeSample *ssamp) onlyshadow= (shi->mat->mode & MA_ONLYSHADOW); exclude.obi= shi->obi - re->objectinstance; exclude.facenr= shi->vlr->index; - sample_occ_tree(re, tree, &exclude, shi->co, shi->vno, shi->thread, onlyshadow, shi->ao); + sample_occ_tree(re, tree, &exclude, shi->co, shi->vno, shi->thread, onlyshadow, shi->ao, shi->indirect); VECCOPY(sample->co, shi->co); VECCOPY(sample->n, shi->vno); - VECCOPY(sample->col, shi->ao); - sample->intensity= MAX3(sample->col[0], sample->col[1], sample->col[2]); + VECCOPY(sample->ao, shi->ao); + VECCOPY(sample->indirect, shi->indirect); + sample->intensity= MAX3(sample->ao[0], sample->ao[1], sample->ao[2]); + sample->intensity= MAX2(sample->intensity, MAX3(sample->indirect[0], sample->indirect[1], sample->indirect[2])); sample->dist2= INPR(shi->dxco, shi->dxco) + INPR(shi->dyco, shi->dyco); sample->x= shi->xs; sample->y= shi->ys; diff --git a/source/blender/render/intern/source/shadeoutput.c b/source/blender/render/intern/source/shadeoutput.c index f167122f497..958a2e34215 100644 --- a/source/blender/render/intern/source/shadeoutput.c +++ b/source/blender/render/intern/source/shadeoutput.c @@ -1041,6 +1041,7 @@ void ambient_occlusion_to_diffuse(ShadeInput *shi, float *diff) } VECMUL(diff, f); + madd_v3_v3fl(diff, shi->indirect, R.wrld.ao_indirect_energy*shi->amb); } else diff[0]= diff[1]= diff[2]= 0.0f; diff --git a/source/blender/render/intern/source/strand.c b/source/blender/render/intern/source/strand.c index 47a7c052b18..ecea7360974 100644 --- a/source/blender/render/intern/source/strand.c +++ b/source/blender/render/intern/source/strand.c @@ -959,7 +959,8 @@ StrandSurface *cache_strand_surface(Render *re, ObjectRen *obr, DerivedMesh *dm, mesh->totvert= totvert; mesh->totface= totface; mesh->face= MEM_callocN(sizeof(int)*4*mesh->totface, "StrandSurfFaces"); - mesh->col= MEM_callocN(sizeof(float)*3*mesh->totvert, "StrandSurfCol"); + mesh->ao= MEM_callocN(sizeof(float)*3*mesh->totvert, "StrandSurfAO"); + mesh->indirect= MEM_callocN(sizeof(float)*3*mesh->totvert, "StrandSurfIndirect"); BLI_addtail(&re->strandsurface, mesh); } @@ -997,7 +998,8 @@ void free_strand_surface(Render *re) if(mesh->co) MEM_freeN(mesh->co); if(mesh->prevco) MEM_freeN(mesh->prevco); if(mesh->nextco) MEM_freeN(mesh->nextco); - if(mesh->col) MEM_freeN(mesh->col); + if(mesh->ao) MEM_freeN(mesh->ao); + if(mesh->indirect) MEM_freeN(mesh->indirect); if(mesh->face) MEM_freeN(mesh->face); } |