Approximate AO: Diffuse Bounce Hack
authorBrecht Van Lommel <brechtvanlommel@pandora.be>
Mon, 30 Nov 2009 18:42:13 +0000 (18:42 +0000)
committerBrecht Van Lommel <brechtvanlommel@pandora.be>
Mon, 30 Nov 2009 18:42:13 +0000 (18:42 +0000)
This brings back the single bounce indirect diffuse lighting for AAO,
it's not integrated well but that will be tackled later as part of
shading system refactor and subdivision changes. The caveats are the
same as AAO, with one extra thing, the diffuse lighting is sampled once
per face, so it will not be accurate unless faces are subdivided.

I'm committing this now so we can start testing it for Durian, and
since changes need to make it work properly are planned.

release/scripts/ui/properties_world.py
source/blender/makesdna/DNA_world_types.h
source/blender/makesrna/intern/rna_world.c
source/blender/render/extern/include/RE_shader_ext.h
source/blender/render/intern/include/render_types.h
source/blender/render/intern/source/occlusion.c
source/blender/render/intern/source/shadeoutput.c
source/blender/render/intern/source/strand.c

index 4f662df8cc81a37841592afaefa9b63ee1d51ebb..ec0e1c42add21ad28996ad74f4ac9ff57d898212 100644 (file)
@@ -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()
index 64ff23dd1a888dcf2525d9bc0f8a81bf0d7a3d33..11ecbf97d974a5e0bf26621f6ae9793546297a52 100644 (file)
@@ -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) */
index c0c9c1d6568715a2dfb42518cfa7ebc7f6ef644d..88992387148ae5b3c244e4be1d228da8f8e0469e 100644 (file)
@@ -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)
index b36163f57c0a08deff1d27588e8cf377ca0269c8..2615be1440a4f6c0bfe801e2266b2df34a034ef7 100644 (file)
@@ -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 */
index 48bf34d06963629e6d984ef71a2b5d97577ffa03..d41851db5ffd7deb45b24c60bf4119bacea97e42 100644 (file)
@@ -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;
index f62668b84c007ce05997b9589164cc889208d180..90929db2f74d4ce3f2a0facb02455046f5231034 100644 (file)
@@ -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;
index f167122f49719a17106d91af3bc5f85a7966849c..958a2e3421510547d9db13d074ad38e292cc9733 100644 (file)
@@ -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;
index 47a7c052b1863168b052ea4a3712e11dff937c77..ecea7360974cac4cc6eeca8db6febfe84dfcbffa 100644 (file)
@@ -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);
        }