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:
@@ -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));
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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];
|
||||
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user