Approximate Ambient Occlusion

=============================

A new approximate ambient occlusion method has been added, next to the
existing one based on raytracing. This method is specifically targetted
at use in animations, since it is inherently noise free, and so will
not flicker across frames.

http://www.blender.org/development/current-projects/changes-since-244/approximate-ambient-occlusion/
http://peach.blender.org/index.php/approximate-ambient-occlusion/

Further improvements are still needed, but it can be tested already. There
are still a number of known issues:

- Bias errors on backfaces.
- For performance, instanced object do not occlude currently.
- Sky textures don't work well, the derivatives for texture evaluation
  are not correct.
- Multiple passes do not work entirely correct (they are not accurate
  to begin with, but could be better).
This commit is contained in:
Brecht Van Lommel 2008-01-17 19:27:16 +00:00
parent 9af3b8a07e
commit 8cdfe865ec
18 changed files with 1925 additions and 76 deletions

View File

@ -98,12 +98,12 @@ World *add_world(char *name)
wrld->exp= 0.0f;
wrld->exposure=wrld->range= 1.0f;
wrld->aodist= 5.0;
wrld->aodist= 5.0f;
wrld->aosamp= 5;
wrld->aoenergy= 1.0;
wrld->aobias= 0.05;
wrld->aoenergy= 1.0f;
wrld->aobias= 0.05f;
wrld->ao_samp_method = WO_AOSAMP_HAMMERSLEY;
wrld->ao_approx_error= 0.25f;
wrld->physicsEngine= WOPHY_BULLET;//WOPHY_SUMO; Bullet by default
wrld->preview = NULL;

View File

@ -6698,6 +6698,7 @@ static void do_versions(FileData *fd, Library *lib, Main *main)
Lamp *la;
Material *ma;
ParticleSettings *part;
World *wrld;
Mesh *me;
/* unless the file was created 2.44.3 but not 2.45, update the constraints */
@ -6878,6 +6879,11 @@ static void do_versions(FileData *fd, Library *lib, Main *main)
}
}
for(wrld=main->world.first; wrld; wrld= wrld->id.next) {
if(wrld->ao_approx_error == 0.0f)
wrld->ao_approx_error= 0.25f;
}
if (main->versionfile < 245 || main->subversionfile < 12)
{
/* initialize skeleton generation toolsettings */

View File

@ -104,9 +104,8 @@ typedef struct World {
float aodist, aodistfac, aoenergy, aobias;
short aomode, aosamp, aomix, aocolor;
float ao_adapt_thresh, ao_adapt_speed_fac;
float pad2[2];
short ao_samp_method;
short pad1[3];
float ao_approx_error, ao_approx_correction;
short ao_samp_method, ao_gather_method, ao_approx_passes, pad1;
float *aosphere, *aotables;
@ -151,12 +150,17 @@ typedef struct World {
/* aomode (use distances & random sampling modes) */
#define WO_AODIST 1
#define WO_AORNDSMP 2
#define WO_AOCACHE 4
/* aocolor */
#define WO_AOPLAIN 0
#define WO_AOSKYCOL 1
#define WO_AOSKYTEX 2
/* ao_gather_method */
#define WO_AOGATHER_RAYTRACE 0
#define WO_AOGATHER_APPROX 1
/* texco (also in DNA_material_types.h) */
#define TEXCO_ANGMAP 64
#define TEXCO_H_SPHEREMAP 256

View File

@ -64,6 +64,7 @@ struct ShadeInputCopy {
struct Material *mat;
struct VlakRen *vlr;
struct StrandRen *strand;
struct ObjectInstanceRen *obi;
struct ObjectRen *obr;
int facenr;
@ -96,6 +97,7 @@ typedef struct ShadeInput
struct Material *mat;
struct VlakRen *vlr;
struct StrandRen *strand;
struct ObjectInstanceRen *obi;
struct ObjectRen *obr;
int facenr;
@ -132,7 +134,7 @@ typedef struct ShadeInput
/* texture coordinates */
float lo[3], gl[3], ref[3], orn[3], winco[3], sticky[3], vcol[4], rad[3];
float refcol[4], displace[3];
float strand, tang[3], stress, winspeed[4];
float strandco, tang[3], stress, winspeed[4];
float duplilo[3], dupliuv[3];
ShadeInputUV uv[8]; /* 8 = MAX_MTFACE */

View File

@ -0,0 +1,51 @@
/*
* $Id$
*
* ***** BEGIN GPL LICENSE BLOCK *****
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*
* The Original Code is Copyright (C) 2008 Blender Foundation.
* All rights reserved.
*
* The Original Code is: all of this file.
*
* Contributor(s): Brecht Van Lommel.
*
* ***** END GPL LICENSE BLOCK *****
*/
#ifndef OCCLUSION_H
#define OCCLUSION_H
struct Render;
struct ShadeInput;
struct ShadeResult;
struct RenderPart;
struct ShadeSample;
struct DerivedMesh;
struct ObjectRen;
void make_occ_tree(struct Render *re);
void free_occ(struct Render *re);
void sample_occ(struct Render *re, struct ShadeInput *shi);
void cache_occ_samples(struct Render *re, struct RenderPart *pa, struct ShadeSample *ssamp);
void free_occ_samples(struct Render *re, struct RenderPart *pa);
void *cache_occ_mesh(struct Render *re, struct ObjectRen *obr, struct DerivedMesh *dm, float mat[][4]);
#endif

View File

@ -158,6 +158,10 @@ struct Render
/* octree tables and variables for raytrace */
void *raytree;
/* occlusion tree */
void *occlusiontree;
ListBase occlusionmesh;
/* use this instead of R.r.cfra */
float cfra;
@ -341,6 +345,7 @@ typedef struct StrandBuffer {
struct ObjectRen *obr;
struct Material *ma;
void *occlusionmesh;
unsigned int lay;
int overrideuv;
int flag, maxdepth;

View File

@ -70,6 +70,7 @@ typedef struct StrandTableNode {
float *winspeed;
float *surfnor;
float *simplify;
int *face;
struct MCol *mcol;
float *uv;
int totuv, totmcol;
@ -114,6 +115,7 @@ float *RE_strandren_get_surfnor(struct ObjectRen *obr, struct StrandRen *strand,
float *RE_strandren_get_uv(struct ObjectRen *obr, struct StrandRen *strand, int n, char **name, int verify);
struct MCol *RE_strandren_get_mcol(struct ObjectRen *obr, struct StrandRen *strand, int n, char **name, int verify);
float *RE_strandren_get_simplify(struct ObjectRen *obr, struct StrandRen *strand, int verify);
int *RE_strandren_get_face(struct ObjectRen *obr, struct StrandRen *strand, int verify);
float *RE_strandren_get_winspeed(struct ObjectInstanceRen *obi, struct StrandRen *strand, int verify);
struct VertRen *RE_vertren_copy(struct ObjectRen *obr, struct VertRen *ver);

View File

@ -69,6 +69,7 @@ void shade_input_initialize(struct ShadeInput *shi, struct RenderPart *pa, struc
void shade_sample_initialize(struct ShadeSample *ssamp, struct RenderPart *pa, struct RenderLayer *rl);
void shade_samples_do_AO(struct ShadeSample *ssamp);
void shade_samples_fill_with_ps(struct ShadeSample *ssamp, struct PixStr *ps, int x, int y);
int shade_samples(struct ShadeSample *ssamp, struct PixStr *ps, int x, int y);
void vlr_set_uv_indices(struct VlakRen *vlr, int *i1, int *i2, int *i3);

View File

@ -100,6 +100,7 @@
#include "envmap.h"
#include "multires.h"
#include "occlusion.h"
#include "render_types.h"
#include "rendercore.h"
#include "renderdatabase.h"
@ -1497,7 +1498,7 @@ static int render_new_particle_system(Render *re, ObjectRen *obr, ParticleSystem
float *orco=0,*surfnor=0,*uvco=0, strandlen=0.0f, curlen=0.0f;
float hasize, pa_size, pa_time, r_tilt, cfra=bsystem_time(ob,(float)CFRA,0.0);
float adapt_angle=0.0, adapt_pix=0.0, random, simplify[2];
int i, a, k, max_k=0, totpart, totuv=0, override_uv=-1, dosimplify = 0;
int i, a, k, max_k=0, totpart, totuv=0, override_uv=-1, dosimplify = 0, doapproxao = 0;
int path_possible=0, keys_possible=0, baked_keys=0, totchild=psys->totchild;
int seed, path_nbr=0, path=0, orco1=0, adapt=0, uv[3]={0,0,0}, num;
char **uv_name=0;
@ -1656,6 +1657,10 @@ static int render_new_particle_system(Render *re, ObjectRen *obr, ParticleSystem
strandbuf->flag |= R_STRAND_B_UNITS;
svert= strandbuf->vert;
if((re->wrld.mode & WO_AMB_OCC) && (re->wrld.ao_gather_method == WO_AOGATHER_APPROX))
if(ma->amb != 0.0f)
doapproxao= 1;
}
}
}
@ -1704,15 +1709,15 @@ static int render_new_particle_system(Render *re, ObjectRen *obr, ParticleSystem
else
psys_particle_on_emitter(ob, psmd,part->from,pa->num,pa->num_dmcache,pa->fuv,pa->foffset,co,nor,0,0,orco,0);
num= pa->num_dmcache;
if(num == DMCACHE_NOTFOUND)
if(pa->num < psmd->dm->getNumFaces(psmd->dm))
num= pa->num;
if(uvco && ELEM(part->from,PART_FROM_FACE,PART_FROM_VOLUME)){
layer=psmd->dm->faceData.layers + CustomData_get_layer_index(&psmd->dm->faceData,CD_MFACE);
num= pa->num_dmcache;
if(num == DMCACHE_NOTFOUND)
if(pa->num < psmd->dm->getNumFaces(psmd->dm))
num= pa->num;
for(i=0; i<totuv; i++){
if(num != DMCACHE_NOTFOUND) {
MFace *mface=psmd->dm->getFaceData(psmd->dm,num,CD_MFACE);
@ -1761,6 +1766,8 @@ static int render_new_particle_system(Render *re, ObjectRen *obr, ParticleSystem
r_tilt=2.0f*cpa->rand[2];
num= cpa->num;
/* get orco */
psys_particle_on_emitter(ob, psmd,
(part->childtype == PART_CHILD_FACES)? PART_FROM_FACE: PART_FROM_PARTICLE,
@ -1831,6 +1838,11 @@ static int render_new_particle_system(Render *re, ObjectRen *obr, ParticleSystem
VECCOPY(snor, surfnor);
}
if(doapproxao && num >= 0) {
int *facenum= RE_strandren_get_face(obr, strand, 1);
*facenum= num;
}
if(uvco){
for(i=0; i<totuv; i++){
if(i != override_uv) {
@ -1930,6 +1942,9 @@ static int render_new_particle_system(Render *re, ObjectRen *obr, ParticleSystem
break;
}
if(doapproxao)
strandbuf->occlusionmesh= cache_occ_mesh(re, obr, psmd->dm, mat);
/* 4. clean up */
if(ma) do_mat_ipo(ma);
@ -3636,7 +3651,7 @@ void init_render_world(Render *re)
if(re->osa)
while(re->wrld.aosamp*re->wrld.aosamp < re->osa)
re->wrld.aosamp++;
if(!(re->r.mode & R_RAYTRACE))
if(!(re->r.mode & R_RAYTRACE) && (re->wrld.ao_gather_method == WO_AOGATHER_RAYTRACE))
re->wrld.mode &= ~WO_AMB_OCC;
}
else {
@ -4069,6 +4084,7 @@ void RE_Database_Free(Render *re)
if(re->r.mode & R_RAYTRACE) freeraytree(re);
free_sss(re);
free_occ(re);
re->totvlak=re->totvert=re->totstrand=re->totlamp=re->tothalo= 0;
re->i.convertdone= 0;
@ -4289,7 +4305,7 @@ void RE_Database_FromScene(Render *re, Scene *scene, int use_camera_view)
}
init_render_world(re); /* do first, because of ambient. also requires re->osa set correct */
if(re->wrld.mode & WO_AMB_OCC) {
if((re->r.mode & R_RAYTRACE) && (re->wrld.mode & WO_AMB_OCC)) {
if (re->wrld.ao_samp_method == WO_AOSAMP_HAMMERSLEY)
init_render_hammersley(re);
else if (re->wrld.ao_samp_method == WO_AOSAMP_CONSTANT)
@ -4354,10 +4370,16 @@ void RE_Database_FromScene(Render *re, Scene *scene, int use_camera_view)
if(!re->test_break())
project_renderdata(re, projectverto, re->r.mode & R_PANORAMA, 0, 1);
/* Occlusion */
if((re->wrld.mode & WO_AMB_OCC) && !re->test_break())
if(re->wrld.ao_gather_method == WO_AOGATHER_APPROX)
if(re->r.renderer==R_INTERN)
make_occ_tree(re);
/* SSS */
if((re->r.mode & R_SSS) && !re->test_break())
if (re->r.renderer==R_INTERN)
if(re->r.renderer==R_INTERN)
make_sss_tree(re);
}
@ -4837,7 +4859,7 @@ void RE_Database_Baking(Render *re, Scene *scene, int type, Object *actob)
}
init_render_world(re); /* do first, because of ambient. also requires re->osa set correct */
if(re->wrld.mode & WO_AMB_OCC) {
if((re->r.mode & R_RAYTRACE) && (re->wrld.mode & WO_AMB_OCC)) {
if (re->wrld.ao_samp_method == WO_AOSAMP_HAMMERSLEY)
init_render_hammersley(re);
else if (re->wrld.ao_samp_method == WO_AOSAMP_CONSTANT)

File diff suppressed because it is too large Load Diff

View File

@ -538,6 +538,9 @@ static RenderResult *new_render_result(Render *re, rcti *partrct, int crop, int
if(srl->passflag & SCE_PASS_REFRACT)
render_layer_add_pass(rr, rl, 3, SCE_PASS_REFRACT);
}
else if(re->wrld.mode & WO_AMB_OCC)
if(re->wrld.ao_gather_method == WO_AOGATHER_APPROX)
render_layer_add_pass(rr, rl, 3, SCE_PASS_AO);
if(re->r.mode & R_RADIO)
if(srl->passflag & SCE_PASS_RADIO)
render_layer_add_pass(rr, rl, 3, SCE_PASS_RADIO);

View File

@ -60,6 +60,7 @@
#include "renderpipeline.h"
#include "render_types.h"
#include "renderdatabase.h"
#include "occlusion.h"
#include "pixelblending.h"
#include "pixelshading.h"
#include "shadbuf.h"
@ -534,7 +535,11 @@ static void shadeDA_tile(RenderPart *pa, RenderLayer *rl)
/* general shader info, passes */
shade_sample_initialize(&ssamp, pa, rl);
addpassflag= rl->passflag & ~(SCE_PASS_Z|SCE_PASS_COMBINED);
/* occlusion caching */
if(R.occlusiontree)
cache_occ_samples(&R, pa, &ssamp);
/* filtered render, for now we assume only 1 filter size */
if(pa->crop) {
crop= 1;
@ -582,6 +587,9 @@ static void shadeDA_tile(RenderPart *pa, RenderLayer *rl)
if(R.r.mode & R_SHADOW)
ISB_free(pa);
if(R.occlusiontree)
free_occ_samples(&R, pa);
}
/* ************* pixel struct ******** */
@ -1072,6 +1080,9 @@ void zbufshade_tile(RenderPart *pa)
/* irregular shadowb buffer creation */
if(R.r.mode & R_SHADOW)
ISB_create(pa, NULL);
if(R.occlusiontree)
cache_occ_samples(&R, pa, &ssamp);
for(y=pa->disprect.ymin; y<pa->disprect.ymax; y++, rr->renrect.ymax++) {
for(x=pa->disprect.xmin; x<pa->disprect.xmax; x++, ro++, rz++, rp++, fcol+=4, offs++) {
@ -1085,9 +1096,6 @@ void zbufshade_tile(RenderPart *pa)
if(shade_samples(&ssamp, &ps, x, y)) {
QUATCOPY(fcol, ssamp.shr[0].combined);
if(!(fcol[0] == fcol[0]))
printvecf("fudgecol", fcol);
/* passes */
if(addpassflag)
add_passes(rl, offs, ssamp.shi, ssamp.shr);
@ -1098,6 +1106,9 @@ void zbufshade_tile(RenderPart *pa)
if(R.test_break()) break;
}
if(R.occlusiontree)
free_occ_samples(&R, pa);
if(R.r.mode & R_SHADOW)
ISB_free(pa);
}

View File

@ -105,6 +105,7 @@
#define RE_UV_ELEMS 2
#define RE_SURFNOR_ELEMS 3
#define RE_SIMPLIFY_ELEMS 2
#define RE_FACE_ELEMS 1
float *RE_vertren_get_sticky(ObjectRen *obr, VertRen *ver, int verify)
{
@ -607,6 +608,21 @@ float *RE_strandren_get_simplify(struct ObjectRen *obr, struct StrandRen *strand
return simplify + (strand->index & 255)*RE_SIMPLIFY_ELEMS;
}
int *RE_strandren_get_face(ObjectRen *obr, StrandRen *strand, int verify)
{
int *face;
int nr= strand->index>>8;
face= obr->strandnodes[nr].face;
if(face==NULL) {
if(verify)
face= obr->strandnodes[nr].face= MEM_callocN(256*RE_FACE_ELEMS*sizeof(int), "face table");
else
return NULL;
}
return face + (strand->index & 255)*RE_FACE_ELEMS;
}
/* winspeed is exception, it is stored per instance */
float *RE_strandren_get_winspeed(ObjectInstanceRen *obi, StrandRen *strand, int verify)
{
@ -757,6 +773,8 @@ void free_renderdata_strandnodes(StrandTableNode *strandnodes)
MEM_freeN(strandnodes[a].surfnor);
if(strandnodes[a].simplify)
MEM_freeN(strandnodes[a].simplify);
if(strandnodes[a].face)
MEM_freeN(strandnodes[a].face);
}
MEM_freeN(strandnodes);

View File

@ -422,7 +422,7 @@ void shade_input_set_strand_texco(ShadeInput *shi, StrandRen *strand, StrandVert
}
if(texco & TEXCO_STRAND) {
shi->strand= spoint->strandco;
shi->strandco= spoint->strandco;
if(shi->osatex) {
shi->dxstrand= spoint->dtstrandco;
@ -935,7 +935,7 @@ void shade_input_set_shade_texco(ShadeInput *shi)
}
if(texco & TEXCO_STRAND) {
shi->strand= (l*v3->accum - u*v1->accum - v*v2->accum);
shi->strandco= (l*v3->accum - u*v1->accum - v*v2->accum);
if(shi->osatex) {
dl= shi->dx_u+shi->dx_v;
shi->dxstrand= dl*v3->accum-shi->dx_u*v1->accum-shi->dx_v*v2->accum;
@ -1236,7 +1236,7 @@ void shade_samples_do_AO(ShadeSample *ssamp)
if(!(R.r.mode & R_SHADOW))
return;
if(!(R.r.mode & R_RAYTRACE))
if(!(R.r.mode & R_RAYTRACE) && !(R.wrld.ao_gather_method == WO_AOGATHER_APPROX))
return;
if(R.wrld.mode & WO_AMB_OCC)
@ -1248,7 +1248,7 @@ void shade_samples_do_AO(ShadeSample *ssamp)
}
static void shade_samples_fill_with_ps(ShadeSample *ssamp, PixStr *ps, int x, int y)
void shade_samples_fill_with_ps(ShadeSample *ssamp, PixStr *ps, int x, int y)
{
ShadeInput *shi;
float xs, ys;

View File

@ -43,6 +43,7 @@
#include "DNA_material_types.h"
/* local include */
#include "occlusion.h"
#include "renderpipeline.h"
#include "render_types.h"
#include "pixelblending.h"
@ -1006,8 +1007,9 @@ static void do_specular_ramp(ShadeInput *shi, float is, float t, float *spec)
/* pure AO, check for raytrace and world should have been done */
void ambient_occlusion(ShadeInput *shi)
{
if((R.r.mode & R_RAYTRACE) && shi->mat->amb!=0.0f)
if((R.wrld.ao_gather_method == WO_AOGATHER_APPROX) && shi->mat->amb!=0.0f)
sample_occ(&R, shi);
else if((R.r.mode & R_RAYTRACE) && shi->mat->amb!=0.0f)
ray_ao(shi, shi->ao);
else
shi->ao[0]= shi->ao[1]= shi->ao[2]= 1.0f;
@ -1017,25 +1019,28 @@ void ambient_occlusion(ShadeInput *shi)
/* wrld mode was checked for */
void ambient_occlusion_to_diffuse(ShadeInput *shi, float *diff)
{
if((R.r.mode & R_RAYTRACE) && shi->mat->amb!=0.0f) {
float f= R.wrld.aoenergy*shi->mat->amb;
if((R.r.mode & R_RAYTRACE) || R.wrld.ao_gather_method == WO_AOGATHER_APPROX) {
if(shi->mat->amb!=0.0f) {
float f= R.wrld.aoenergy*shi->mat->amb;
if (R.wrld.aomix==WO_AOADDSUB) {
diff[0] = 2.0f*shi->ao[0]-1.0f;
diff[1] = 2.0f*shi->ao[1]-1.0f;
diff[2] = 2.0f*shi->ao[2]-1.0f;
if (R.wrld.aomix==WO_AOADDSUB) {
diff[0] = 2.0f*shi->ao[0]-1.0f;
diff[1] = 2.0f*shi->ao[1]-1.0f;
diff[2] = 2.0f*shi->ao[2]-1.0f;
}
else if (R.wrld.aomix==WO_AOSUB) {
diff[0] = shi->ao[0]-1.0f;
diff[1] = shi->ao[1]-1.0f;
diff[2] = shi->ao[2]-1.0f;
}
else {
VECCOPY(diff, shi->ao);
}
VECMUL(diff, f);
}
else if (R.wrld.aomix==WO_AOSUB) {
diff[0] = shi->ao[0]-1.0f;
diff[1] = shi->ao[1]-1.0f;
diff[2] = shi->ao[2]-1.0f;
}
else {
VECCOPY(diff, shi->ao);
}
VECMUL(diff, f);
else
diff[0]= diff[1]= diff[2]= 0.0f;
}
else
diff[0]= diff[1]= diff[2]= 0.0f;

View File

@ -685,6 +685,7 @@ static void strand_shade_point(Render *re, ShadeSample *ssamp, StrandSegment *ss
vlr.flag |= R_TANGENT;
shi->vlr= &vlr;
shi->strand= sseg->strand;
shi->obi= sseg->obi;
shi->obr= sseg->obi->obr;

View File

@ -1521,7 +1521,7 @@ void do_material_tex(ShadeInput *shi)
}
else if(mtex->texco==TEXCO_STRAND) {
co= tempvec; dx= dxt; dy= dyt;
co[0]= shi->strand;
co[0]= shi->strandco;
co[1]= co[2]= 0.0f;
dx[0]= shi->dxstrand;
dx[1]= dx[2]= 0.0f;

View File

@ -2152,18 +2152,27 @@ static void world_panel_amb_occ(World *wrld)
uiBlockSetCol(block, TH_AUTO);
if(!(wrld->mode & WO_AMB_OCC)) return;
yco -= YSPACE;
uiDefButS(block, NUM, B_REDR, "Samples:",
X2CLM1, yco-=BUTH, BUTW2, BUTH, &wrld->aosamp, 1.0, 32.0, 100, 0, "Sets the number of samples used for AO (actual number: squared)");
yco -= YSPACE;
uiDefButF(block, NUM, B_REDR, "Max Dist:",
X2CLM1, yco-=BUTH, BUTW2, BUTH, &wrld->aodist, 0.001, 5000.0, 100, 0, "Sets length of AO rays, defines how far away other faces give occlusion effect");
yco -= YSPACE;
if(wrld->ao_gather_method == WO_AOGATHER_RAYTRACE) {
uiDefButS(block, NUM, B_REDR, "Samples:",
X2CLM1, yco-=BUTH, BUTW2, BUTH, &wrld->aosamp, 1.0, 32.0, 100, 0, "Sets the number of samples used for AO (actual number: squared)");
yco -= YSPACE;
uiDefButF(block, NUM, B_REDR, "Max Dist:",
X2CLM1, yco-=BUTH, BUTW2, BUTH, &wrld->aodist, 0.001, 5000.0, 100, 0, "Sets length of AO rays, defines how far away other faces give occlusion effect");
}
else {
uiDefButS(block, NUM, B_REDR, "Passes:",
X2CLM1, yco-=BUTH, BUTW2, BUTH, &wrld->ao_approx_passes, 0.0, 10.0, 0, 0, "Sets the number of preprocessing passes to reduce overocclusion");
yco -= YSPACE;
uiDefButF(block, NUM, B_REDR, "Correction:",
X2CLM1, yco-=BUTH, BUTW2, BUTH, &wrld->ao_approx_correction, 0.0, 1.0, 0, 0, "Ad-hoc correction for over-occlusion due to the approximation.");
}
uiBlockBeginAlign(block);
uiDefButBitS(block, TOG, WO_AODIST, B_AO_FALLOFF, "Use Falloff",
@ -2176,23 +2185,38 @@ static void world_panel_amb_occ(World *wrld)
/* column 2 */
yco = PANEL_YMAX - BUTH - YSPACE;
uiDefButS(block, MENU, B_REDR, "Constant QMC %x2|Adaptive QMC %x1|Constant Jittered %x0",
X2CLM2, yco-=BUTH, BUTW2, BUTH, &wrld->ao_samp_method, 0, 0, 0, 0, "Method for generating shadow samples: Constant QMC: best quality, Adaptive QMC: fast in high contrast areas");
yco -= YSPACE;
if (wrld->ao_samp_method == WO_AOSAMP_HALTON) {
uiBlockBeginAlign(block);
uiDefButF(block, NUM, B_REDR, "Threshold:",
X2CLM2, yco-=BUTH, BUTW2, BUTH, &wrld->ao_adapt_thresh, 0.0, 1.0, 100, 0, "Samples below this threshold will be considered fully shadowed/unshadowed and skipped");
uiDefButF(block, NUMSLI, B_REDR, "Adapt Vec:",
X2CLM2, yco-=BUTH, BUTW2, BUTH, &wrld->ao_adapt_speed_fac, 0.0, 1.0, 100, 0, "Use the speed vector pass to reduce AO samples in fast moving pixels. The higher the value, the more aggressive the sample reduction. Requires Vec pass enabled.");
uiBlockEndAlign(block);
} else if (wrld->ao_samp_method == WO_AOSAMP_CONSTANT) {
uiDefButF(block, NUMSLI, B_REDR, "Bias:",
X2CLM2, yco-=BUTH, BUTW2, BUTH, &wrld->aobias, 0.0, 0.5, 10, 0, "Sets bias to prevent smoothed faces to show banding (in radians)");
}
uiDefButS(block, MENU, B_REDR, "Gather Method%t|Raytrace %x0|Approximate %x1",
X2CLM2, yco-=BUTH, BUTW2, BUTH, &wrld->ao_gather_method, 0, 0, 0, 0, "Method for occlusion gathering: Raytrace: slow when noise free results are required, but accurate, Approximate: faster and without noise, but inaccurate");
yco -= YSPACE;
if(wrld->ao_gather_method == WO_AOGATHER_RAYTRACE) {
uiDefButS(block, MENU, B_REDR, "Constant QMC %x2|Adaptive QMC %x1|Constant Jittered %x0",
X2CLM2, yco-=BUTH, BUTW2, BUTH, &wrld->ao_samp_method, 0, 0, 0, 0, "Method for generating shadow samples: Constant QMC: best quality, Adaptive QMC: fast in high contrast areas");
yco -= YSPACE;
if (wrld->ao_samp_method == WO_AOSAMP_HALTON) {
uiBlockBeginAlign(block);
uiDefButF(block, NUM, B_REDR, "Threshold:",
X2CLM2, yco-=BUTH, BUTW2, BUTH, &wrld->ao_adapt_thresh, 0.0, 1.0, 100, 0, "Samples below this threshold will be considered fully shadowed/unshadowed and skipped");
uiDefButF(block, NUMSLI, B_REDR, "Adapt Vec:",
X2CLM2, yco-=BUTH, BUTW2, BUTH, &wrld->ao_adapt_speed_fac, 0.0, 1.0, 100, 0, "Use the speed vector pass to reduce AO samples in fast moving pixels. The higher the value, the more aggressive the sample reduction. Requires Vec pass enabled.");
uiBlockEndAlign(block);
} else if (wrld->ao_samp_method == WO_AOSAMP_CONSTANT) {
uiDefButF(block, NUMSLI, B_REDR, "Bias:",
X2CLM2, yco-=BUTH, BUTW2, BUTH, &wrld->aobias, 0.0, 0.5, 10, 0, "Sets bias to prevent smoothed faces to show banding (in radians)");
}
}
else {
uiBlockBeginAlign(block);
uiDefButF(block, NUM, B_REDR, "Error:",
X2CLM2, yco-=BUTH, BUTW2, BUTH, &wrld->ao_approx_error, 0.0001, 10.0, 0, 0, "Error tolerance (low values are slower and higher quality)");
uiDefButBitS(block, TOG, WO_AOCACHE, B_REDR, "Pixel Cache",
X2CLM2, yco-=BUTH, BUTW2, BUTH, &wrld->aomode, 0, 0, 0, 0, "Cache AO results in pixels and interpolate over neighbouring pixels for speedup.");
uiBlockEndAlign(block);
}
yco = PANEL_YMAX - (5*BUTH+4*YSPACE);
@ -2204,6 +2228,7 @@ static void world_panel_amb_occ(World *wrld)
X3CLM2, yco, BUTW3, BUTH, &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",
X3CLM3, yco, BUTW3, BUTH, &wrld->aomix, 1.0, (float)WO_AOADDSUB, 0, 0, "both lightens & darkens");
uiBlockEndAlign(block);
yco -= YSPACE;
@ -2216,12 +2241,11 @@ static void world_panel_amb_occ(World *wrld)
uiDefButS(block, ROW, B_REDR, "Sky Texture",
X3CLM3, yco, BUTW3, BUTH, &wrld->aocolor, 2.0, (float)WO_AOSKYTEX, 0, 0, "Does full Sky texture render for diffuse energy");
uiBlockEndAlign(block);
yco -= YSPACE;
uiDefButF(block, NUMSLI, B_REDR, "Energy:",
X2CLM1, yco-=BUTH, BUTW2, BUTH, &wrld->aoenergy, 0.01, 3.0, 100, 0, "Sets global energy scale for AO");
}
static void world_panel_world(World *wrld)