Page MenuHome

raytraced_indirect.patch

File Metadata

Author
Shaun Graham (sgraham)
Created
Nov 13 2013, 5:08 PM

raytraced_indirect.patch

Index: release/scripts/startup/bl_ui/properties_world.py
===================================================================
--- release/scripts/startup/bl_ui/properties_world.py (revision 60414)
+++ release/scripts/startup/bl_ui/properties_world.py (working copy)
@@ -155,16 +155,13 @@
light = context.world.light_settings
- layout.active = light.use_indirect_light and light.gather_method == 'APPROXIMATE'
+ layout.active = light.use_indirect_light
split = layout.split()
split.prop(light, "indirect_factor", text="Factor")
split.prop(light, "indirect_bounces", text="Bounces")
- if light.gather_method == 'RAYTRACE':
- layout.label(text="Only works with Approximate gather method")
-
class WORLD_PT_gather(WorldButtonsPanel, Panel):
bl_label = "Gather"
COMPAT_ENGINES = {'BLENDER_RENDER'}
Index: source/blender/render/intern/include/rendercore.h
===================================================================
--- source/blender/render/intern/include/rendercore.h (revision 60414)
+++ source/blender/render/intern/include/rendercore.h (working copy)
@@ -91,7 +91,7 @@
extern void ray_shadow(ShadeInput *shi, LampRen *lar, float shadfac[4]);
extern void ray_trace(ShadeInput *shi, ShadeResult *);
-extern void ray_ao(ShadeInput *shi, float ao[3], float env[3]);
+extern void ray_ao(ShadeInput *shi);
extern void init_jitter_plane(LampRen *lar);
extern void init_ao_sphere(struct World *wrld);
extern void init_render_qmcsampler(Render *re);
Index: source/blender/render/intern/source/rayshade.c
===================================================================
--- source/blender/render/intern/source/rayshade.c (revision 60414)
+++ source/blender/render/intern/source/rayshade.c (working copy)
@@ -1200,7 +1200,8 @@
vec[0] = cosf(phi)*sqr;
vec[1] = sinf(phi)*sqr;
- vec[2] = (float)(1.0 - s[1]*s[1]);
+ //vec[2] = (float)(1.0 - s[1]*s[1]);
+ vec[2] = (float)sqrt(1.0 - s[1]); // adds cosine weighting
}
#if 0 /* currently not used */
@@ -1851,144 +1852,281 @@
}
}
-static void ray_ao_qmc(ShadeInput *shi, float ao[3], float env[3])
+// returns true if the ray hit something, false if not
+// the resulting color based on what was or was not hit
+// is accumulated in shi variables ao, env, and indirect
+// accordingly
+static bool cast_ao_sample_ray(ShadeInput *origshi, ShadeInput *shi, Isect *isec)
{
- Isect isec;
RayHint point_hint;
- QMCSampler *qsa=NULL;
- float samp3d[3];
- float up[3], side[3], dir[3], nrm[3];
+ float bboxMax[3];
+
+ if (origshi->obi->flag & R_ENV_TRANSFORMED) {
+ ray_env_rotate_dir(isec, origshi->obi->imat);
+ }
+
+ // this ray hint potentially speeds up heavier scenes
+ copy_v3_v3(bboxMax, isec->dir);
+ mul_v3_fl(bboxMax, R.wrld.aodist);
+ add_v3_v3(bboxMax, isec->start);
+ RE_rayobject_hint_bb(R.raytree, &point_hint, isec->start, bboxMax);
+ isec->hint = &point_hint;
+
+ if (RE_rayobject_raycast(R.raytree, isec)) {
+ // ray hit something
+ if (R.wrld.mode & WO_INDIRECT_LIGHT) {
+ // we need to get fully rendered color of material at intersect point
+ ShadeResult shr; // we don't need to initialize this because it is cleared before usage
+
+ // copy intersect UV coords
+ shi->u = isec->u;
+ shi->v = isec->v;
+
+ // determine intersect position, is the intersect position already stored somewhere?
+ copy_v3_v3(shi->co, isec->dir);
+ mul_v3_fl(shi->co, isec->dist);
+ add_v3_v3(shi->co, isec->start);
+
+ // sets uv coords, normals, material and other polygon data taken from the face we hit
+ shade_input_set_triangle_i(shi, isec->hit.ob, (VlakRen *)isec->hit.face, 0, 1, 2);
+
+ // we must unflip normal if we flipped in the previous call
+ // note: we have to do this here because the flippednor attribute gets
+ // overwritten later. Alternative is to copy all the code from the functions
+ // we are using minus the normal flipping code
+ if (shi->flippednor) {
+ shade_input_flip_normals(shi);
+ }
+
+ copy_v3_v3(shi->view, shi->co);
+ normalize_v3(shi->view);
+
+ // update normal information used in shader evaluation
+ shade_input_set_normals(shi);
+
+ // undo any normal flips again...
+ if (shi->flippednor) {
+ shade_input_flip_normals(shi);
+ }
+
+ // additional offset to avoid self collisions? doesn't seem to be an issue... is this handled in the raytracer now?
+ //madd_v3_v3fl(shi->co, shi->facenor, -0.0001f); /* ugly.. */
+
+ // copy over hit shi->mat vars to matching shi vars
+ shade_input_init_material(shi);
+
+ // let renderer know we don't need pass info
+ shi->passflag = SCE_PASS_COMBINED;
+
+ // we might decide later we want to not calculate specular since it will
+ // most likely have minimal effect anyway, though more accurate...
+ // to do that add this to the flags: ~(SCE_PASS_SPEC);
+ if (shi->depth >= R.wrld.ao_indirect_bounces) {
+ // we are at the bounce limit, don't be casting more rays!
+ shi->combinedflag = ~(SCE_PASS_AO | SCE_PASS_ENVIRONMENT | SCE_PASS_INDIRECT); // get all shading that doesn't go back into the ambient_occlusion loop!
+ } else {
+ // not over the bounce limit, so keep going
+ shi->combinedflag = ~(0); // perform full shading including additional raytracing
+ }
- float maxdist = R.wrld.aodist;
- float fac=0.0f, prev=0.0f;
- float adapt_thresh = R.wrld.ao_adapt_thresh;
- float adapt_speed_fac = R.wrld.ao_adapt_speed_fac;
+ // evaluate texture for this sample
+ shade_input_set_shade_texco(shi);
+
+ // evaluate material for this sample
+ shade_material_loop(shi, &shr); // todo: nodes?
- int samples=0;
- int max_samples = R.wrld.aosamp*R.wrld.aosamp;
+ add_v3_v3(origshi->indirect, shr.combined);
+ }
+
+ // handle falloff for occlusion, also used to compare for adaptive sampling
+ if (R.wrld.aomode & WO_AODIST) {
+ origshi->ao[0] += expf(-isec->dist*R.wrld.aodistfac);
+ } else {
+ origshi->ao[0] += 1.0f;
+ }
+
+ return true;
+ }
+ else if (R.wrld.mode & WO_ENV_LIGHT) {
+ // ray missed geometry, sample sky instead
+ if (R.wrld.aocolor != WO_AOPLAIN && !(origshi->mat->mode & MA_ONLYSHADOW)) {
+ if (R.wrld.aocolor == WO_AOSKYCOL) {
+ // linear interpolation of ray direction and zenith (up) and horizontal (sideways)
+ const float skyfac = 0.5f * (1.0f + dot_v3v3(isec->dir, R.grvec));
+ origshi->env[0] += (1.0f-skyfac)*R.wrld.horr + skyfac*R.wrld.zenr;
+ origshi->env[1] += (1.0f-skyfac)*R.wrld.horg + skyfac*R.wrld.zeng;
+ origshi->env[2] += (1.0f-skyfac)*R.wrld.horb + skyfac*R.wrld.zenb;
+ } else { // WO_AOSKYTEX
+ float skycol[4];
+ float dxyview[3];
+ // how could 1/ao_samples be of any use to the shadeSkyView function???
+ // took this from ray_ao code and optimized out repeat division, but it looks broken to me
+ dxyview[1] = dxyview[0] = 1.0f/(float)R.wrld.aosamp;
+ dxyview[2] = 0.0f;
+
+ shadeSkyView(skycol, isec->start, isec->dir, dxyview, shi->thread);
+ shadeSunView(skycol, isec->dir);
+ add_v3_v3(origshi->env, skycol);
+ }
+ }
+ }
+
+ return false;
+}
+
+void init_common_ao_sample_vars(ShadeInput *origshi, ShadeInput *shi, Isect *isec)
+{
+ // fill in values that will be used for every raycast
+ // for as long we don't have proper dx/dy transform for rays we copy over original
+ copy_v3_v3(shi->dxco, origshi->dxco);
+ copy_v3_v3(shi->dyco, origshi->dyco);
+ shi->mask = origshi->mask;
+ shi->depth = origshi->depth + 1;
+ shi->thread = origshi->thread;
+ shi->xs = origshi->xs;
+ shi->ys = origshi->ys;
+ shi->lay = origshi->lay;
+ shi->light_override = origshi->light_override; // not sure we want this one to come from origshi
- float dxyview[3], skyadded=0;
- int envcolor;
+ // init isec ray counter with shi ray count
+ RE_RC_INIT(*isec, *origshi);
+ isec->orig.ob = origshi->obi;
+ isec->orig.face = origshi->vlr;
+ if (R.wrld.mode & WO_INDIRECT_LIGHT) {
+ isec->check = RE_CHECK_VLR_RENDER; // RE_CHECK_VLR_NON_SOLID_MATERIAL; // not sure what to put here... but render makes sense
+ isec->mode = RE_RAY_MIRROR;
+ } else {
+ isec->check= RE_CHECK_VLR_NON_SOLID_MATERIAL;
+ isec->mode= (R.wrld.aomode & WO_AODIST)?RE_RAY_SHADOW_TRA:RE_RAY_SHADOW;
+ }
+ isec->skip = RE_SKIP_VLR_NEIGHBOUR;
+ isec->hit.ob = NULL;
+ isec->hit.face = NULL;
+ isec->last_hit = NULL;
- RE_RC_INIT(isec, *shi);
- isec.orig.ob = shi->obi;
- isec.orig.face = shi->vlr;
- isec.check = RE_CHECK_VLR_NON_SOLID_MATERIAL;
- isec.skip = RE_SKIP_VLR_NEIGHBOUR;
- isec.hint = NULL;
+ isec->lay = origshi->lay;
+
+ // copy original sample coordinate to be our start position of the ray
+ copy_v3_v3(isec->start, origshi->co);
- isec.hit.ob = NULL;
- isec.hit.face = NULL;
+ // not totally sure what this is transforming
+ if (origshi->obi->flag & R_ENV_TRANSFORMED) {
+ ray_env_rotate(isec, origshi->obi->imat);
+ }
- isec.last_hit = NULL;
+ // initialize accumulators
+ zero_v3(origshi->indirect);
+ zero_v3(origshi->env);
+ zero_v3(origshi->ao);
+}
+
+void calculate_final_ao(ShadeInput *shi, float samples, float skyadded)
+{
+//printf("samples:%d fac:%f indir:%f env:%f\n", samples, shi.ao[0], shi.indirect[0], shi.env[0]);
+ float fac = shi->ao[0], sample_contrib;
- isec.mode= (R.wrld.aomode & WO_AODIST)?RE_RAY_SHADOW_TRA:RE_RAY_SHADOW;
- isec.lay= -1;
+ if (samples) {
+ sample_contrib = 1.0f / samples;
+ }
+ else {
+ sample_contrib = 0.0f;
+ }
+
+ // calculate final ambient occlusion
+ if (R.wrld.mode & WO_AMB_OCC || R.wrld.mode & WO_ENV_LIGHT) {
+ shi->ao[0]= shi->ao[1]= shi->ao[2]= 1.0f - (fac * sample_contrib); //1.0f - fac/(float)samples;
+ }
+
+ // calculate final env color
+ if (R.wrld.mode & WO_ENV_LIGHT) {
+ if (R.wrld.aocolor != WO_AOPLAIN && skyadded) {
+ mul_v3_fl(shi->env, shi->ao[0] / (float)skyadded);
+ }
+ else {
+ copy_v3_v3(shi->env, shi->ao);
+ }
+ }
+
+ // calculate final indirect lighting color
+ if (R.wrld.mode & WO_INDIRECT_LIGHT) {
+ mul_v3_fl(shi->indirect, sample_contrib);
+ }
+}
+
+void ray_ao_qmc(ShadeInput *origshi)
+{
+ // for now we are only doing qmc to keep things simple
+ Isect isec;
+ QMCSampler *qsa = NULL;
+ float samp3d[3];
+ float up[3], side[3], nrm[3];
- copy_v3_v3(isec.start, shi->co);
+ float prevfac;
+ float adapt_thresh = R.wrld.ao_adapt_thresh;
+ float adapt_speed_fac = R.wrld.ao_adapt_speed_fac;
- if (shi->obi->flag & R_ENV_TRANSFORMED)
- ray_env_rotate_start(&isec, shi->obi->imat);
-
- RE_rayobject_hint_bb(R.raytree, &point_hint, isec.start, isec.start);
- isec.hint = &point_hint;
+ int samples=0, skyadded=0;
+ int max_samples = R.wrld.aosamp * R.wrld.aosamp;
- zero_v3(ao);
- zero_v3(env);
+ // create a new shi and shr which we will use as a copy to evaluate shader at isec
+ ShadeInput shi = {NULL};
- /* prevent sky colors to be added for only shadow (shadow becomes alpha) */
- envcolor= R.wrld.aocolor;
- if (shi->mat->mode & MA_ONLYSHADOW)
- envcolor= WO_AOPLAIN;
+ init_common_ao_sample_vars(origshi, &shi, &isec);
- if (envcolor == WO_AOSKYTEX) {
- dxyview[0]= 1.0f/(float)R.wrld.aosamp;
- dxyview[1]= 1.0f/(float)R.wrld.aosamp;
- dxyview[2]= 0.0f;
+ // get hemisphere direction based on surface normal
+ if (origshi->vlr->flag & R_SMOOTH) {
+ copy_v3_v3(nrm, origshi->vn);
}
-
- if (shi->vlr->flag & R_SMOOTH) {
- copy_v3_v3(nrm, shi->vn);
- }
else {
- copy_v3_v3(nrm, shi->facenor);
+ copy_v3_v3(nrm, origshi->facenor);
}
+ // get basis for hemisphere direction
ortho_basis_v3v3_v3(up, side, nrm);
-
- /* sampling init */
- if (R.wrld.ao_samp_method==WO_AOSAMP_HALTON) {
+
+ // sampling init
+ if (R.wrld.ao_samp_method == WO_AOSAMP_HALTON) {
float speedfac;
- speedfac = get_avg_speed(shi) * adapt_speed_fac;
+ speedfac = get_avg_speed(origshi) * adapt_speed_fac;
CLAMP(speedfac, 1.0f, 1000.0f);
max_samples /= speedfac;
if (max_samples < 5) max_samples = 5;
- qsa = get_thread_qmcsampler(&R, shi->thread, SAMP_TYPE_HALTON, max_samples);
+ qsa = get_thread_qmcsampler(&R, origshi->thread, SAMP_TYPE_HALTON, max_samples);
}
- else if (R.wrld.ao_samp_method==WO_AOSAMP_HAMMERSLEY)
- qsa = get_thread_qmcsampler(&R, shi->thread, SAMP_TYPE_HAMMERSLEY, max_samples);
+ else if (R.wrld.ao_samp_method == WO_AOSAMP_HAMMERSLEY) {
+ qsa = get_thread_qmcsampler(&R, origshi->thread, SAMP_TYPE_HAMMERSLEY, max_samples);
+ }
- QMC_initPixel(qsa, shi->thread);
+ // initialize random number generator once for all samples
+ QMC_initPixel(qsa, origshi->thread);
while (samples < max_samples) {
+ // returns quasi-random unit length vector in hemisphere
+ QMC_sampleHemi(samp3d, qsa, origshi->thread, samples);
- /* sampling, returns quasi-random vector in unit hemisphere */
- QMC_sampleHemi(samp3d, qsa, shi->thread, samples);
+ // rotate the random vector so the hemisphere is facing the normal direction
+ // note: should not need to normalize as the result of the random hemisphere vector and rotate should be unit length
+ isec.dir[0] = -(samp3d[0]*up[0] + samp3d[1]*side[0] + samp3d[2]*nrm[0]);
+ isec.dir[1] = -(samp3d[0]*up[1] + samp3d[1]*side[1] + samp3d[2]*nrm[1]);
+ isec.dir[2] = -(samp3d[0]*up[2] + samp3d[1]*side[2] + samp3d[2]*nrm[2]);
+ isec.dist = R.wrld.aodist;
+
+ // store previous factor for adaptive sampling comparison
+ prevfac = origshi->ao[0];
- dir[0] = (samp3d[0]*up[0] + samp3d[1]*side[0] + samp3d[2]*nrm[0]);
- dir[1] = (samp3d[0]*up[1] + samp3d[1]*side[1] + samp3d[2]*nrm[1]);
- dir[2] = (samp3d[0]*up[2] + samp3d[1]*side[2] + samp3d[2]*nrm[2]);
-
- normalize_v3(dir);
-
- isec.dir[0] = -dir[0];
- isec.dir[1] = -dir[1];
- isec.dir[2] = -dir[2];
- isec.dist = maxdist;
-
- if (shi->obi->flag & R_ENV_TRANSFORMED)
- ray_env_rotate_dir(&isec, shi->obi->imat);
-
- prev = fac;
-
- if (RE_rayobject_raycast(R.raytree, &isec)) {
- if (R.wrld.aomode & WO_AODIST) fac+= expf(-isec.dist*R.wrld.aodistfac);
- else fac+= 1.0f;
+ // accumulate light data for this sample into shi-> ao, env, and indirect
+ if (!cast_ao_sample_ray(origshi, &shi, &isec)) {
+ ++skyadded;
}
- else if (envcolor!=WO_AOPLAIN) {
- float skycol[4];
- float view[3];
-
- view[0]= -dir[0];
- view[1]= -dir[1];
- view[2]= -dir[2];
- normalize_v3(view);
-
- if (envcolor==WO_AOSKYCOL) {
- const float skyfac= 0.5f * (1.0f + dot_v3v3(view, R.grvec));
- env[0]+= (1.0f-skyfac)*R.wrld.horr + skyfac*R.wrld.zenr;
- env[1]+= (1.0f-skyfac)*R.wrld.horg + skyfac*R.wrld.zeng;
- env[2]+= (1.0f-skyfac)*R.wrld.horb + skyfac*R.wrld.zenb;
- }
- else { /* WO_AOSKYTEX */
- shadeSkyView(skycol, isec.start, view, dxyview, shi->thread);
- shadeSunView(skycol, shi->view);
- env[0]+= skycol[0];
- env[1]+= skycol[1];
- env[2]+= skycol[2];
- }
- skyadded++;
- }
-
- samples++;
-
+
+ ++samples;
+
if (qsa && qsa->type == SAMP_TYPE_HALTON) {
/* adaptive sampling - consider samples below threshold as in shadow (or vice versa) and exit early */
if (adapt_thresh > 0.0f && (samples > max_samples/2) ) {
-
- if (adaptive_sample_contrast_val(samples, prev, fac, adapt_thresh)) {
+ if (adaptive_sample_contrast_val(samples, prevfac, origshi->ao[0], adapt_thresh)) {
break;
}
}
@@ -1995,163 +2133,87 @@
}
}
- /* average color times distances/hits formula */
- ao[0]= ao[1]= ao[2]= 1.0f - fac/(float)samples;
+ calculate_final_ao(origshi, (float)samples, (float)skyadded);
- if (envcolor!=WO_AOPLAIN && skyadded)
- mul_v3_fl(env, (1.0f - fac/(float)samples)/((float)skyadded));
- else
- copy_v3_v3(env, ao);
-
- if (qsa)
- release_thread_qmcsampler(&R, shi->thread, qsa);
+ if (qsa) {
+ release_thread_qmcsampler(&R, origshi->thread, qsa);
+ }
}
+
/* extern call from shade_lamp_loop, ambient occlusion calculus */
-static void ray_ao_spheresamp(ShadeInput *shi, float ao[3], float env[3])
+void ray_ao_spheresamp(ShadeInput *origshi)
{
+ // for now we are only doing qmc to keep things simple
Isect isec;
- RayHint point_hint;
- float *vec, *nrm, bias, sh=0.0f;
- float maxdist = R.wrld.aodist;
- float dxyview[3];
- int j= -1, tot, actual=0, skyadded=0, envcolor, resol= R.wrld.aosamp;
-
- RE_RC_INIT(isec, *shi);
- isec.orig.ob = shi->obi;
- isec.orig.face = shi->vlr;
- isec.check = RE_CHECK_VLR_RENDER;
- isec.skip = RE_SKIP_VLR_NEIGHBOUR;
- isec.hint = NULL;
+ float *vec, *nrm, bias;
+ int samples= 0, tot, j= -1, resol = R.wrld.aosamp, skyadded= 0;
- isec.hit.ob = NULL;
- isec.hit.face = NULL;
-
- isec.last_hit = NULL;
-
- isec.mode= (R.wrld.aomode & WO_AODIST)?RE_RAY_SHADOW_TRA:RE_RAY_SHADOW;
- isec.lay= -1;
+ // create a new shi and shr which we will use as a copy to evaluate shader at isec
+ ShadeInput shi = {NULL};
- copy_v3_v3(isec.start, shi->co);
- if (shi->obi->flag & R_ENV_TRANSFORMED)
- ray_env_rotate_start(&isec, shi->obi->imat);
+ init_common_ao_sample_vars(origshi, &shi, &isec);
- RE_rayobject_hint_bb(R.raytree, &point_hint, isec.start, isec.start);
- isec.hint = &point_hint;
-
- zero_v3(ao);
- zero_v3(env);
-
/* bias prevents smoothed faces to appear flat */
- if (shi->vlr->flag & R_SMOOTH) {
+ if (origshi->vlr->flag & R_SMOOTH) {
bias= R.wrld.aobias;
- nrm= shi->vn;
+ nrm= origshi->vn;
}
else {
bias= 0.0f;
- nrm= shi->facenor;
+ nrm= origshi->facenor;
}
- /* prevent sky colors to be added for only shadow (shadow becomes alpha) */
- envcolor= R.wrld.aocolor;
- if (shi->mat->mode & MA_ONLYSHADOW)
- envcolor= WO_AOPLAIN;
-
if (resol>32) resol= 32;
/* get sphere samples. for faces we get the same samples for sample x/y values,
* for strand render we always require a new sampler because x/y are not set */
- vec= sphere_sampler(R.wrld.aomode, resol, shi->thread, shi->xs, shi->ys, shi->strand != NULL);
-
+ vec= sphere_sampler(R.wrld.aomode, resol, origshi->thread, origshi->xs, origshi->ys, origshi->strand != NULL);
+
/* warning: since we use full sphere now, and dotproduct is below, we do twice as much */
tot= 2*resol*resol;
-
- if (envcolor == WO_AOSKYTEX) {
- dxyview[0]= 1.0f/(float)resol;
- dxyview[1]= 1.0f/(float)resol;
- dxyview[2]= 0.0f;
- }
while (tot--) {
-
if (dot_v3v3(vec, nrm) > bias) {
/* only ao samples for mask */
if (R.r.mode & R_OSA) {
- j++;
+ ++j;
if (j==R.osa) j= 0;
- if (!(shi->mask & (1<<j))) {
+ if (!(origshi->mask & (1<<j))) {
vec+=3;
continue;
}
}
-
- actual++;
-
+
/* always set start/vec/dist */
isec.dir[0] = -vec[0];
isec.dir[1] = -vec[1];
isec.dir[2] = -vec[2];
- isec.dist = maxdist;
-
- if (shi->obi->flag & R_ENV_TRANSFORMED)
- ray_env_rotate_dir(&isec, shi->obi->imat);
+ isec.dist = R.wrld.aodist;
- /* do the trace */
- if (RE_rayobject_raycast(R.raytree, &isec)) {
- if (R.wrld.aomode & WO_AODIST) sh+= expf(-isec.dist*R.wrld.aodistfac);
- else sh+= 1.0f;
+ // accumulate light data for this sample into shi-> ao, env, and indirect
+ if (!cast_ao_sample_ray(origshi, &shi, &isec)) {
+ ++skyadded;
}
- else if (envcolor!=WO_AOPLAIN) {
- float skycol[4];
- float view[3];
-
- view[0]= -vec[0];
- view[1]= -vec[1];
- view[2]= -vec[2];
- normalize_v3(view);
-
- if (envcolor==WO_AOSKYCOL) {
- const float fac = 0.5f * (1.0f + dot_v3v3(view, R.grvec));
- env[0]+= (1.0f-fac)*R.wrld.horr + fac*R.wrld.zenr;
- env[1]+= (1.0f-fac)*R.wrld.horg + fac*R.wrld.zeng;
- env[2]+= (1.0f-fac)*R.wrld.horb + fac*R.wrld.zenb;
- }
- else { /* WO_AOSKYTEX */
- shadeSkyView(skycol, isec.start, view, dxyview, shi->thread);
- shadeSunView(skycol, shi->view);
- env[0]+= skycol[0];
- env[1]+= skycol[1];
- env[2]+= skycol[2];
- }
- skyadded++;
- }
+
+ ++samples;
}
- /* samples */
+ // get next sample vector
vec+= 3;
}
-
- if (actual==0) sh= 1.0f;
- else sh = 1.0f - sh/((float)actual);
-
- /* average color times distances/hits formula */
- ao[0]= ao[1]= ao[2]= sh;
- if (envcolor!=WO_AOPLAIN && skyadded)
- mul_v3_fl(env, sh/((float)skyadded));
- else
- copy_v3_v3(env, ao);
+ calculate_final_ao(origshi, (float)samples, (float)skyadded);
}
-void ray_ao(ShadeInput *shi, float ao[3], float env[3])
+void ray_ao(ShadeInput *shi)
{
- /* Unfortunately, the unusual way that the sphere sampler calculates roughly twice as many
- * samples as are actually traced, and skips them based on bias and OSA settings makes it very difficult
- * to reuse code between these two functions. This is the easiest way I can think of to do it
- * --broken */
- if (ELEM(R.wrld.ao_samp_method, WO_AOSAMP_HAMMERSLEY, WO_AOSAMP_HALTON))
- ray_ao_qmc(shi, ao, env);
- else if (R.wrld.ao_samp_method == WO_AOSAMP_CONSTANT)
- ray_ao_spheresamp(shi, ao, env);
+ // each sample type has its own function
+ if (ELEM(R.wrld.ao_samp_method, WO_AOSAMP_HAMMERSLEY, WO_AOSAMP_HALTON)) {
+ ray_ao_qmc(shi);
+ }
+ else if (R.wrld.ao_samp_method == WO_AOSAMP_CONSTANT) {
+ ray_ao_spheresamp(shi);
+ }
}
static void ray_shadow_jittered_coords(ShadeInput *shi, int max, float jitco[RE_MAX_OSA][3], int *totjitco)
Index: source/blender/render/intern/source/shadeoutput.c
===================================================================
--- source/blender/render/intern/source/shadeoutput.c (revision 60621)
+++ source/blender/render/intern/source/shadeoutput.c (working copy)
@@ -1078,12 +1078,15 @@
void ambient_occlusion(ShadeInput *shi)
{
if ((R.wrld.ao_gather_method == WO_AOGATHER_APPROX) && shi->mat->amb!=0.0f) {
+ // approximate gather method
sample_occ(&R, shi);
}
else if ((R.r.mode & R_RAYTRACE) && shi->mat->amb!=0.0f) {
- ray_ao(shi, shi->ao, shi->env);
+ // raytraced gather method
+ ray_ao(shi);
}
else {
+ // unknown method
shi->ao[0]= shi->ao[1]= shi->ao[2]= 1.0f;
zero_v3(shi->env);
zero_v3(shi->indirect);
@@ -1436,9 +1439,12 @@
}
i_noshad= i;
- vn = shi->vn; /* bring back original vector, we use special specular shaders for tangent */
- if (ma->mode & MA_TANGENT_V)
- vn= shi->tang;
+ /* bring back original vector, we use special specular shaders for tangent */
+ if (ma->mode & MA_TANGENT_V) {
+ vn = shi->tang;
+ } else {
+ vn = shi->vn;
+ }
/* init transp shadow */
shadfac[0]= shadfac[1]= shadfac[2]= shadfac[3]= 1.0f;
@@ -1803,7 +1809,6 @@
}
}
}
-
/* lighting pass */
if (passflag & (SCE_PASS_COMBINED|SCE_PASS_DIFFUSE|SCE_PASS_SPEC|SCE_PASS_SHADOW)) {
GroupObject *go;
@@ -1913,7 +1918,7 @@
}
}
shr->alpha= shi->alpha;
-
+
/* from now stuff everything in shr->combined: ambient, AO, ramps, exposure */
if (!(ma->sss_flag & MA_DIFF_SSS) || !sss_pass_done(&R, ma)) {
if (R.r.mode & R_SHADOW) {
@@ -1961,7 +1966,7 @@
add_v3_v3(shr->combined, shr->emit);
if (shi->combinedflag & SCE_PASS_SPEC)
add_v3_v3(shr->combined, shr->spec);
-
+
/* modulate by the object color */
if ((ma->shade_flag & MA_OBCOLOR) && shi->obr->ob) {
if (!(ma->sss_flag & MA_DIFF_SSS) || !sss_pass_done(&R, ma)) {

Event Timeline