Approximate AO: Diffuse Bounce Hack

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.
This commit is contained in:
2009-11-30 18:42:13 +00:00
parent 4a4fff5b21
commit afe475b55b
8 changed files with 164 additions and 77 deletions

View File

@@ -219,6 +219,7 @@ class WORLD_PT_ambient_occlusion(WorldButtonsPanel):
col = split.column() col = split.column()
col.prop(ao, "energy") col.prop(ao, "energy")
col.prop(ao, "indirect_energy")
if wide_ui: if wide_ui:
col = split.column() col = split.column()

View File

@@ -107,6 +107,7 @@ typedef struct World {
short aomode, aosamp, aomix, aocolor; short aomode, aosamp, aomix, aocolor;
float ao_adapt_thresh, ao_adapt_speed_fac; float ao_adapt_thresh, ao_adapt_speed_fac;
float ao_approx_error, ao_approx_correction; float ao_approx_error, ao_approx_correction;
float ao_indirect_energy, aopad;
short ao_samp_method, ao_gather_method, ao_approx_passes; short ao_samp_method, ao_gather_method, ao_approx_passes;
/* assorted settings (in the middle of ambient occlusion settings for padding reasons) */ /* assorted settings (in the middle of ambient occlusion settings for padding reasons) */

View File

@@ -312,6 +312,12 @@ static void rna_def_ambient_occlusion(BlenderRNA *brna)
RNA_def_property_range(prop, 0, 10); 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_ui_text(prop, "Passes", "Number of preprocessing passes to reduce overocclusion (for Approximate).");
RNA_def_property_update(prop, 0, "rna_World_update"); 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) static void rna_def_world_mist(BlenderRNA *brna)

View File

@@ -153,7 +153,7 @@ typedef struct ShadeInput
float dxstrand, dystrand; float dxstrand, dystrand;
/* AO is a pre-process now */ /* AO is a pre-process now */
float ao[3]; float ao[3], indirect[3];
int xs, ys; /* pixel to be rendered */ int xs, ys; /* pixel to be rendered */
int mask; /* subsample mask */ int mask; /* subsample mask */

View File

@@ -398,7 +398,8 @@ typedef struct StrandSurface {
int (*face)[4]; int (*face)[4];
float (*co)[3]; float (*co)[3];
/* for occlusion caching */ /* for occlusion caching */
float (*col)[3]; float (*ao)[3];
float (*indirect)[3];
/* for speedvectors */ /* for speedvectors */
float (*prevco)[3], (*nextco)[3]; float (*prevco)[3], (*nextco)[3];
int totvert, totface; int totvert, totface;

View File

@@ -64,7 +64,7 @@
#define CACHE_STEP 3 #define CACHE_STEP 3
typedef struct OcclusionCacheSample { 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; int x, y, filled;
} OcclusionCacheSample; } OcclusionCacheSample;
@@ -81,7 +81,7 @@ typedef struct OccFace {
typedef struct OccNode { typedef struct OccNode {
float co[3], area; float co[3], area;
float sh[9], dco; float sh[9], dco;
float occlusion; float occlusion, rad[3];
int childflag; int childflag;
union { union {
//OccFace face; //OccFace face;
@@ -97,6 +97,7 @@ typedef struct OcclusionTree {
OccFace *face; /* instance and face indices */ OccFace *face; /* instance and face indices */
float *occlusion; /* occlusion for faces */ float *occlusion; /* occlusion for faces */
float (*rad)[3]; /* radiance for faces */
OccNode *root; OccNode *root;
@@ -117,7 +118,8 @@ typedef struct OcclusionTree {
typedef struct OcclusionThread { typedef struct OcclusionThread {
Render *re; Render *re;
StrandSurface *mesh; StrandSurface *mesh;
float (*facecol)[3]; float (*faceao)[3];
float (*faceindirect)[3];
int begin, end; int begin, end;
int thread; int thread;
} OcclusionThread; } OcclusionThread;
@@ -132,7 +134,6 @@ typedef struct OcclusionBuildThread {
extern Render R; // meh extern Render R; // meh
#if 0
static void occ_shade(ShadeSample *ssamp, ObjectInstanceRen *obi, VlakRen *vlr, float *rad) static void occ_shade(ShadeSample *ssamp, ObjectInstanceRen *obi, VlakRen *vlr, float *rad)
{ {
ShadeInput *shi= ssamp->shi; 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[0]= l*v3[0]+u*v1[0]+v*v2[0];
shi->co[1]= l*v3[1]+u*v1[1]+v*v2[1]; shi->co[1]= l*v3[1]+u*v1[1]+v*v2[1];
shi->co[2]= l*v3[2]+u*v1[2]+v*v2[2]; shi->co[2]= l*v3[2]+u*v1[2]+v*v2[2];
shade_input_set_triangle_i(shi, obi, vlr, 0, 1, 2); shade_input_set_triangle_i(shi, obi, vlr, 0, 1, 2);
/* set up view vector */ /* set up view vector */
@@ -179,6 +180,8 @@ static void occ_shade(ShadeSample *ssamp, ObjectInstanceRen *obi, VlakRen *vlr,
if(shi->flippednor) if(shi->flippednor)
shade_input_flip_normals(shi); shade_input_flip_normals(shi);
madd_v3_v3fl(shi->co, shi->vn, 0.0001f); /* ugly.. */
/* not a pretty solution, but fixes common cases */ /* not a pretty solution, but fixes common cases */
if(shi->obr->ob && shi->obr->ob->transflag & OB_NEG_SCALE) { if(shi->obr->ob && shi->obr->ob->transflag & OB_NEG_SCALE) {
negate_v3(shi->vn); negate_v3(shi->vn);
@@ -215,12 +218,11 @@ static void occ_build_shade(Render *re, OcclusionTree *tree)
for(a=0; a<tree->totface; a++) { for(a=0; a<tree->totface; a++) {
obi= &R.objectinstance[tree->face[a].obi]; 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]); occ_shade(&ssamp, obi, vlr, tree->rad[a]);
} }
} }
#endif
/* ------------------------- Spherical Harmonics --------------------------- */ /* ------------------------- 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) static void occ_sum_occlusion(OcclusionTree *tree, OccNode *node)
{ {
OccNode *child; OccNode *child;
float occ, area, totarea; float occ, area, totarea, rad[3];
int a, b; int a, b;
occ= 0.0f; occ= 0.0f;
totarea= 0.0f; totarea= 0.0f;
zero_v3(rad);
for(b=0; b<TOTCHILD; b++) { for(b=0; b<TOTCHILD; b++) {
if(node->childflag & (1<<b)) { if(node->childflag & (1<<b)) {
a= node->child[b].face; a= node->child[b].face;
occ_face(&tree->face[a], 0, 0, &area); occ_face(&tree->face[a], 0, 0, &area);
occ += area*tree->occlusion[a]; occ += area*tree->occlusion[a];
madd_v3_v3fl(rad, tree->rad[a], area);
totarea += area; totarea += area;
} }
else if(node->child[b].node) { 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_sum_occlusion(tree, child);
occ += child->area*child->occlusion; occ += child->area*child->occlusion;
madd_v3_v3fl(rad, child->rad, child->area);
totarea += child->area; totarea += child->area;
} }
} }
if(totarea != 0.0f) if(totarea != 0.0f) {
occ /= totarea; occ /= totarea;
mul_v3_fl(rad, 1.0f/totarea);
}
node->occlusion= occ; 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) 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->co= MEM_callocN(sizeof(float)*3*totface, "OcclusionCo");
tree->occlusion= MEM_callocN(sizeof(float)*totface, "OcclusionOcclusion"); 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 */ /* make array of face pointers */
for(b=0, c=0, obi=re->instancetable.first; obi; obi=obi->next, c++) { for(b=0, c=0, obi=re->instancetable.first; obi; obi=obi->next, c++) {
obr= obi->obr; obr= obi->obr;
@@ -682,12 +693,10 @@ static OcclusionTree *occ_tree_build(Render *re)
tree->maxdepth= 1; tree->maxdepth= 1;
occ_build_recursive(tree, tree->root, 0, totface, 1); occ_build_recursive(tree, tree->root, 0, totface, 1);
#if 0 if(re->wrld.ao_indirect_energy != 0.0f) {
if(tree->doindirect) {
occ_build_shade(re, tree); occ_build_shade(re, tree);
occ_sum_occlusion(tree, tree->root); occ_sum_occlusion(tree, tree->root);
} }
#endif
MEM_freeN(tree->co); MEM_freeN(tree->co);
tree->co= NULL; tree->co= NULL;
@@ -710,8 +719,9 @@ static void occ_free_tree(OcclusionTree *tree)
if(tree->stack[a]) if(tree->stack[a])
MEM_freeN(tree->stack[a]); MEM_freeN(tree->stack[a]);
if(tree->occlusion) MEM_freeN(tree->occlusion); if(tree->occlusion) MEM_freeN(tree->occlusion);
if(tree->face) MEM_freeN(tree->face);
if(tree->cache) MEM_freeN(tree->cache); if(tree->cache) MEM_freeN(tree->cache);
if(tree->face) MEM_freeN(tree->face);
if(tree->rad) MEM_freeN(tree->rad);
MEM_freeN(tree); MEM_freeN(tree);
} }
} }
@@ -1171,13 +1181,13 @@ static float occ_form_factor(OccFace *face, float *p, float *n)
return contrib; 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; OccNode *node, **stack;
OccFace *face; 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; float distfac, fac, error, d2, weight, emitarea;
int b, totstack; int b, f, totstack;
/* init variables */ /* init variables */
VECCOPY(p, pp); VECCOPY(p, pp);
@@ -1185,12 +1195,13 @@ static void occ_lookup(OcclusionTree *tree, int thread, OccFace *exclude, float
VECADDFAC(p, p, n, 1e-4f); VECADDFAC(p, p, n, 1e-4f);
if(bentn) if(bentn)
VECCOPY(bentn, n); copy_v3_v3(bentn, n);
error= tree->error; error= tree->error;
distfac= tree->distfac; distfac= tree->distfac;
resultocc= 0.0f; resultocc= 0.0f;
zero_v3(resultrad);
/* init stack */ /* init stack */
stack= tree->stack[thread]; stack= tree->stack[thread];
@@ -1217,6 +1228,10 @@ static void occ_lookup(OcclusionTree *tree, int thread, OccFace *exclude, float
/* accumulate occlusion from spherical harmonics */ /* accumulate occlusion from spherical harmonics */
invd2 = 1.0f/sqrtf(d2); invd2 = 1.0f/sqrtf(d2);
weight= occ_solid_angle(node, v, d2, invd2, n); weight= occ_solid_angle(node, v, d2, invd2, n);
if(rad)
madd_v3_v3fl(resultrad, node->rad, weight*fac);
weight *= node->occlusion; weight *= node->occlusion;
if(bentn) { if(bentn) {
@@ -1231,7 +1246,8 @@ static void occ_lookup(OcclusionTree *tree, int thread, OccFace *exclude, float
/* traverse into children */ /* traverse into children */
for(b=0; b<TOTCHILD; b++) { for(b=0; b<TOTCHILD; b++) {
if(node->childflag & (1<<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 */ /* accumulate occlusion with face form factor */
if(!exclude || !(face->obi == exclude->obi && face->facenr == exclude->facenr)) { 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; fac= 1.0f;
weight= occ_form_factor(face, p, n); 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) { if(bentn) {
invd2= 1.0f/sqrtf(d2); 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(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); if(bentn) normalize_v3(bentn);
} }
static void occ_compute_passes(Render *re, OcclusionTree *tree, int totpass) 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; int pass, i;
occ= MEM_callocN(sizeof(float)*tree->totface, "OcclusionPassOcc"); 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(pass=0; pass<totpass; pass++) {
for(i=0; i<tree->totface; i++) { 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); negate_v3(n);
VECADDFAC(co, co, n, 1e-8f); 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)) if(re->test_break(re->tbh))
break; 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); tree->occlusion[i] -= occ[i]; //MAX2(1.0f-occ[i], 0.0f);
if(tree->occlusion[i] < 0.0f) if(tree->occlusion[i] < 0.0f)
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); occ_sum_occlusion(tree, tree->root);
} }
MEM_freeN(occ); 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; float nn[3], bn[3], fac, occ, occlusion, correction, rad[3];
int aocolor; int aocolor, aorad;
aocolor= re->wrld.aocolor; aocolor= re->wrld.aocolor;
if(onlyshadow) if(onlyshadow)
aocolor= WO_AOPLAIN; aocolor= WO_AOPLAIN;
aorad= (re->wrld.ao_indirect_energy != 0.0f);
VECCOPY(nn, n); VECCOPY(nn, n);
negate_v3(nn); 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; 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 */ /* sky shading using bent normal */
if(ELEM(aocolor, WO_AOSKYCOL, WO_AOSKYTEX)) { 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]); 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; ao[0]= (1.0f-fac)*re->wrld.horr + fac*re->wrld.zenr;
skycol[1]= (1.0f-fac)*re->wrld.horg + fac*re->wrld.zeng; ao[1]= (1.0f-fac)*re->wrld.horg + fac*re->wrld.zeng;
skycol[2]= (1.0f-fac)*re->wrld.horb + fac*re->wrld.zenb; ao[2]= (1.0f-fac)*re->wrld.horb + fac*re->wrld.zenb;
} }
#if 0 #if 0
else { /* WO_AOSKYTEX */ else { /* WO_AOSKYTEX */
@@ -1343,17 +1386,20 @@ static void sample_occ_tree(Render *re, OcclusionTree *tree, OccFace *exclude, f
dxyview[0]= 1.0f; dxyview[0]= 1.0f;
dxyview[1]= 1.0f; dxyview[1]= 1.0f;
dxyview[2]= 0.0f; dxyview[2]= 0.0f;
shadeSkyView(skycol, co, bn, dxyview); shadeSkyView(ao, co, bn, dxyview);
} }
#endif #endif
mul_v3_fl(skycol, occlusion); mul_v3_fl(ao, occlusion);
} }
else { else {
skycol[0]= occlusion; ao[0]= occlusion;
skycol[1]= occlusion; ao[1]= occlusion;
skycol[2]= occlusion; ao[2]= occlusion;
} }
if(aorad) copy_v3_v3(indirect, rad);
else zero_v3(indirect);
} }
/* ---------------------------- Caching ------------------------------- */ /* ---------------------------- Caching ------------------------------- */
@@ -1374,7 +1420,7 @@ static OcclusionCacheSample *find_occ_sample(OcclusionCache *cache, int x, int y
return &cache->sample[y*cache->w + x]; 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; OcclusionCache *cache;
OcclusionCacheSample *samples[4], *sample; 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); VECSUB(d, sample->co, co);
dist2= INPR(d, d); dist2= INPR(d, d);
if(dist2 < 0.5f*sample->dist2 && INPR(sample->n, n) > 0.98f) { 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; return 1;
} }
} }
@@ -1420,7 +1467,8 @@ static int sample_occ_cache(OcclusionTree *tree, float *co, float *n, int x, int
return 0; return 0;
/* compute weighted interpolation between samples */ /* compute weighted interpolation between samples */
col[0]= col[1]= col[2]= 0.0f; zero_v3(ao);
zero_v3(indirect);
totw= 0.0f; totw= 0.0f;
x1= samples[0]->x; 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]; w= wb[i]*wn[i]*wz[i];
totw += w; totw += w;
col[0] += w*samples[i]->col[0]; madd_v3_v3fl(ao, samples[i]->ao, w);
col[1] += w*samples[i]->col[1]; madd_v3_v3fl(indirect, samples[i]->indirect, w);
col[2] += w*samples[i]->col[2];
} }
if(totw >= 0.9f) { if(totw >= 0.9f) {
totw= 1.0f/totw; totw= 1.0f/totw;
col[0] *= totw; mul_v3_fl(ao, totw);
col[1] *= totw; mul_v3_fl(indirect, totw);
col[2] *= totw;
return 1; return 1;
} }
@@ -1469,7 +1515,7 @@ static void sample_occ_surface(ShadeInput *shi)
int *face, *index = RE_strandren_get_face(shi->obr, strand, 0); int *face, *index = RE_strandren_get_face(shi->obr, strand, 0);
float w[4], *co1, *co2, *co3, *co4; 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]; face= mesh->face[*index];
co1= mesh->co[face[0]]; co1= mesh->co[face[0]];
@@ -1477,19 +1523,27 @@ static void sample_occ_surface(ShadeInput *shi)
co3= mesh->co[face[2]]; co3= mesh->co[face[2]];
co4= (face[3])? mesh->co[face[3]]: NULL; 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);
shi->ao[0]= shi->ao[1]= shi->ao[2]= 0.0f; zero_v3(shi->ao);
VECADDFAC(shi->ao, shi->ao, mesh->col[face[0]], w[0]); zero_v3(shi->indirect);
VECADDFAC(shi->ao, shi->ao, mesh->col[face[1]], w[1]);
VECADDFAC(shi->ao, shi->ao, mesh->col[face[2]], w[2]); madd_v3_v3fl(shi->ao, mesh->ao[face[0]], w[0]);
if(face[3]) madd_v3_v3fl(shi->indirect, mesh->indirect[face[0]], w[0]);
VECADDFAC(shi->ao, shi->ao, mesh->col[face[3]], w[3]); 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 { else {
shi->ao[0]= 1.0f; shi->ao[0]= 1.0f;
shi->ao[1]= 1.0f; shi->ao[1]= 1.0f;
shi->ao[2]= 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; OcclusionThread *othread= (OcclusionThread*)data;
Render *re= othread->re; Render *re= othread->re;
StrandSurface *mesh= othread->mesh; 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; int a, *face;
for(a=othread->begin; a<othread->end; a++) { for(a=othread->begin; a<othread->end; a++) {
@@ -1521,8 +1575,9 @@ static void *exec_strandsurface_sample(void *data)
} }
negate_v3(n); negate_v3(n);
sample_occ_tree(re, re->occlusiontree, NULL, co, n, othread->thread, 0, col); sample_occ_tree(re, re->occlusiontree, NULL, co, n, othread->thread, 0, ao, indirect);
VECCOPY(othread->facecol[a], col); VECCOPY(othread->faceao[a], ao);
VECCOPY(othread->faceindirect[a], indirect);
} }
return 0; return 0;
@@ -1533,7 +1588,7 @@ void make_occ_tree(Render *re)
OcclusionThread othreads[BLENDER_MAX_THREADS]; OcclusionThread othreads[BLENDER_MAX_THREADS];
StrandSurface *mesh; StrandSurface *mesh;
ListBase threads; ListBase threads;
float col[3], (*facecol)[3]; float ao[3], indirect[3], (*faceao)[3], (*faceindirect)[3];
int a, totface, totthread, *face, *count; int a, totface, totthread, *face, *count;
/* ugly, needed for occ_face */ /* 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); occ_compute_passes(re, re->occlusiontree, re->wrld.ao_approx_passes);
for(mesh=re->strandsurface.first; mesh; mesh=mesh->next) { for(mesh=re->strandsurface.first; mesh; mesh=mesh->next) {
if(!mesh->face || !mesh->co || !mesh->col) if(!mesh->face || !mesh->co || !mesh->ao)
continue; continue;
count= MEM_callocN(sizeof(int)*mesh->totvert, "OcclusionCount"); 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; totthread= (mesh->totface > 10000)? re->r.threads: 1;
totface= mesh->totface/totthread; totface= mesh->totface/totthread;
for(a=0; a<totthread; a++) { for(a=0; a<totthread; a++) {
othreads[a].re= re; othreads[a].re= re;
othreads[a].facecol= facecol; othreads[a].faceao= faceao;
othreads[a].faceindirect= faceindirect;
othreads[a].thread= a; othreads[a].thread= a;
othreads[a].mesh= mesh; othreads[a].mesh= mesh;
othreads[a].begin= a*totface; othreads[a].begin= a*totface;
@@ -1581,26 +1638,36 @@ void make_occ_tree(Render *re)
for(a=0; a<mesh->totface; a++) { for(a=0; a<mesh->totface; a++) {
face= mesh->face[a]; face= mesh->face[a];
VECCOPY(col, facecol[a]); VECCOPY(ao, faceao[a]);
VECADD(mesh->col[face[0]], mesh->col[face[0]], col); 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]]++; 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]]++; 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]]++; count[face[2]]++;
if(face[3]) { 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]]++; count[face[3]]++;
} }
} }
for(a=0; a<mesh->totvert; a++) for(a=0; a<mesh->totvert; a++) {
if(count[a]) if(count[a]) {
mul_v3_fl(mesh->col[a], 1.0f/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(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); sample_occ_surface(shi);
} }
/* try to get result from the cache if possible */ /* 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 */ /* no luck, let's sample the occlusion */
exclude.obi= shi->obi - re->objectinstance; exclude.obi= shi->obi - re->objectinstance;
exclude.facenr= shi->vlr->index; exclude.facenr= shi->vlr->index;
onlyshadow= (shi->mat->mode & MA_ONLYSHADOW); 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 */ /* fill result into sample, each time */
if(tree->cache) { 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)]; sample= &cache->sample[(shi->ys-cache->y)*cache->w + (shi->xs-cache->x)];
VECCOPY(sample->co, shi->co); VECCOPY(sample->co, shi->co);
VECCOPY(sample->n, shi->vno); VECCOPY(sample->n, shi->vno);
VECCOPY(sample->col, shi->ao); VECCOPY(sample->ao, shi->ao);
sample->intensity= MAX3(sample->col[0], sample->col[1], sample->col[2]); 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->dist2= INPR(shi->dxco, shi->dxco) + INPR(shi->dyco, shi->dyco);
sample->filled= 1; sample->filled= 1;
} }
@@ -1653,6 +1722,10 @@ void sample_occ(Render *re, ShadeInput *shi)
shi->ao[0]= 1.0f; shi->ao[0]= 1.0f;
shi->ao[1]= 1.0f; shi->ao[1]= 1.0f;
shi->ao[2]= 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); onlyshadow= (shi->mat->mode & MA_ONLYSHADOW);
exclude.obi= shi->obi - re->objectinstance; exclude.obi= shi->obi - re->objectinstance;
exclude.facenr= shi->vlr->index; 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->co, shi->co);
VECCOPY(sample->n, shi->vno); VECCOPY(sample->n, shi->vno);
VECCOPY(sample->col, shi->ao); VECCOPY(sample->ao, shi->ao);
sample->intensity= MAX3(sample->col[0], sample->col[1], sample->col[2]); 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->dist2= INPR(shi->dxco, shi->dxco) + INPR(shi->dyco, shi->dyco);
sample->x= shi->xs; sample->x= shi->xs;
sample->y= shi->ys; sample->y= shi->ys;

View File

@@ -1041,6 +1041,7 @@ void ambient_occlusion_to_diffuse(ShadeInput *shi, float *diff)
} }
VECMUL(diff, f); VECMUL(diff, f);
madd_v3_v3fl(diff, shi->indirect, R.wrld.ao_indirect_energy*shi->amb);
} }
else else
diff[0]= diff[1]= diff[2]= 0.0f; diff[0]= diff[1]= diff[2]= 0.0f;

View File

@@ -959,7 +959,8 @@ StrandSurface *cache_strand_surface(Render *re, ObjectRen *obr, DerivedMesh *dm,
mesh->totvert= totvert; mesh->totvert= totvert;
mesh->totface= totface; mesh->totface= totface;
mesh->face= MEM_callocN(sizeof(int)*4*mesh->totface, "StrandSurfFaces"); 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); BLI_addtail(&re->strandsurface, mesh);
} }
@@ -997,7 +998,8 @@ void free_strand_surface(Render *re)
if(mesh->co) MEM_freeN(mesh->co); if(mesh->co) MEM_freeN(mesh->co);
if(mesh->prevco) MEM_freeN(mesh->prevco); if(mesh->prevco) MEM_freeN(mesh->prevco);
if(mesh->nextco) MEM_freeN(mesh->nextco); 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); if(mesh->face) MEM_freeN(mesh->face);
} }