diff options
author | Ton Roosendaal <ton@blender.org> | 2004-04-06 01:04:13 +0400 |
---|---|---|
committer | Ton Roosendaal <ton@blender.org> | 2004-04-06 01:04:13 +0400 |
commit | 2a90de034826cd172117e6dd9764bfb481c1b14f (patch) | |
tree | a33d07ed7346bc7f7266857195a48efc0ddb957f | |
parent | e4ce73c99eca48d7d494f5e2d0ca0e034f7d4a62 (diff) |
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..
-rw-r--r-- | source/blender/blenkernel/intern/world.c | 5 | ||||
-rw-r--r-- | source/blender/blenloader/intern/readfile.c | 8 | ||||
-rw-r--r-- | source/blender/makesdna/DNA_world_types.h | 18 | ||||
-rw-r--r-- | source/blender/render/intern/include/rendercore.h | 1 | ||||
-rw-r--r-- | source/blender/render/intern/source/ray.c | 100 | ||||
-rw-r--r-- | source/blender/render/intern/source/rendercore.c | 20 | ||||
-rw-r--r-- | source/blender/src/buttons_shading.c | 39 |
7 files changed, 188 insertions, 3 deletions
diff --git a/source/blender/blenkernel/intern/world.c b/source/blender/blenkernel/intern/world.c index a5872c0abe9..a31c33e76e6 100644 --- a/source/blender/blenkernel/intern/world.c +++ b/source/blender/blenkernel/intern/world.c @@ -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)); diff --git a/source/blender/blenloader/intern/readfile.c b/source/blender/blenloader/intern/readfile.c index 4797e85d2f4..9f6ba376180 100644 --- a/source/blender/blenloader/intern/readfile.c +++ b/source/blender/blenloader/intern/readfile.c @@ -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; + } + } diff --git a/source/blender/makesdna/DNA_world_types.h b/source/blender/makesdna/DNA_world_types.h index efa17af4996..c325c2d1b8a 100644 --- a/source/blender/makesdna/DNA_world_types.h +++ b/source/blender/makesdna/DNA_world_types.h @@ -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 diff --git a/source/blender/render/intern/include/rendercore.h b/source/blender/render/intern/include/rendercore.h index 288ff10937f..2daf4c2c299 100644 --- a/source/blender/render/intern/include/rendercore.h +++ b/source/blender/render/intern/include/rendercore.h @@ -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 diff --git a/source/blender/render/intern/source/ray.c b/source/blender/render/intern/source/ray.c index 00bb576aea8..dc736b85e22 100644 --- a/source/blender/render/intern/source/ray.c +++ b/source/blender/render/intern/source/ray.c @@ -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) diff --git a/source/blender/render/intern/source/rendercore.c b/source/blender/render/intern/source/rendercore.c index 75ef82658f4..1055e564beb 100644 --- a/source/blender/render/intern/source/rendercore.c +++ b/source/blender/render/intern/source/rendercore.c @@ -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]; diff --git a/source/blender/src/buttons_shading.c b/source/blender/src/buttons_shading.c index 92fd7367209..7fab5d569f8 100644 --- a/source/blender/src/buttons_shading.c +++ b/source/blender/src/buttons_shading.c @@ -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); } |