Eeshlo AO patch, revised

- Ambient Occlusion is a more sophisticated ambient trick, which takes
  nearby faces into account by firing a hemisphere of shadow-rays
  around. AKA 'dirt shader'.
- Eeshlo made it a Lamp type, which doesn't fit well. I've moved the
  settings to the World menu, and let the Material->ambient value control
  the amount it contributes
- currently, the AO value is added/subtracted/mixed with the 'diffuse'
  factor while shading, before it is multiplied with Material color

Buttons are in new Panel 'Amb Occ" in F8 menu. Note:

- "Dist:" by shortening the length of rays you get subtler effects and it
  renders faster too
- "DistF:" the attennuation factor gives control over how the 'shadow'
  spreads out.

Further it's just raytracing, so tends to be slooooow.... :)
Here same tricks as for other raytraced scenes apply, especially try to
keep the environment as small as possible (exclude faces from Octree by
giving them no Material Traceable).

I still have to think over a couple of aspects, will await feedback on it:
- AO color? Now it just adds 'white'
- other sampling patterns? I tried dithering, which was so-so
- method of controlling final 'samples' in F10? Might be useful for other
  oversampling too (area light) to have it reacting to a percentage or so..
This commit is contained in:
Ton Roosendaal
2004-04-05 21:04:13 +00:00
parent e4ce73c99e
commit 2a90de0348
7 changed files with 188 additions and 3 deletions

View File

@@ -198,6 +198,11 @@ void init_render_world()
R.wrld.miststa+= (float)fabs(R.viewmat[3][2]);
}
}
/* ambient occlusion */
R.wrld.aototsamp= R.wrld.aosamp*R.wrld.aosamp;
}
else {
memset(&R.wrld, 0, sizeof(World));

View File

@@ -4119,6 +4119,7 @@ static void do_versions(Main *main)
}
if(main->versionfile <= 232) {
Tex *tex= main->tex.first;
World *wrld= main->world.first;
while(tex) {
/* copied from kernel texture.c */
@@ -4138,6 +4139,13 @@ static void do_versions(Main *main)
tex= tex->id.next;
}
while(wrld) {
if(wrld->aodist==0.0) wrld->aodist= 10.0;
if(wrld->aosamp==0.0) wrld->aosamp= 5;
wrld= wrld->id.next;
}
}

View File

@@ -91,8 +91,13 @@ typedef struct World {
float starsize, starmindist;
float stardist, starcolnoise;
/* unused now: DOF */
short dofsta, dofend, dofmin, dofmax;
/* ambient occlusion */
float aodist, aodistfac;
short aomode, aosamp, aomix, aototsamp;
int physicsEngine;
struct Ipo *ipo;
@@ -117,6 +122,17 @@ typedef struct World {
#define WO_STARS 2
#define WO_DOF 4
#define WO_ACTIVITY_CULLING 8
#define WO_AMB_OCC 16
/* aomix */
#define WO_AOADD 0
#define WO_AOSUB 1
#define WO_AOADDSUB 2
/* aomode (use distances & random sampling modes) */
#define WO_AODIST 1
#define WO_AORNDSMP 2
/* mapto */
#define WOMAP_BLEND 1

View File

@@ -75,6 +75,7 @@ float spec(float inp, int hard);
extern void ray_shadow(ShadeInput *, LampRen *, float *, int);
extern void ray_trace(ShadeInput *, ShadeResult *, int);
extern void ray_ao(ShadeInput *, World *, float *);
/**
* Apply the background (sky). Depending on the active alphamode and

View File

@@ -425,8 +425,8 @@ void freeoctree(void)
// printf("branches %d nodes %d\n", branchcount, nodecount);
// printf("raycount %d \n", raycount);
// printf("ray coherent %d \n", coherent_ray);
printf("raycount %d \n", raycount);
printf("ray coherent %d \n", coherent_ray);
// printf("accepted %d rejected %d\n", accepted, rejected);
branchcount= 0;
@@ -1844,6 +1844,102 @@ int ray_trace_shadow_rad(ShadeInput *ship, ShadeResult *shr)
return 1;
}
/* aolight: function to create random unit sphere vectors for total random sampling */
#include <BLI_rand.h>
void RandomSpherical(float *v)
{
float r;
v[2] = 2.f*BLI_frand()-1.f;
if ((r = 1.f - v[2]*v[2])>0.f) {
float a = 6.283185307f*BLI_frand();
r = sqrt(r);
v[0] = r * cos(a);
v[1] = r * sin(a);
}
else v[2] = 1.f;
}
/* extern call from shade_lamp_loop, ambient occlusion calculus */
void ray_ao(ShadeInput *shi, World *wrld, float *shadfac)
{
Isect isec;
float nrm[3], vec[3], ru[3], rv[3];
float d, z1, z2, sqz1, sz2, cz2, sh=0;
int grid = wrld->aosamp;
float gdiv = 1.0/grid;
float gdiv2p = gdiv*2.0*M_PI;
float maxdist = wrld->aodist;
int x, y;
int j=0;
VECCOPY(isec.start, shi->co);
isec.vlrorig= shi->vlr;
isec.mode= DDA_SHADOW;
coh_test= 0; // reset coherence optimize
VECCOPY(nrm, shi->vn);
if ((nrm[0]==0.0) && (nrm[1]==0.0)) {
if (nrm[2]<0) ru[0]=-1; else ru[0]=1;
ru[1] = ru[2] = 0;
rv[0] = rv[2] = 0;
rv[1] = 1;
}
else {
ru[0] = nrm[1];
ru[1] = -nrm[0];
ru[2] = 0.0;
d = ru[0]*ru[0] + ru[1]*ru[1];
if (d!=0) {
d = 1.0/sqrt(d);
ru[0] *= d;
ru[1] *= d;
}
Crossf(rv, nrm, ru);
}
for (x=0;x<grid;x++) {
for (y=0;y<grid;y++) {
if (wrld->aomode & WO_AORNDSMP) {
/* total random sampling */
RandomSpherical(vec);
if ((vec[0]*nrm[0] + vec[1]*nrm[1] + vec[2]*nrm[2]) < 0.0) {
vec[0] = -vec[0];
vec[1] = -vec[1];
vec[2] = -vec[2];
}
}
else {
/* stratified uniform sampling */
z1 = (x + BLI_frand()) * gdiv;
z2 = (y + BLI_frand()) * gdiv2p;
if ((sqz1 = 1.0-z1*z1)<0) sqz1=0; else sqz1=sqrt(sqz1);
sz2 = sin(z2);
cz2 = cos(z2);
vec[0] = sqz1*(cz2*ru[0] + sz2*rv[0]) + nrm[0]*z1;
vec[1] = sqz1*(cz2*ru[1] + sz2*rv[1]) + nrm[1]*z1;
vec[2] = sqz1*(cz2*ru[2] + sz2*rv[2]) + nrm[2]*z1;
}
isec.end[0] = shi->co[0] - maxdist*vec[0];
isec.end[1] = shi->co[1] - maxdist*vec[1];
isec.end[2] = shi->co[2] - maxdist*vec[2];
if (R.r.mode & R_OSA) {
isec.start[0]= shi->co[0] + (jit[j][0]-0.5)*O.dxco[0] + (jit[j][1]-0.5)*O.dyco[0] ;
isec.start[1]= shi->co[1] + (jit[j][0]-0.5)*O.dxco[1] + (jit[j][1]-0.5)*O.dyco[1] ;
isec.start[2]= shi->co[2] + (jit[j][0]-0.5)*O.dxco[2] + (jit[j][1]-0.5)*O.dyco[2] ;
j = ((j+1) % R.osa);
}
if (d3dda(&isec)) {
if (wrld->aomode & WO_AODIST) sh+=exp(-isec.labda*wrld->aodistfac); else sh+=1.0;
}
}
}
shadfac[3] = 1.0 - (sh/(float)wrld->aototsamp);
}
/* extern call from shade_lamp_loop */
void ray_shadow(ShadeInput *shi, LampRen *lar, float *shadfac, int mask)

View File

@@ -1640,6 +1640,24 @@ void shade_color(ShadeInput *shi, ShadeResult *shr)
shr->alpha= ma->alpha;
}
static void ambient_occlusion(World *wrld, ShadeInput *shi, ShadeResult *shr)
{
float f, shadfac[4];
if(wrld->mode & WO_AMB_OCC) {
ray_ao(shi, wrld, shadfac);
if (wrld->aomix==WO_AOADDSUB) shadfac[3] = 2.0*shadfac[3]-1.0;
else if (wrld->aomix==WO_AOSUB) shadfac[3] = -(1.0-shadfac[3]);
f= shadfac[3]*shi->matren->amb;
shr->diff[0] += f;
shr->diff[1] += f;
shr->diff[2] += f;
}
}
/* mask is used to define the amount of rays/samples */
void shade_lamp_loop(ShadeInput *shi, ShadeResult *shr, int mask)
{
@@ -1747,6 +1765,8 @@ void shade_lamp_loop(ShadeInput *shi, ShadeResult *shr, int mask)
}
else shr->diff[0]= shr->diff[1]= shr->diff[2]= ma->emit;
ambient_occlusion(&R.wrld, shi, shr);
for(a=0; a<R.totlamp; a++) {
lar= R.la[a];

View File

@@ -1688,6 +1688,44 @@ static void world_panel_mistaph(World *wrld)
}
static void world_panel_amb_occ(World *wrld)
{
uiBlock *block;
block= uiNewBlock(&curarea->uiblocks, "world_panel_amb_oc", UI_EMBOSS, UI_HELV, curarea->win);
uiNewPanelTabbed("Mist / Stars / Physics", "World");
if(uiNewPanel(curarea, block, "Amb Occ", "World", 320, 0, 318, 204)==0) return;
uiBlockSetCol(block, TH_BUT_SETTING1);
uiDefButS(block, TOG|BIT|4,B_REDR, "Ambient Occlusion",10,150,300,19, &wrld->mode, 0, 0, 0, 0, "Toggles starfield generation");
uiBlockSetCol(block, TH_AUTO);
if(wrld->mode & WO_AMB_OCC) {
/* aolight: samples */
uiBlockBeginAlign(block);
uiDefButS(block, NUM, 0, "Samples:", 10, 120, 150, 19, &wrld->aosamp, 1.0, 16.0, 100, 0, "Sets the number of samples used for AO (actual number: squared)");
/* enable/disable total random sampling */
uiDefButS(block, TOG|BIT|1, 0, "Random Sampling", 160, 120, 150, 19, &wrld->aomode, 0, 0, 0, 0, "When enabled, total random sampling will be used for an even noisier effect");
uiBlockEndAlign(block);
uiDefButF(block, NUM, 0, "Dist:", 10, 95, 150, 19, &wrld->aodist, 0.001, 5000.0, 100, 0, "Sets length of AO rays, defines how far away other faces give occlusion effect");
uiBlockBeginAlign(block);
uiDefButS(block, TOG|BIT|0, B_REDR, "Use Distances", 10, 70, 150, 19, &wrld->aomode, 0, 0, 0, 0, "When enabled, distances to objects will be used to attenuate shadows");
/* distance attenuation factor */
if (wrld->aomode & WO_AODIST)
uiDefButF(block, NUM, 0, "DistF:", 160, 70, 150, 19, &wrld->aodistfac, 0.00001, 10.0, 100, 0, "Distance factor, the higher, the 'shorter' the shadows");
/* result mix modes */
uiBlockBeginAlign(block);
uiDefButS(block, ROW, B_REDR, "Add", 10, 45, 100, 20, &wrld->aomix, 1.0, (float)WO_AOADD, 0, 0, "adds light/shadows");
uiDefButS(block, ROW, B_REDR, "Sub", 110, 45, 100, 20, &wrld->aomix, 1.0, (float)WO_AOSUB, 0, 0, "subtracts light/shadows (needs at least one normal light to make anything visible)");
uiDefButS(block, ROW, B_REDR, "Both", 210, 45, 100, 20, &wrld->aomix, 1.0, (float)WO_AOADDSUB, 0, 0, "both lightens & darkens");
}
}
static void world_panel_world(World *wrld)
{
uiBlock *block;
@@ -2757,6 +2795,7 @@ void world_panels()
if(wrld) {
world_panel_mistaph(wrld);
world_panel_amb_occ(wrld);
world_panel_texture(wrld);
world_panel_mapto(wrld);
}