Numerous fixes in Render code:

- Bug: material emit was ignored (showed in preview render backdrop)
- Bug: world exposure was ignored
- Bug: lamp halo was ignoring 'render layer light override'.

Further reshuffled the way shadows are being pre-calculated, this to enable
more advanced (and faster) usage of Material lightgroups. Now shadows are
being cached in lamps, using a per-sample counter to check if a recalc is
needed. Will also work (later) for Raytracing node shaders.

- New: Material LightGroup option "Always", which always shades the lights
  in the group, independent of visibility layer. (so it allows to move such
  lights to hidden layer, not influencing anything).
This commit is contained in:
Ton Roosendaal 2006-12-08 09:40:44 +00:00
parent 3da771fefc
commit 902a69a7d3
13 changed files with 106 additions and 113 deletions

@ -720,6 +720,7 @@ void shadeDispList(Base *base)
}
/* frees render and shade part of displists */
/* note: dont do a shade again, until a redraw happens */
void reshadeall_displist(void)
{
Base *base;

@ -5329,21 +5329,17 @@ static void do_versions(FileData *fd, Library *lib, Main *main)
Lamp *la;
World *wrld;
/* introduction of raytrace */
while(ma) {
if(ma->fresnel_tra_i==0.0) ma->fresnel_tra_i= 1.25;
if(ma->fresnel_mir_i==0.0) ma->fresnel_mir_i= 1.25;
if(ma->ang==0.0) {
ma->ang= 1.0;
ma->ray_depth= 2;
ma->ray_depth_tra= 2;
ma->fresnel_tra= 0.0;
ma->fresnel_mir= 0.0;
}
else if(ma->ang<1.0) { // temporal, because of IOR & fresnel change
ma->ang= 1.0f/ma->ang;
ma->fresnel_tra= ma->ang;
ma->fresnel_mir= ma->ang;
}
ma->ang= 1.0;
ma->ray_depth= 2;
ma->ray_depth_tra= 2;
ma->fresnel_tra= 0.0;
ma->fresnel_mir= 0.0;
ma= ma->id.next;
}
sce= main->scene.first;

@ -172,8 +172,9 @@ typedef struct Material {
#define MA_TANGENT_V 0x4000000
/* qdn: a bit clumsy this, tangents needed for normal maps separated from shading */
#define MA_NORMAP_TANG 0x8000000
#define MA_GROUP_NOLAY 0x10000000
#define MA_MODE_MASK 0xbffffff /* all valid mode bits */
#define MA_MODE_MASK 0x1fffffff /* all valid mode bits */
/* diff_shader */
#define MA_DIFF_LAMBERT 0

@ -132,7 +132,8 @@ typedef struct ShadeInput
int xs, ys; /* pixel to be rendered */
short osatex;
int mask;
int mask; /* subsample mask */
int samplenr; /* sample counter, to detect if we should do shadow again */
int depth; /* 1 or larger on raytrace shading */
/* from initialize, part or renderlayer */

@ -290,8 +290,13 @@ struct MTex;
* properties of a lightsource.
*/
typedef struct LampShadowSubSample {
int samplenr;
float shadfac[4]; /* rgba shadow */
} LampShadowSubSample;
typedef struct LampShadowSample {
float shadfac[16][4]; /* 16 = RE_MAX_OSA, 4 = rgba */
LampShadowSubSample s[16]; /* MAX OSA */
} LampShadowSample;
typedef struct LampRen {
@ -344,8 +349,7 @@ typedef struct LampRen {
float area[8][3], areasize;
/* passes & node shader support: all shadow info for a pixel */
/* struct is currently 2k long... check on alloc? */
LampShadowSample shadsamp[BLENDER_MAX_THREADS];
LampShadowSample *shadsamp;
/* yafray: photonlight params */
int YF_numphotons, YF_numsearch;

@ -28,6 +28,7 @@ struct ShadeResult;
struct RenderPart;
struct RenderLayer;
struct PixStr;
struct LampRen;
/* shadeinput.c */
@ -35,8 +36,12 @@ struct PixStr;
/* needed to calculate shadow and AO for an entire pixel */
typedef struct ShadeSample {
int tot; /* amount of shi in use, can be 1 for not FULL_OSA */
/* could be malloced once */
ShadeInput shi[16]; /* RE_MAX_OSA */
ShadeResult shr[16]; /* RE_MAX_OSA */
int samplenr; /* counter, detect shadow-reuse for shaders */
} ShadeSample;
@ -52,8 +57,10 @@ void shade_input_set_normals(struct ShadeInput *shi);
void shade_input_set_shade_texco(struct ShadeInput *shi);
void shade_input_do_shade(struct ShadeInput *shi, struct ShadeResult *shr);
void shade_input_initialize(struct ShadeInput *shi, struct RenderPart *pa, struct RenderLayer *rl, int sample);
void shade_sample_initialize(struct ShadeSample *ssamp, struct RenderPart *pa, struct RenderLayer *rl);
void shade_samples_do_shadow(struct ShadeSample *ssamp);
void shade_samples_do_AO(struct ShadeSample *ssamp);
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);

@ -2340,9 +2340,15 @@ static LampRen *add_render_lamp(Render *re, Object *ob)
}
}
}
/* yafray: shadowbuffers and jitter only needed for internal render */
/* yafray: shadow flag should not be cleared, only used with internal renderer */
if (re->r.renderer==R_INTERN) {
/* to make sure we can check ray shadow easily in the render code */
if(lar->mode & LA_SHAD_RAY) {
if( (re->r.mode & R_RAYTRACE)==0)
lar->mode &= ~LA_SHAD_RAY;
}
if(re->r.mode & R_SHADOW) {
if (la->type==LA_SPOT && (lar->mode & LA_SHAD_BUF) ) {
/* Per lamp, one shadow buffer is made. */
@ -2353,24 +2359,25 @@ static LampRen *add_render_lamp(Render *re, Object *ob)
else if(la->type==LA_AREA && (lar->mode & LA_SHAD_RAY) ) {
init_jitter_plane(lar);
}
/* this is the way used all over to check for shadow */
if(lar->shb || (lar->mode & LA_SHAD_RAY)) {
LampShadowSubSample *lss;
int a, b, tot= re->r.threads*re->r.osa;
lar->shadsamp= MEM_mallocN(re->r.threads*sizeof(LampShadowSample), "lamp shadow sample");
lss= lar->shadsamp[0].s;
/* shadfacs actually mean light, let's put them to 1 to prevent unitialized accidents */
for(a=0; a<tot; a++, lss++) {
for(b=0; b<4; b++) {
lss->samplenr= -1; /* used to detect whether we store or read */
lss->shadfac[b]= 1.0f;
}
}
}
}
}
/* yafray: shadow flag should not be cleared, only used with internal renderer */
if (re->r.renderer==R_INTERN) {
int a, b;
/* to make sure we can check ray shadow easily in the render code */
if(lar->mode & LA_SHAD_RAY) {
if( (re->r.mode & R_RAYTRACE)==0)
lar->mode &= ~LA_SHAD_RAY;
}
/* shadfacs actually mean light, let's put them to 1 to prevent unitialized accidents */
for(c=0; c<re->r.threads; c++)
for(a=0; a<re->r.osa; a++)
for(b=0; b<4; b++)
lar->shadsamp[c].shadfac[a][b]= 1.0f;
}
return lar;
}
@ -2928,8 +2935,10 @@ void RE_Database_Free(Render *re)
for(go= re->lights.first; go; go= go->next) {
struct LampRen *lar= go->lampren;
freeshadowbuf(lar);
if(lar->jitter) MEM_freeN(lar->jitter);
if(lar->shadsamp) MEM_freeN(lar->shadsamp);
MEM_freeN(lar);
}
@ -3115,7 +3124,8 @@ static void check_non_flat_quads(Render *re)
}
}
static void add_lightgroup(Render *re, Group *group)
/* layflag: allows material group to ignore layerflag */
static void add_lightgroup(Render *re, Group *group, int nolay)
{
GroupObject *go, *gol;
@ -3131,6 +3141,8 @@ static void add_lightgroup(Render *re, Group *group)
}
if(go->lampren==NULL)
go->lampren= add_render_lamp(re, go->ob);
if(nolay)
((LampRen *)go->lampren)->lay= 0xFFFFFFFF;
}
}
}
@ -3143,7 +3155,7 @@ static void set_material_lightgroups(Render *re)
/* hola! materials not in use...? */
for(ma= G.main->mat.first; ma; ma=ma->id.next) {
if(ma->group)
add_lightgroup(re, ma->group);
add_lightgroup(re, ma->group, ma->mode & MA_GROUP_NOLAY);
}
}
@ -3153,7 +3165,7 @@ static void set_renderlayer_lightgroups(Render *re, Scene *sce)
for(srl= sce->r.layers.first; srl; srl= srl->next) {
if(srl->light_override)
add_lightgroup(re, srl->light_override);
add_lightgroup(re, srl->light_override, 0);
}
}

@ -287,14 +287,15 @@ static void halo_tile(RenderPart *pa, float *pass, unsigned int lay)
}
}
static void lamphalo_tile(RenderPart *pa, float *pass, unsigned int lay)
static void lamphalo_tile(RenderPart *pa, RenderLayer *rl)
{
ShadeInput shi;
float *pass= rl->rectf;
float fac;
long *rd= pa->rectdaps;
int x, y, *rz= pa->rectz;
shi.lay= lay;
shade_input_initialize(&shi, pa, rl, 0);
for(y=pa->disprect.ymin; y<pa->disprect.ymax; y++) {
for(x=pa->disprect.xmin; x<pa->disprect.xmax; x++, rz++, pass+=4) {
@ -321,7 +322,6 @@ static void lamphalo_tile(RenderPart *pa, float *pass, unsigned int lay)
shi.co[2]= 0.0f;
renderspothalo(&shi, pass, fac);
}
}
else {
if(R.r.mode & R_ORTHO)
@ -859,7 +859,7 @@ void zbufshadeDA_tile(RenderPart *pa)
/* lamphalo after solid, before ztra, looks nicest because ztra does own halo */
if(R.flag & R_LAMPHALO)
if(rl->layflag & SCE_LAY_HALO)
lamphalo_tile(pa, rl->rectf, rl->lay);
lamphalo_tile(pa, rl);
/* halo before ztra, because ztra fills in zbuffer now */
if(R.flag & R_HALO)
@ -1028,7 +1028,7 @@ void zbufshade_tile(RenderPart *pa)
/* lamphalo after solid, before ztra, looks nicest because ztra does own halo */
if(R.flag & R_LAMPHALO)
if(rl->layflag & SCE_LAY_HALO)
lamphalo_tile(pa, rl->rectf, rl->lay);
lamphalo_tile(pa, rl);
/* halo before ztra, because ztra fills in zbuffer now */
if(R.flag & R_HALO)
@ -1353,6 +1353,9 @@ static void do_bake_shade(void *handle, int x, int y, float u, float v)
/* no face normal flip */
shi->puno= 0;
/* cache for shadow */
shi->samplenr++;
if(bs->quad)
shade_input_set_triangle_i(shi, vlr, 0, 2, 3);
else
@ -1377,8 +1380,7 @@ static void do_bake_shade(void *handle, int x, int y, float u, float v)
shade_input_set_shade_texco(shi);
if(R.r.mode & R_SHADOW)
shade_samples_do_shadow(ssamp);
shade_samples_do_AO(ssamp);
if(shi->mat->nodetree && shi->mat->use_nodes) {
ntreeShaderExecTree(shi->mat->nodetree, shi, &shr);

@ -70,8 +70,8 @@ extern struct Render R;
- shade_input_set_uv() <- not for ray or bake
- shade_input_set_normals()
- shade_samples()
- if shadow or AO
- shade_samples_do_shadow()
- if AO
- shade_samples_do_AO()
- if shading happens
- for each sample
- shade_input_set_shade_texco()
@ -835,7 +835,7 @@ void shade_input_set_shade_texco(ShadeInput *shi)
/* initialize per part, not per pixel! */
static void shade_input_initialize(ShadeInput *shi, RenderPart *pa, RenderLayer *rl, int sample)
void shade_input_initialize(ShadeInput *shi, RenderPart *pa, RenderLayer *rl, int sample)
{
memset(shi, 0, sizeof(ShadeInput));
@ -864,59 +864,24 @@ void shade_sample_initialize(ShadeSample *ssamp, RenderPart *pa, RenderLayer *rl
shade_input_initialize(&ssamp->shi[a], pa, rl, a);
memset(&ssamp->shr[a], 0, sizeof(ShadeResult));
}
ssamp->samplenr= 0; /* counter, detect shadow-reuse for shaders */
}
/* for all lamps, for all samples, do shadow */
/* renderdata mode was checked for */
void shade_samples_do_shadow(ShadeSample *ssamp)
/* Do AO or (future) GI */
void shade_samples_do_AO(ShadeSample *ssamp)
{
GroupObject *go;
LampRen *lar;
ShadeInput *shi;
int sample;
if(ssamp->shi[0].passflag & (SCE_PASS_COMBINED|SCE_PASS_DIFFUSE|SCE_PASS_SPEC|SCE_PASS_SHADOW)) {
for(go=R.lights.first; go; go= go->next) {
lar= go->lampren;
/* if there's shadow */
if(lar->shb || (lar->mode & LA_SHAD_RAY)) {
for(sample=0, shi= ssamp->shi; sample<ssamp->tot; shi++, sample++) {
float visifac, lv[3], lampdist, inpr;
/* tests to quickly reject */
if(lar->mode & LA_LAYER) if((lar->lay & shi->vlr->lay)==0) continue;
if((lar->lay & shi->lay)==0) continue;
if(!(shi->mode & MA_SHADOW) || (shi->mode & MA_SHLESS))
continue;
if(!( (shi->combinedflag | shi->passflag) & SCE_PASS_SHADOW))
continue;
visifac= lamp_get_visibility(lar, shi->co, lv, &lampdist);
if(visifac==0.0f)
continue;
inpr= INPR(shi->vn, lv);
/* tangential faces always look at lamp */
if( (shi->mat->mode & MA_TANGENT_V) || (shi->vlr->flag & R_TANGENT) )
inpr= 1.0f - inpr*inpr;
else if(inpr <= 0.0f)
continue;
/* now we're going (1 = do it real) */
lamp_get_shadow(lar, shi, inpr, lar->shadsamp[shi->thread].shadfac[sample], 1);
}
}
}
}
if(!(R.r.mode & R_SHADOW))
return;
if(!(R.r.mode & R_RAYTRACE))
return;
/* do the AO */
if(R.wrld.mode & WO_AMB_OCC)
if(ssamp->shi[0].passflag & (SCE_PASS_COMBINED|SCE_PASS_DIFFUSE|SCE_PASS_AO))
if(ssamp->shi[0].passflag & (SCE_PASS_COMBINED|SCE_PASS_AO))
for(sample=0, shi= ssamp->shi; sample<ssamp->tot; shi++, sample++)
if(!(shi->mode & MA_SHLESS))
if(shi->mode & MA_SHADOW)
@ -924,6 +889,7 @@ void shade_samples_do_shadow(ShadeSample *ssamp)
}
static void shade_samples_fill_with_ps(ShadeSample *ssamp, PixStr *ps, int x, int y)
{
ShadeInput *shi;
@ -950,6 +916,7 @@ static void shade_samples_fill_with_ps(ShadeSample *ssamp, PixStr *ps, int x, in
shade_input_copy_triangle(shi, shi-1);
shi->mask= (1<<samp);
shi->samplenr= ssamp->samplenr++;
shade_input_set_viewco(shi, xs, ys, (float)ps->z);
shade_input_set_uv(shi);
shade_input_set_normals(shi);
@ -970,6 +937,7 @@ static void shade_samples_fill_with_ps(ShadeSample *ssamp, PixStr *ps, int x, in
ys= (float)y + 0.5f;
}
shi->mask= curmask;
shi->samplenr= ssamp->samplenr++;
shade_input_set_viewco(shi, xs, ys, (float)ps->z);
shade_input_set_uv(shi);
shade_input_set_normals(shi);
@ -994,8 +962,7 @@ int shade_samples(ShadeSample *ssamp, PixStr *ps, int x, int y)
int samp;
/* if shadow or AO? */
if(R.r.mode & R_SHADOW)
shade_samples_do_shadow(ssamp);
shade_samples_do_AO(ssamp);
/* if shade (all shadepinputs have same passflag) */
if(ssamp->shi[0].passflag & ~(SCE_PASS_Z|SCE_PASS_INDEXOB)) {

@ -59,7 +59,7 @@ static ListBase *get_lights(ShadeInput *shi)
if(shi->light_override)
return &shi->light_override->gobject;
else if(shi->mat->group)
else if(shi->mat && shi->mat->group)
return &shi->mat->group->gobject;
else
return &R.lights;
@ -1003,8 +1003,9 @@ void ambient_occlusion_to_diffuse(ShadeInput *shi, float *diff)
/* result written in shadfac */
void lamp_get_shadow(LampRen *lar, ShadeInput *shi, float inp, float *shadfac, int do_real)
{
LampShadowSubSample *lss= &(lar->shadsamp[shi->thread].s[shi->sample]);
if(do_real) {
if(do_real || lss->samplenr!=shi->samplenr) {
shadfac[0]= shadfac[1]= shadfac[2]= shadfac[3]= 1.0f;
@ -1017,10 +1018,12 @@ void lamp_get_shadow(LampRen *lar, ShadeInput *shi, float inp, float *shadfac, i
else if(lar->mode & LA_SHAD_RAY) {
ray_shadow(shi, lar, shadfac);
}
QUATCOPY(lss->shadfac, shadfac);
lss->samplenr= shi->samplenr;
}
else {
float *fp= lar->shadsamp[shi->thread].shadfac[shi->sample];
QUATCOPY(shadfac, fp);
QUATCOPY(shadfac, lss->shadfac);
}
}
@ -1455,6 +1458,7 @@ void shade_lamp_loop(ShadeInput *shi, ShadeResult *shr)
shr->diff[1]= shi->g*shi->emit;
shr->diff[2]= shi->b*shi->emit;
}
VECCOPY(shr->shad, shr->diff);
/* AO pass */
if(R.wrld.mode & WO_AMB_OCC) {
@ -1501,7 +1505,7 @@ void shade_lamp_loop(ShadeInput *shi, ShadeResult *shr)
/* exposure correction */
if(R.wrld.exp!=0.0f || R.wrld.range!=1.0f) {
wrld_exposure_correct(shr->diff);
wrld_exposure_correct(shr->combined); /* has no spec! */
wrld_exposure_correct(shr->spec);
}
}

@ -2813,9 +2813,6 @@ static int vergzvlak(const void *a1, const void *a2)
return 0;
}
/**
* Shade this face at this location in SCS.
*/
static void shade_tra_samples_fill(ShadeSample *ssamp, int x, int y, int z, int facenr, int curmask)
{
@ -2843,6 +2840,7 @@ static void shade_tra_samples_fill(ShadeSample *ssamp, int x, int y, int z, int
shi++;
}
shi->mask= (1<<samp);
shi->samplenr= ssamp->samplenr++;
shade_input_set_viewco(shi, xs, ys, (float)z);
shade_input_set_uv(shi);
shade_input_set_normals(shi);
@ -2862,6 +2860,7 @@ static void shade_tra_samples_fill(ShadeSample *ssamp, int x, int y, int z, int
ys= (float)y + 0.5f;
}
shi->mask= curmask;
shi->samplenr= ssamp->samplenr++;
shade_input_set_viewco(shi, xs, ys, (float)z);
shade_input_set_uv(shi);
shade_input_set_normals(shi);
@ -2881,9 +2880,8 @@ static int shade_tra_samples(ShadeSample *ssamp, int x, int y, int z, int facenr
ShadeResult *shr= ssamp->shr;
int samp;
/* if shadow or AO? */
if(R.r.mode & R_SHADOW)
shade_samples_do_shadow(ssamp);
/* if AO? */
shade_samples_do_AO(ssamp);
/* if shade (all shadepinputs have same passflag) */
if(shi->passflag & ~(SCE_PASS_Z|SCE_PASS_INDEXOB)) {

@ -3052,12 +3052,12 @@ static void material_panel_shading(Material *ma)
uiBlockBeginAlign(block);
uiDefButBitI(block, TOG, MA_SHADOW, B_MATPRV, "Shadow", 245,140,65,19, &(ma->mode), 0, 0, 0, 0, "Makes material receive shadows");
uiDefButBitI(block, TOG, MA_SHADOW_TRA, B_MATPRV, "TraShadow", 245,120,65,19, &(ma->mode), 0, 0, 0, 0, "Receives transparent shadows based at material color and alpha");
uiDefButBitI(block, TOG, MA_ONLYSHADOW, B_MATPRV, "OnlyShad", 245,100,65,20, &(ma->mode), 0, 0, 0, 0, "Renders shadows on material as Alpha value");
uiDefButBitI(block, TOG, MA_ONLYSHADOW, B_MATPRV, "OnlyShad", 245,100,65,20, &(ma->mode), 0, 0, 0, 0, "Renders shadows on material as Alpha value");
uiDefButBitI(block, TOG, MA_RAYBIAS, B_MATPRV, "Bias", 245,80,65,19, &(ma->mode), 0, 0, 0, 0, "Prevents ray traced shadow errors with phong interpolated normals (terminator problem)");
uiBlockEndAlign(block);
uiDefIDPoinBut(block, test_grouppoin_but, ID_GR, B_MATPRV, "GR:", 9, 55, 150, 19, &ma->group, "Limit Lighting to Lamps in this Group");
uiBlockBeginAlign(block);
uiDefIDPoinBut(block, test_grouppoin_but, ID_GR, B_MATPRV, "GR:", 9, 55, 150, 19, &ma->group, "Limit Lighting to Lamps in this Group");
uiDefButBitI(block, TOG, MA_GROUP_NOLAY, B_MATPRV, "Always", 159,55, 65,20, &(ma->mode), 0, 0, 0, 0, "Ignore visibility layers for Lamps in this Group");
}
}

@ -201,7 +201,7 @@ void add_object_draw(int type) /* for toolbox or menus, only non-editmode stuff
if(type==OB_EMPTY) BIF_undo_push("Add Empty");
else if(type==OB_LAMP) {
BIF_undo_push("Add Lamp");
if(G.vd->drawtype == OB_SHADED) reshadeall_displist();
reshadeall_displist(); /* only frees */
}
else if(type==OB_LATTICE) BIF_undo_push("Add Lattice");
else if(type==OB_CAMERA) BIF_undo_push("Add Camera");
@ -311,7 +311,7 @@ void delete_obj(int ok)
G.f &= ~(G_VERTEXPAINT+G_FACESELECT+G_TEXTUREPAINT+G_WEIGHTPAINT);
setcursor_space(SPACE_VIEW3D, CURSOR_STD);
if(islamp && G.vd->drawtype==OB_SHADED) reshadeall_displist();
if(islamp) reshadeall_displist(); /* only frees displist */
redraw_test_buttons(OBACT);
allqueue(REDRAWVIEW3D, 0);
@ -2080,7 +2080,7 @@ void movetolayer(void)
base= base->next;
}
}
if(islamp && G.vd->drawtype == OB_SHADED) reshadeall_displist();
if(islamp) reshadeall_displist(); /* only frees */
/* warning, active object may be hidden now */