AAO Indirect Diffuse
authorBrecht Van Lommel <brechtvanlommel@pandora.be>
Wed, 2 Dec 2009 11:54:48 +0000 (11:54 +0000)
committerBrecht Van Lommel <brechtvanlommel@pandora.be>
Wed, 2 Dec 2009 11:54:48 +0000 (11:54 +0000)
Don't use passes anymore for indirect lighting, people were using this
probably thinking it would do bounces, but that's not the intention of
this feature, it is to reduce problems with light bleeding. I want to
remove this option for AO as well, but will leave it in for now until
there is a better alternative.

Added bounces option for indirect, could be implemented much better,
but perhaps useful for testing now. Existing files need to set this to
1 to get the same results again.

release/scripts/ui/properties_world.py
source/blender/makesdna/DNA_world_types.h
source/blender/makesrna/intern/rna_world.c
source/blender/render/intern/source/occlusion.c

index ec0e1c42add21ad28996ad74f4ac9ff57d898212..9adc8d0bad48b2812a7e411bef31aca04f8c5b7a 100644 (file)
@@ -224,6 +224,7 @@ class WORLD_PT_ambient_occlusion(WorldButtonsPanel):
         if wide_ui:
             col = split.column()
         col.prop(ao, "color")
+        col.prop(ao, "indirect_bounces")
 
 bpy.types.register(WORLD_PT_context_world)
 bpy.types.register(WORLD_PT_preview)
index 11ecbf97d974a5e0bf26621f6ae9793546297a52..9b3f78caee0662176e5052b23120a3fac7ecaf4f 100644 (file)
@@ -107,7 +107,8 @@ 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;
+       float ao_indirect_energy;
+       short ao_indirect_bounces, ao_pad;
        short ao_samp_method, ao_gather_method, ao_approx_passes;
        
        /* assorted settings (in the middle of ambient occlusion settings for padding reasons) */
index 88992387148ae5b3c244e4be1d228da8f8e0469e..231faffef0fe8a4f5df8798ef1f9f5d9148fde4f 100644 (file)
@@ -318,6 +318,11 @@ static void rna_def_ambient_occlusion(BlenderRNA *brna)
        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");
+
+       prop= RNA_def_property(srna, "indirect_bounces", PROP_INT, PROP_UNSIGNED);
+       RNA_def_property_int_sdna(prop, NULL, "ao_indirect_bounces");
+       RNA_def_property_ui_text(prop, "Bounces", "Number of indirect diffuse light bounces to use for approximate ambient occlusion.");
+       RNA_def_property_update(prop, 0, "rna_World_update");
 }
 
 static void rna_def_world_mist(BlenderRNA *brna)
index 90929db2f74d4ce3f2a0facb02455046f5231034..3a5680eaf705cdaa1285994f9b82c5835e588248 100644 (file)
@@ -111,6 +111,7 @@ typedef struct OcclusionTree {
 
        int dothreadedbuild;
        int totbuildthread;
+       int doindirect;
 
        OcclusionCache *cache;
 } OcclusionTree;
@@ -652,6 +653,7 @@ static OcclusionTree *occ_tree_build(Render *re)
        /* parameters */
        tree->error= get_render_aosss_error(&re->r, re->wrld.ao_approx_error);
        tree->distfac= (re->wrld.aomode & WO_AODIST)? re->wrld.aodistfac: 0.0f;
+       tree->doindirect= (re->wrld.ao_indirect_energy > 0.0f && re->wrld.ao_indirect_bounces > 0);
 
        /* allocation */
        tree->arena= BLI_memarena_new(0x8000 * sizeof(OccNode));
@@ -664,7 +666,7 @@ 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)
+       if(tree->doindirect)
                tree->rad= MEM_callocN(sizeof(float)*3*totface, "OcclusionRad");
 
        /* make array of face pointers */
@@ -693,7 +695,7 @@ static OcclusionTree *occ_tree_build(Render *re)
        tree->maxdepth= 1;
        occ_build_recursive(tree, tree->root, 0, totface, 1);
 
-       if(re->wrld.ao_indirect_energy != 0.0f) {
+       if(tree->doindirect) {
                occ_build_shade(re, tree);
                occ_sum_occlusion(tree, tree->root);
        }
@@ -1299,14 +1301,53 @@ static void occ_lookup(OcclusionTree *tree, int thread, OccFace *exclude, float
        if(bentn) normalize_v3(bentn);
 }
 
+static void occ_compute_bounces(Render *re, OcclusionTree *tree, int totbounce)
+{
+       float (*rad)[3], (*sum)[3], (*tmp)[3], co[3], n[3], occ;
+       int bounce, i;
+
+       rad= MEM_callocN(sizeof(float)*3*tree->totface, "OcclusionBounceRad");
+       sum= MEM_dupallocN(tree->rad);
+
+       for(bounce=1; bounce<totbounce; bounce++) {
+               for(i=0; i<tree->totface; i++) {
+                       occ_face(&tree->face[i], co, n, NULL);
+                       madd_v3_v3fl(co, n, 1e-8f);
+
+                       occ_lookup(tree, 0, &tree->face[i], co, n, &occ, rad[i], NULL);
+                       rad[i][0]= MAX2(rad[i][0], 0.0f);
+                       rad[i][1]= MAX2(rad[i][1], 0.0f);
+                       rad[i][2]= MAX2(rad[i][2], 0.0f);
+                       add_v3_v3(sum[i], rad[i]);
+
+                       if(re->test_break(re->tbh))
+                               break;
+               }
+
+               if(re->test_break(re->tbh))
+                       break;
+
+               tmp= tree->rad;
+               tree->rad= rad;
+               rad= tmp;
+
+               occ_sum_occlusion(tree, tree->root);
+       }
+
+       MEM_freeN(rad);
+       MEM_freeN(tree->rad);
+       tree->rad= sum;
+
+       if(!re->test_break(re->tbh))
+               occ_sum_occlusion(tree, tree->root);
+}
+
 static void occ_compute_passes(Render *re, OcclusionTree *tree, int totpass)
 {
-       float *occ, (*rad)[3]= NULL, co[3], n[3];
+       float *occ, 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++) {
@@ -1314,7 +1355,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, (rad)? rad[i]: NULL);
+                       occ_lookup(tree, 0, &tree->face[i], co, n, &occ[i], NULL, NULL);
                        if(re->test_break(re->tbh))
                                break;
                }
@@ -1326,41 +1367,27 @@ 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 *ao, float *indirect)
 {
        float nn[3], bn[3], fac, occ, occlusion, correction, rad[3];
-       int aocolor, aorad;
+       int aocolor;
 
        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, (aorad)? rad: NULL, (aocolor)? bn: NULL);
+       occ_lookup(tree, thread, exclude, co, nn, &occ, (tree->doindirect)? rad: NULL, (aocolor)? bn: NULL);
 
        correction= re->wrld.ao_approx_correction;
 
@@ -1398,7 +1425,7 @@ static void sample_occ_tree(Render *re, OcclusionTree *tree, OccFace *exclude, f
                ao[2]= occlusion;
        }
 
-       if(aorad) copy_v3_v3(indirect, rad);
+       if(tree->doindirect) copy_v3_v3(indirect, rad);
        else zero_v3(indirect);
 }
 
@@ -1600,8 +1627,10 @@ void make_occ_tree(Render *re)
        re->occlusiontree= occ_tree_build(re);
        
        if(re->occlusiontree) {
-               if(re->wrld.ao_approx_passes)
+               if(re->wrld.ao_approx_passes > 0)
                        occ_compute_passes(re, re->occlusiontree, re->wrld.ao_approx_passes);
+               if(re->wrld.ao_indirect_bounces > 1)
+                       occ_compute_bounces(re, re->occlusiontree, re->wrld.ao_indirect_bounces);
 
                for(mesh=re->strandsurface.first; mesh; mesh=mesh->next) {
                        if(!mesh->face || !mesh->co || !mesh->ao)