/** * $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) 2006 Blender Foundation * All rights reserved. * * Contributors: Hos, Robert Wenzlaff. * * ***** END GPL LICENSE BLOCK ***** */ #include #include #include #include "MTC_matrixops.h" #include "BLI_arithb.h" #include "DNA_curve_types.h" #include "DNA_group_types.h" #include "DNA_lamp_types.h" #include "DNA_meshdata_types.h" #include "DNA_material_types.h" #include "BKE_utildefines.h" #include "BKE_node.h" /* local include */ #include "renderpipeline.h" #include "render_types.h" #include "renderdatabase.h" #include "rendercore.h" #include "shadbuf.h" #include "shading.h" #include "strand.h" #include "texture.h" #include "zbuf.h" /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ /* defined in pipeline.c, is hardcopy of active dynamic allocated Render */ /* only to be used here in this file, it's for speed */ extern struct Render R; /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ #define VECADDISFAC(v1,v3,fac) {*(v1)+= *(v3)*(fac); *(v1+1)+= *(v3+1)*(fac); *(v1+2)+= *(v3+2)*(fac);} /* Shade Sample order: - shade_samples_fill_with_ps() - for each sample - shade_input_set_triangle() <- if prev sample-face is same, use shade_input_copy_triangle() - if vlr - shade_input_set_viewco() <- not for ray or bake - shade_input_set_uv() <- not for ray or bake - shade_input_set_normals() - shade_samples() - if AO - shade_samples_do_AO() - if shading happens - for each sample - shade_input_set_shade_texco() - shade_samples_do_shade() - OSA: distribute sample result with filter masking */ /* also used as callback for nodes */ /* delivers a fully filled in ShadeResult, for all passes */ void shade_material_loop(ShadeInput *shi, ShadeResult *shr) { shade_lamp_loop(shi, shr); /* clears shr */ if(shi->translucency!=0.0f) { ShadeResult shr_t; float fac= shi->translucency; /* gotta copy it again */ memcpy(&shi->r, &shi->mat->r, 23*sizeof(float)); shi->har= shi->mat->har; VECCOPY(shi->vn, shi->vno); VECMUL(shi->vn, -1.0f); VECMUL(shi->facenor, -1.0f); shi->depth++; /* hack to get real shadow now */ shade_lamp_loop(shi, &shr_t); shi->depth--; /* a couple of passes */ VECADDISFAC(shr->combined, shr_t.combined, fac); if(shi->passflag & SCE_PASS_SPEC) VECADDISFAC(shr->spec, shr_t.spec, fac); if(shi->passflag & SCE_PASS_DIFFUSE) VECADDISFAC(shr->diff, shr_t.diff, fac); if(shi->passflag & SCE_PASS_SHADOW) VECADDISFAC(shr->shad, shr_t.shad, fac); VECMUL(shi->vn, -1.0f); VECMUL(shi->facenor, -1.0f); } /* depth >= 1 when ray-shading */ if(shi->depth==0) { if(R.r.mode & R_RAYTRACE) { if(shi->ray_mirror!=0.0f || ((shi->mat->mode & MA_RAYTRANSP) && shr->alpha!=1.0f)) { /* ray trace works on combined, but gives pass info */ ray_trace(shi, shr); } } /* disable adding of sky for raytransp */ if(shi->mat->mode & MA_RAYTRANSP) if(shi->layflag & SCE_LAY_SKY) shr->alpha= 1.0f; } } /* do a shade, finish up some passes, apply mist */ void shade_input_do_shade(ShadeInput *shi, ShadeResult *shr) { float alpha; /* ------ main shading loop -------- */ if(shi->mat->nodetree && shi->mat->use_nodes) { ntreeShaderExecTree(shi->mat->nodetree, shi, shr); } else { /* copy all relevant material vars, note, keep this synced with render_types.h */ memcpy(&shi->r, &shi->mat->r, 23*sizeof(float)); shi->har= shi->mat->har; shade_material_loop(shi, shr); } /* copy additional passes */ if(shi->passflag & (SCE_PASS_VECTOR|SCE_PASS_NORMAL|SCE_PASS_RADIO)) { QUATCOPY(shr->winspeed, shi->winspeed); VECCOPY(shr->nor, shi->vn); VECCOPY(shr->rad, shi->rad); } /* MIST */ if((shi->passflag & SCE_PASS_MIST) || ((R.wrld.mode & WO_MIST) && (shi->mat->mode & MA_NOMIST)==0)) { if(R.r.mode & R_ORTHO) shr->mist= mistfactor(-shi->co[2], shi->co); else shr->mist= mistfactor(VecLength(shi->co), shi->co); } else shr->mist= 0.0f; if((R.wrld.mode & WO_MIST) && (shi->mat->mode & MA_NOMIST)==0 ) { alpha= shr->mist; } else alpha= 1.0f; /* add mist and premul color */ if(shr->alpha!=1.0f || alpha!=1.0f) { float fac= alpha*(shr->alpha); shr->combined[3]= fac; shr->combined[0]*= fac; shr->combined[1]*= fac; shr->combined[2]*= fac; } else shr->combined[3]= 1.0f; } /* **************************************************************************** */ /* ShadeInput */ /* **************************************************************************** */ void vlr_set_uv_indices(VlakRen *vlr, int *i1, int *i2, int *i3) { /* to prevent storing new tfaces or vcols, we check a split runtime */ /* 4---3 4---3 */ /* |\ 1| or |1 /| */ /* |0\ | |/ 0| */ /* 1---2 1---2 0 = orig face, 1 = new face */ /* Update vert nums to point to correct verts of original face */ if(vlr->flag & R_DIVIDE_24) { if(vlr->flag & R_FACE_SPLIT) { (*i1)++; (*i2)++; (*i3)++; } else { (*i3)++; } } else if(vlr->flag & R_FACE_SPLIT) { (*i2)++; (*i3)++; } } static void normal_transform(float imat[][3], float *nor) { float xn, yn, zn; xn= nor[0]; yn= nor[1]; zn= nor[2]; nor[0]= imat[0][0]*xn+imat[0][1]*yn+imat[0][2]*zn; nor[1]= imat[1][0]*xn+imat[1][1]*yn+imat[1][2]*zn; nor[2]= imat[2][0]*xn+imat[2][1]*yn+imat[2][2]*zn; } /* copy data from face to ShadeInput, general case */ /* indices 0 1 2 3 only */ void shade_input_set_triangle_i(ShadeInput *shi, ObjectInstanceRen *obi, VlakRen *vlr, short i1, short i2, short i3) { VertRen **vpp= &vlr->v1; shi->vlr= vlr; shi->obi= obi; shi->obr= obi->obr; shi->v1= vpp[i1]; shi->v2= vpp[i2]; shi->v3= vpp[i3]; shi->i1= i1; shi->i2= i2; shi->i3= i3; /* note, shi->mat is set in node shaders */ shi->mat= shi->mat_override?shi->mat_override:vlr->mat; shi->osatex= (shi->mat->texco & TEXCO_OSA); shi->mode= shi->mat->mode_l; /* or-ed result for all nodes */ /* facenormal copy, can get flipped */ shi->flippednor= RE_vlakren_get_normal(&R, obi, vlr, shi->facenor); /* copy of original pre-flipped normal, for geometry->front/back node output */ VECCOPY(shi->orignor, shi->facenor); if(shi->flippednor) VECMUL(shi->orignor, -1.0f); /* calculate vertexnormals */ if(vlr->flag & R_SMOOTH) { VECCOPY(shi->n1, shi->v1->n); VECCOPY(shi->n2, shi->v2->n); VECCOPY(shi->n3, shi->v3->n); if(obi->flag & R_TRANSFORMED) { normal_transform(obi->imat, shi->n1); normal_transform(obi->imat, shi->n2); normal_transform(obi->imat, shi->n3); } if(!(vlr->flag & (R_NOPUNOFLIP|R_TANGENT))) { if(INPR(shi->facenor, shi->n1) < 0.0f) { shi->n1[0]= -shi->n1[0]; shi->n1[1]= -shi->n1[1]; shi->n1[2]= -shi->n1[2]; } if(INPR(shi->facenor, shi->n2) < 0.0f) { shi->n2[0]= -shi->n2[0]; shi->n2[1]= -shi->n2[1]; shi->n2[2]= -shi->n2[2]; } if(INPR(shi->facenor, shi->n3) < 0.0f) { shi->n3[0]= -shi->n3[0]; shi->n3[1]= -shi->n3[1]; shi->n3[2]= -shi->n3[2]; } } } } /* note, facenr declared volatile due to over-eager -O2 optimizations * on cygwin (particularly -frerun-cse-after-loop) */ /* copy data from face to ShadeInput, scanline case */ void shade_input_set_triangle(ShadeInput *shi, volatile int obi, volatile int facenr, int normal_flip) { if(facenr>0) { shi->obi= &R.objectinstance[obi]; shi->obr= shi->obi->obr; shi->facenr= (facenr-1) & RE_QUAD_MASK; if( shi->facenr < shi->obr->totvlak ) { VlakRen *vlr= RE_findOrAddVlak(shi->obr, shi->facenr); if(facenr & RE_QUAD_OFFS) shade_input_set_triangle_i(shi, shi->obi, vlr, 0, 2, 3); else shade_input_set_triangle_i(shi, shi->obi, vlr, 0, 1, 2); } else shi->vlr= NULL; /* general signal we got sky */ } else shi->vlr= NULL; /* general signal we got sky */ } /* full osa case: copy static info */ void shade_input_copy_triangle(ShadeInput *shi, ShadeInput *from) { /* not so nice, but works... warning is in RE_shader_ext.h */ memcpy(shi, from, sizeof(struct ShadeInputCopy)); } /* copy data from strand to shadeinput */ void shade_input_set_strand(ShadeInput *shi, StrandRen *strand, StrandPoint *spoint) { /* note, shi->mat is set in node shaders */ shi->mat= shi->mat_override? shi->mat_override: strand->buffer->ma; shi->osatex= (shi->mat->texco & TEXCO_OSA); shi->mode= shi->mat->mode_l; /* or-ed result for all nodes */ /* shade_input_set_viewco equivalent */ VECCOPY(shi->co, spoint->co); VECCOPY(shi->view, shi->co); Normalize(shi->view); shi->xs= (int)spoint->x; shi->ys= (int)spoint->y; if(shi->osatex || (R.r.mode & R_SHADOW)) { VECCOPY(shi->dxco, spoint->dtco); VECCOPY(shi->dyco, spoint->dsco); } /* dxview, dyview, not supported */ /* facenormal, simply viewco flipped */ VECCOPY(shi->facenor, spoint->nor); VECCOPY(shi->orignor, shi->facenor); /* shade_input_set_normals equivalent */ if(shi->mat->mode & MA_TANGENT_STR) VECCOPY(shi->vn, spoint->tan) else VECCOPY(shi->vn, spoint->nor) VECCOPY(shi->vno, shi->vn); } void shade_input_set_strand_texco(ShadeInput *shi, StrandRen *strand, StrandVert *svert, StrandPoint *spoint) { StrandBuffer *strandbuf= strand->buffer; ObjectRen *obr= strandbuf->obr; StrandVert *sv; int mode= shi->mode; /* or-ed result for all nodes */ short texco= shi->mat->texco; if((shi->mat->texco & TEXCO_REFL)) { /* shi->dxview, shi->dyview, not supported */ } if(shi->osatex && (texco & (TEXCO_NORM|TEXCO_REFL))) { /* not supported */ } if(mode & (MA_TANGENT_V|MA_NORMAP_TANG)) { VECCOPY(shi->tang, spoint->tan); } if(mode & MA_STR_SURFDIFF) { float *surfnor= RE_strandren_get_surfnor(obr, strand, 0); if(surfnor) VECCOPY(shi->surfnor, surfnor) else VECCOPY(shi->surfnor, shi->vn) if(shi->mat->strand_surfnor > 0.0f) { shi->surfdist= 0.0f; for(sv=strand->vert; sv!=svert; sv++) shi->surfdist+=VecLenf(sv->co, (sv+1)->co); shi->surfdist += 0.5f*(spoint->strandco+1.0f)*VecLenf(sv->co, (sv+1)->co); } } if(R.r.mode & R_SPEED) { float *speed; speed= RE_strandren_get_winspeed(shi->obi, strand, 0); if(speed) QUATCOPY(shi->winspeed, speed) else shi->winspeed[0]= shi->winspeed[1]= shi->winspeed[2]= shi->winspeed[3]= 0.0f; } /* shade_input_set_shade_texco equivalent */ if(texco & NEED_UV) { if(texco & TEXCO_ORCO) { VECCOPY(shi->lo, strand->orco); /* no shi->osatex, orco derivatives are zero */ } if(texco & TEXCO_GLOB) { VECCOPY(shi->gl, shi->co); MTC_Mat4MulVecfl(R.viewinv, shi->gl); if(shi->osatex) { VECCOPY(shi->dxgl, shi->dxco); MTC_Mat3MulVecfl(R.imat, shi->dxco); VECCOPY(shi->dygl, shi->dyco); MTC_Mat3MulVecfl(R.imat, shi->dyco); } } if(texco & TEXCO_STRAND) { shi->strandco= spoint->strandco; if(shi->osatex) { shi->dxstrand= spoint->dtstrandco; shi->dystrand= 0.0f; } } if((texco & TEXCO_UV) || (mode & (MA_VERTEXCOL|MA_VERTEXCOLP|MA_FACETEXTURE))) { MCol *mcol; float *uv; char *name; int i; shi->totuv= 0; shi->totcol= 0; if(mode & (MA_VERTEXCOL|MA_VERTEXCOLP)) { for (i=0; (mcol=RE_strandren_get_mcol(obr, strand, i, &name, 0)); i++) { ShadeInputCol *scol= &shi->col[i]; char *cp= (char*)mcol; shi->totcol++; scol->name= name; scol->col[0]= cp[0]/255.0f; scol->col[1]= cp[1]/255.0f; scol->col[2]= cp[2]/255.0f; } if(shi->totcol) { shi->vcol[0]= shi->col[0].col[0]; shi->vcol[1]= shi->col[0].col[1]; shi->vcol[2]= shi->col[0].col[2]; } else { shi->vcol[0]= 0.0f; shi->vcol[1]= 0.0f; shi->vcol[2]= 0.0f; } } for (i=0; (uv=RE_strandren_get_uv(obr, strand, i, &name, 0)); i++) { ShadeInputUV *suv= &shi->uv[i]; shi->totuv++; suv->name= name; if(strandbuf->overrideuv == i) { suv->uv[0]= -1.0f; suv->uv[1]= spoint->strandco; suv->uv[2]= 0.0f; } else { suv->uv[0]= -1.0f + 2.0f*uv[0]; suv->uv[1]= -1.0f + 2.0f*uv[1]; suv->uv[2]= 0.0f; /* texture.c assumes there are 3 coords */ } if(shi->osatex) { suv->dxuv[0]= 0.0f; suv->dxuv[1]= 0.0f; suv->dyuv[0]= 0.0f; suv->dyuv[1]= 0.0f; } if((mode & MA_FACETEXTURE) && i==0) { if((mode & (MA_VERTEXCOL|MA_VERTEXCOLP))==0) { shi->vcol[0]= 1.0f; shi->vcol[1]= 1.0f; shi->vcol[2]= 1.0f; } } } if(shi->totuv == 0) { ShadeInputUV *suv= &shi->uv[0]; suv->uv[0]= 0.0f; suv->uv[1]= spoint->strandco; suv->uv[2]= 0.0f; /* texture.c assumes there are 3 coords */ if(mode & MA_FACETEXTURE) { /* no tface? set at 1.0f */ shi->vcol[0]= 1.0f; shi->vcol[1]= 1.0f; shi->vcol[2]= 1.0f; } } } if(texco & TEXCO_NORM) { shi->orn[0]= -shi->vn[0]; shi->orn[1]= -shi->vn[1]; shi->orn[2]= -shi->vn[2]; } if(mode & MA_RADIO) { /* not supported */ } if(texco & TEXCO_REFL) { /* mirror reflection color textures (and envmap) */ calc_R_ref(shi); /* wrong location for normal maps! XXXXXXXXXXXXXX */ } if(texco & TEXCO_STRESS) { /* not supported */ } if(texco & TEXCO_TANGENT) { if((mode & MA_TANGENT_V)==0) { /* just prevent surprises */ shi->tang[0]= shi->tang[1]= shi->tang[2]= 0.0f; } } } shi->rad[0]= shi->rad[1]= shi->rad[2]= 0.0f; /* this only avalailable for scanline renders */ if(shi->depth==0) { if(texco & TEXCO_WINDOW) { shi->winco[0]= -1.0f + 2.0f*spoint->x/(float)R.winx; shi->winco[1]= -1.0f + 2.0f*spoint->y/(float)R.winy; shi->winco[2]= 0.0f; /* not supported */ if(shi->osatex) { shi->dxwin[0]= 0.0f; shi->dywin[1]= 0.0f; shi->dxwin[0]= 0.0f; shi->dywin[1]= 0.0f; } } if(texco & TEXCO_STICKY) { /* not supported */ } } } /* scanline pixel coordinates */ /* requires set_triangle */ void shade_input_set_viewco(ShadeInput *shi, float x, float y, float z) { float fac; /* currently in use for dithering (soft shadow), node preview, irregular shad */ shi->xs= (int)(x); shi->ys= (int)(y); calc_view_vector(shi->view, x, y); /* returns not normalized, so is in viewplane coords */ /* wire cannot use normal for calculating shi->co */ if(shi->mat->mode & MA_WIRE) { if(R.r.mode & R_ORTHO) calc_renderco_ortho(shi->co, x, y, z); else calc_renderco_zbuf(shi->co, shi->view, z); } else { float dface, v1[3]; VECCOPY(v1, shi->v1->co); if(shi->obi->flag & R_TRANSFORMED) Mat4MulVecfl(shi->obi->mat, v1); dface= v1[0]*shi->facenor[0]+v1[1]*shi->facenor[1]+v1[2]*shi->facenor[2]; /* ortho viewplane cannot intersect using view vector originating in (0,0,0) */ if(R.r.mode & R_ORTHO) { /* x and y 3d coordinate can be derived from pixel coord and winmat */ float fx= 2.0f/(R.winx*R.winmat[0][0]); float fy= 2.0f/(R.winy*R.winmat[1][1]); shi->co[0]= (x - 0.5f*R.winx)*fx - R.winmat[3][0]/R.winmat[0][0]; shi->co[1]= (y - 0.5f*R.winy)*fy - R.winmat[3][1]/R.winmat[1][1]; /* using a*x + b*y + c*z = d equation, (a b c) is normal */ if(shi->facenor[2]!=0.0f) shi->co[2]= (dface - shi->facenor[0]*shi->co[0] - shi->facenor[1]*shi->co[1])/shi->facenor[2]; else shi->co[2]= 0.0f; if(shi->osatex || (R.r.mode & R_SHADOW) ) { shi->dxco[0]= fx; shi->dxco[1]= 0.0f; if(shi->facenor[2]!=0.0f) shi->dxco[2]= (shi->facenor[0]*fx)/shi->facenor[2]; else shi->dxco[2]= 0.0f; shi->dyco[0]= 0.0f; shi->dyco[1]= fy; if(shi->facenor[2]!=0.0f) shi->dyco[2]= (shi->facenor[1]*fy)/shi->facenor[2]; else shi->dyco[2]= 0.0f; if( (shi->mat->texco & TEXCO_REFL) ) { if(shi->co[2]!=0.0f) fac= 1.0f/shi->co[2]; else fac= 0.0f; shi->dxview= -R.viewdx*fac; shi->dyview= -R.viewdy*fac; } } } else { float div; div= shi->facenor[0]*shi->view[0] + shi->facenor[1]*shi->view[1] + shi->facenor[2]*shi->view[2]; if (div!=0.0f) fac= dface/div; else fac= 0.0f; shi->co[0]= fac*shi->view[0]; shi->co[1]= fac*shi->view[1]; shi->co[2]= fac*shi->view[2]; /* pixel dx/dy for render coord */ if(shi->osatex || (R.r.mode & R_SHADOW) ) { float u= dface/(div - R.viewdx*shi->facenor[0]); float v= dface/(div - R.viewdy*shi->facenor[1]); shi->dxco[0]= shi->co[0]- (shi->view[0]-R.viewdx)*u; shi->dxco[1]= shi->co[1]- (shi->view[1])*u; shi->dxco[2]= shi->co[2]- (shi->view[2])*u; shi->dyco[0]= shi->co[0]- (shi->view[0])*v; shi->dyco[1]= shi->co[1]- (shi->view[1]-R.viewdy)*v; shi->dyco[2]= shi->co[2]- (shi->view[2])*v; if( (shi->mat->texco & TEXCO_REFL) ) { if(fac!=0.0f) fac= 1.0f/fac; shi->dxview= -R.viewdx*fac; shi->dyview= -R.viewdy*fac; } } } } /* cannot normalize earlier, code above needs it at viewplane level */ Normalize(shi->view); } /* calculate U and V, for scanline (silly render face u and v are in range -1 to 0) */ void shade_input_set_uv(ShadeInput *shi) { VlakRen *vlr= shi->vlr; if((vlr->flag & R_SMOOTH) || (shi->mat->texco & NEED_UV) || (shi->passflag & SCE_PASS_UV)) { float v1[3], v2[3], v3[3]; VECCOPY(v1, shi->v1->co); VECCOPY(v2, shi->v2->co); VECCOPY(v3, shi->v3->co); if(shi->obi->flag & R_TRANSFORMED) { Mat4MulVecfl(shi->obi->mat, v1); Mat4MulVecfl(shi->obi->mat, v2); Mat4MulVecfl(shi->obi->mat, v3); } /* exception case for wire render of edge */ if(vlr->v2==vlr->v3) { float lend, lenc; lend= VecLenf(v2, v1); lenc= VecLenf(shi->co, v1); if(lend==0.0f) { shi->u=shi->v= 0.0f; } else { shi->u= - (1.0f - lenc/lend); shi->v= 0.0f; } if(shi->osatex) { shi->dx_u= 0.0f; shi->dx_v= 0.0f; shi->dy_u= 0.0f; shi->dy_v= 0.0f; } } else { /* most of this could become re-used for faces */ float detsh, t00, t10, t01, t11, xn, yn, zn; int axis1, axis2; /* find most stable axis to project */ xn= fabs(shi->facenor[0]); yn= fabs(shi->facenor[1]); zn= fabs(shi->facenor[2]); if(zn>=xn && zn>=yn) { axis1= 0; axis2= 1; } else if(yn>=xn && yn>=zn) { axis1= 0; axis2= 2; } else { axis1= 1; axis2= 2; } /* compute u,v and derivatives */ t00= v3[axis1]-v1[axis1]; t01= v3[axis2]-v1[axis2]; t10= v3[axis1]-v2[axis1]; t11= v3[axis2]-v2[axis2]; detsh= 1.0f/(t00*t11-t10*t01); t00*= detsh; t01*=detsh; t10*=detsh; t11*=detsh; shi->u= (shi->co[axis1]-v3[axis1])*t11-(shi->co[axis2]-v3[axis2])*t10; shi->v= (shi->co[axis2]-v3[axis2])*t00-(shi->co[axis1]-v3[axis1])*t01; if(shi->osatex) { shi->dx_u= shi->dxco[axis1]*t11- shi->dxco[axis2]*t10; shi->dx_v= shi->dxco[axis2]*t00- shi->dxco[axis1]*t01; shi->dy_u= shi->dyco[axis1]*t11- shi->dyco[axis2]*t10; shi->dy_v= shi->dyco[axis2]*t00- shi->dyco[axis1]*t01; } /* u and v are in range -1 to 0, we allow a little bit extra but not too much, screws up speedvectors */ CLAMP(shi->u, -2.0f, 1.0f); CLAMP(shi->v, -2.0f, 1.0f); } } } void shade_input_set_normals(ShadeInput *shi) { float u= shi->u, v= shi->v; float l= 1.0f+u+v; /* calculate vertexnormals */ if(shi->vlr->flag & R_SMOOTH) { float *n1= shi->n1, *n2= shi->n2, *n3= shi->n3; shi->vn[0]= l*n3[0]-u*n1[0]-v*n2[0]; shi->vn[1]= l*n3[1]-u*n1[1]-v*n2[1]; shi->vn[2]= l*n3[2]-u*n1[2]-v*n2[2]; Normalize(shi->vn); } else VECCOPY(shi->vn, shi->facenor); /* used in nodes */ VECCOPY(shi->vno, shi->vn); } /* use by raytrace, sss, bake to flip into the right direction */ void shade_input_flip_normals(ShadeInput *shi) { shi->facenor[0]= -shi->facenor[0]; shi->facenor[1]= -shi->facenor[1]; shi->facenor[2]= -shi->facenor[2]; shi->vn[0]= -shi->vn[0]; shi->vn[1]= -shi->vn[1]; shi->vn[2]= -shi->vn[2]; shi->vno[0]= -shi->vno[0]; shi->vno[1]= -shi->vno[1]; shi->vno[2]= -shi->vno[2]; shi->flippednor= !shi->flippednor; } void shade_input_set_shade_texco(ShadeInput *shi) { ObjectInstanceRen *obi= shi->obi; ObjectRen *obr= shi->obr; VertRen *v1= shi->v1, *v2= shi->v2, *v3= shi->v3; float u= shi->u, v= shi->v; float l= 1.0f+u+v, dl; int mode= shi->mode; /* or-ed result for all nodes */ short texco= shi->mat->texco; /* calculate dxno and tangents */ if(shi->vlr->flag & R_SMOOTH) { if(shi->osatex && (texco & (TEXCO_NORM|TEXCO_REFL)) ) { float *n1= shi->n1, *n2= shi->n2, *n3= shi->n3; dl= shi->dx_u+shi->dx_v; shi->dxno[0]= dl*n3[0]-shi->dx_u*n1[0]-shi->dx_v*n2[0]; shi->dxno[1]= dl*n3[1]-shi->dx_u*n1[1]-shi->dx_v*n2[1]; shi->dxno[2]= dl*n3[2]-shi->dx_u*n1[2]-shi->dx_v*n2[2]; dl= shi->dy_u+shi->dy_v; shi->dyno[0]= dl*n3[0]-shi->dy_u*n1[0]-shi->dy_v*n2[0]; shi->dyno[1]= dl*n3[1]-shi->dy_u*n1[1]-shi->dy_v*n2[1]; shi->dyno[2]= dl*n3[2]-shi->dy_u*n1[2]-shi->dy_v*n2[2]; } /* qdn: normalmap tangent space */ if (mode & (MA_TANGENT_V|MA_NORMAP_TANG) || R.flag & R_NEED_TANGENT) { float *s1, *s2, *s3; s1= RE_vertren_get_tangent(obr, v1, 0); s2= RE_vertren_get_tangent(obr, v2, 0); s3= RE_vertren_get_tangent(obr, v3, 0); if(s1 && s2 && s3) { shi->tang[0]= (l*s3[0] - u*s1[0] - v*s2[0]); shi->tang[1]= (l*s3[1] - u*s1[1] - v*s2[1]); shi->tang[2]= (l*s3[2] - u*s1[2] - v*s2[2]); if(obi->flag & R_TRANSFORMED) normal_transform(obi->imat, shi->tang); /* qdn: normalize just in case */ Normalize(shi->tang); } else shi->tang[0]= shi->tang[1]= shi->tang[2]= 0.0f; } } else { /* qdn: normalmap tangent space */ if (mode & (MA_TANGENT_V|MA_NORMAP_TANG) || R.flag & R_NEED_TANGENT) { /* qdn: flat faces have tangents too, could pick either one, using average here */ float *s1 = RE_vertren_get_tangent(obr, v1, 0); float *s2 = RE_vertren_get_tangent(obr, v2, 0); float *s3 = RE_vertren_get_tangent(obr, v3, 0); if (s1 && s2 && s3) { shi->tang[0] = (s1[0] + s2[0] + s3[0]); shi->tang[1] = (s1[1] + s2[1] + s3[1]); shi->tang[2] = (s1[2] + s2[2] + s3[2]); if(obi->flag & R_TRANSFORMED) normal_transform(obi->imat, shi->tang); Normalize(shi->tang); } else shi->tang[0]= shi->tang[1]= shi->tang[2]= 0.0f; } } if(mode & MA_STR_SURFDIFF) { float *surfnor= RE_vlakren_get_surfnor(obr, shi->vlr, 0); if(surfnor) { VECCOPY(shi->surfnor, surfnor) if(obi->flag & R_TRANSFORMED) normal_transform(obi->imat, shi->surfnor); } else VECCOPY(shi->surfnor, shi->vn) shi->surfdist= 0.0f; } if(R.r.mode & R_SPEED) { float *s1, *s2, *s3; s1= RE_vertren_get_winspeed(obi, v1, 0); s2= RE_vertren_get_winspeed(obi, v2, 0); s3= RE_vertren_get_winspeed(obi, v3, 0); if(s1 && s2 && s3) { shi->winspeed[0]= (l*s3[0] - u*s1[0] - v*s2[0]); shi->winspeed[1]= (l*s3[1] - u*s1[1] - v*s2[1]); shi->winspeed[2]= (l*s3[2] - u*s1[2] - v*s2[2]); shi->winspeed[3]= (l*s3[3] - u*s1[3] - v*s2[3]); } else { shi->winspeed[0]= shi->winspeed[1]= shi->winspeed[2]= shi->winspeed[3]= 0.0f; } } /* pass option forces UV calc */ if(shi->passflag & SCE_PASS_UV) texco |= (NEED_UV|TEXCO_UV); /* texture coordinates. shi->dxuv shi->dyuv have been set */ if(texco & NEED_UV) { if(texco & TEXCO_ORCO) { if(v1->orco) { float *o1, *o2, *o3; o1= v1->orco; o2= v2->orco; o3= v3->orco; shi->lo[0]= l*o3[0]-u*o1[0]-v*o2[0]; shi->lo[1]= l*o3[1]-u*o1[1]-v*o2[1]; shi->lo[2]= l*o3[2]-u*o1[2]-v*o2[2]; if(shi->osatex) { dl= shi->dx_u+shi->dx_v; shi->dxlo[0]= dl*o3[0]-shi->dx_u*o1[0]-shi->dx_v*o2[0]; shi->dxlo[1]= dl*o3[1]-shi->dx_u*o1[1]-shi->dx_v*o2[1]; shi->dxlo[2]= dl*o3[2]-shi->dx_u*o1[2]-shi->dx_v*o2[2]; dl= shi->dy_u+shi->dy_v; shi->dylo[0]= dl*o3[0]-shi->dy_u*o1[0]-shi->dy_v*o2[0]; shi->dylo[1]= dl*o3[1]-shi->dy_u*o1[1]-shi->dy_v*o2[1]; shi->dylo[2]= dl*o3[2]-shi->dy_u*o1[2]-shi->dy_v*o2[2]; } } VECCOPY(shi->duplilo, obi->dupliorco); } if(texco & TEXCO_GLOB) { VECCOPY(shi->gl, shi->co); MTC_Mat4MulVecfl(R.viewinv, shi->gl); if(shi->osatex) { VECCOPY(shi->dxgl, shi->dxco); MTC_Mat3MulVecfl(R.imat, shi->dxco); VECCOPY(shi->dygl, shi->dyco); MTC_Mat3MulVecfl(R.imat, shi->dyco); } } if(texco & TEXCO_STRAND) { 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; dl= shi->dy_u+shi->dy_v; shi->dystrand= dl*v3->accum-shi->dy_u*v1->accum-shi->dy_v*v2->accum; } } if((texco & TEXCO_UV) || (mode & (MA_VERTEXCOL|MA_VERTEXCOLP|MA_FACETEXTURE))) { VlakRen *vlr= shi->vlr; MTFace *tface; MCol *mcol; char *name; int i, j1=shi->i1, j2=shi->i2, j3=shi->i3; /* uv and vcols are not copied on split, so set them according vlr divide flag */ vlr_set_uv_indices(vlr, &j1, &j2, &j3); shi->totuv= 0; shi->totcol= 0; shi->actuv= obr->actmtface; shi->actcol= obr->actmcol; if(mode & (MA_VERTEXCOL|MA_VERTEXCOLP)) { for (i=0; (mcol=RE_vlakren_get_mcol(obr, vlr, i, &name, 0)); i++) { ShadeInputCol *scol= &shi->col[i]; char *cp1, *cp2, *cp3; shi->totcol++; scol->name= name; cp1= (char *)(mcol+j1); cp2= (char *)(mcol+j2); cp3= (char *)(mcol+j3); scol->col[0]= (l*((float)cp3[3]) - u*((float)cp1[3]) - v*((float)cp2[3]))/255.0f; scol->col[1]= (l*((float)cp3[2]) - u*((float)cp1[2]) - v*((float)cp2[2]))/255.0f; scol->col[2]= (l*((float)cp3[1]) - u*((float)cp1[1]) - v*((float)cp2[1]))/255.0f; } if(shi->totcol) { shi->vcol[0]= shi->col[0].col[0]; shi->vcol[1]= shi->col[0].col[1]; shi->vcol[2]= shi->col[0].col[2]; shi->vcol[3]= 1.0f; } else { shi->vcol[0]= 0.0f; shi->vcol[1]= 0.0f; shi->vcol[2]= 0.0f; shi->vcol[3]= 1.0f; } } for (i=0; (tface=RE_vlakren_get_tface(obr, vlr, i, &name, 0)); i++) { ShadeInputUV *suv= &shi->uv[i]; float *uv1, *uv2, *uv3; shi->totuv++; suv->name= name; uv1= tface->uv[j1]; uv2= tface->uv[j2]; uv3= tface->uv[j3]; suv->uv[0]= -1.0f + 2.0f*(l*uv3[0]-u*uv1[0]-v*uv2[0]); suv->uv[1]= -1.0f + 2.0f*(l*uv3[1]-u*uv1[1]-v*uv2[1]); suv->uv[2]= 0.0f; /* texture.c assumes there are 3 coords */ if(shi->osatex) { float duv[2]; dl= shi->dx_u+shi->dx_v; duv[0]= shi->dx_u; duv[1]= shi->dx_v; suv->dxuv[0]= 2.0f*(dl*uv3[0]-duv[0]*uv1[0]-duv[1]*uv2[0]); suv->dxuv[1]= 2.0f*(dl*uv3[1]-duv[0]*uv1[1]-duv[1]*uv2[1]); dl= shi->dy_u+shi->dy_v; duv[0]= shi->dy_u; duv[1]= shi->dy_v; suv->dyuv[0]= 2.0f*(dl*uv3[0]-duv[0]*uv1[0]-duv[1]*uv2[0]); suv->dyuv[1]= 2.0f*(dl*uv3[1]-duv[0]*uv1[1]-duv[1]*uv2[1]); } if((mode & MA_FACETEXTURE) && i==obr->actmtface) { if((mode & (MA_VERTEXCOL|MA_VERTEXCOLP))==0) { shi->vcol[0]= 1.0f; shi->vcol[1]= 1.0f; shi->vcol[2]= 1.0f; shi->vcol[3]= 1.0f; } if(tface && tface->tpage) render_realtime_texture(shi, tface->tpage); } } shi->dupliuv[0]= -1.0f + 2.0f*obi->dupliuv[0]; shi->dupliuv[1]= -1.0f + 2.0f*obi->dupliuv[1]; shi->dupliuv[2]= 0.0f; if(shi->totuv == 0) { ShadeInputUV *suv= &shi->uv[0]; suv->uv[0]= 2.0f*(u+.5f); suv->uv[1]= 2.0f*(v+.5f); suv->uv[2]= 0.0f; /* texture.c assumes there are 3 coords */ if(mode & MA_FACETEXTURE) { /* no tface? set at 1.0f */ shi->vcol[0]= 1.0f; shi->vcol[1]= 1.0f; shi->vcol[2]= 1.0f; shi->vcol[3]= 1.0f; } } } if(texco & TEXCO_NORM) { shi->orn[0]= -shi->vn[0]; shi->orn[1]= -shi->vn[1]; shi->orn[2]= -shi->vn[2]; } if(mode & MA_RADIO) { float *r1, *r2, *r3; r1= RE_vertren_get_rad(obr, v1, 0); r2= RE_vertren_get_rad(obr, v2, 0); r3= RE_vertren_get_rad(obr, v3, 0); if(r1 && r2 && r3) { shi->rad[0]= (l*r3[0] - u*r1[0] - v*r2[0]); shi->rad[1]= (l*r3[1] - u*r1[1] - v*r2[1]); shi->rad[2]= (l*r3[2] - u*r1[2] - v*r2[2]); } else shi->rad[0]= shi->rad[1]= shi->rad[2]= 0.0f; } else shi->rad[0]= shi->rad[1]= shi->rad[2]= 0.0f; if(texco & TEXCO_REFL) { /* mirror reflection color textures (and envmap) */ calc_R_ref(shi); /* wrong location for normal maps! XXXXXXXXXXXXXX */ } if(texco & TEXCO_STRESS) { float *s1, *s2, *s3; s1= RE_vertren_get_stress(obr, v1, 0); s2= RE_vertren_get_stress(obr, v2, 0); s3= RE_vertren_get_stress(obr, v3, 0); if(s1 && s2 && s3) { shi->stress= l*s3[0] - u*s1[0] - v*s2[0]; if(shi->stress<1.0f) shi->stress-= 1.0f; else shi->stress= (shi->stress-1.0f)/shi->stress; } else shi->stress= 0.0f; } if(texco & TEXCO_TANGENT) { if((mode & MA_TANGENT_V)==0) { /* just prevent surprises */ shi->tang[0]= shi->tang[1]= shi->tang[2]= 0.0f; } } } else shi->rad[0]= shi->rad[1]= shi->rad[2]= 0.0f; /* this only avalailable for scanline renders */ if(shi->depth==0) { float x= shi->xs; float y= shi->ys; if(texco & TEXCO_WINDOW) { shi->winco[0]= -1.0f + 2.0f*x/(float)R.winx; shi->winco[1]= -1.0f + 2.0f*y/(float)R.winy; shi->winco[2]= 0.0f; if(shi->osatex) { shi->dxwin[0]= 2.0f/(float)R.winx; shi->dywin[1]= 2.0f/(float)R.winy; shi->dxwin[1]= shi->dxwin[2]= 0.0f; shi->dywin[0]= shi->dywin[2]= 0.0f; } } if(texco & TEXCO_STICKY) { float *s1, *s2, *s3; s1= RE_vertren_get_sticky(obr, v1, 0); s2= RE_vertren_get_sticky(obr, v2, 0); s3= RE_vertren_get_sticky(obr, v3, 0); if(s1 && s2 && s3) { float winmat[4][4], ho1[4], ho2[4], ho3[4]; float Zmulx, Zmuly; float hox, hoy, l, dl, u, v; float s00, s01, s10, s11, detsh; /* old globals, localized now */ Zmulx= ((float)R.winx)/2.0f; Zmuly= ((float)R.winy)/2.0f; if(shi->obi->flag & R_TRANSFORMED) zbuf_make_winmat(&R, shi->obi->mat, winmat); else zbuf_make_winmat(&R, NULL, winmat); zbuf_render_project(winmat, v1->co, ho1); zbuf_render_project(winmat, v2->co, ho2); zbuf_render_project(winmat, v3->co, ho3); s00= ho3[0]/ho3[3] - ho1[0]/ho1[3]; s01= ho3[1]/ho3[3] - ho1[1]/ho1[3]; s10= ho3[0]/ho3[3] - ho2[0]/ho2[3]; s11= ho3[1]/ho3[3] - ho2[1]/ho2[3]; detsh= s00*s11-s10*s01; s00/= detsh; s01/=detsh; s10/=detsh; s11/=detsh; /* recalc u and v again */ hox= x/Zmulx -1.0f; hoy= y/Zmuly -1.0f; u= (hox - ho3[0]/ho3[3])*s11 - (hoy - ho3[1]/ho3[3])*s10; v= (hoy - ho3[1]/ho3[3])*s00 - (hox - ho3[0]/ho3[3])*s01; l= 1.0f+u+v; shi->sticky[0]= l*s3[0]-u*s1[0]-v*s2[0]; shi->sticky[1]= l*s3[1]-u*s1[1]-v*s2[1]; shi->sticky[2]= 0.0f; if(shi->osatex) { float dxuv[2], dyuv[2]; dxuv[0]= s11/Zmulx; dxuv[1]= - s01/Zmulx; dyuv[0]= - s10/Zmuly; dyuv[1]= s00/Zmuly; dl= dxuv[0] + dxuv[1]; shi->dxsticky[0]= dl*s3[0] - dxuv[0]*s1[0] - dxuv[1]*s2[0]; shi->dxsticky[1]= dl*s3[1] - dxuv[0]*s1[1] - dxuv[1]*s2[1]; dl= dyuv[0] + dyuv[1]; shi->dysticky[0]= dl*s3[0] - dyuv[0]*s1[0] - dyuv[1]*s2[0]; shi->dysticky[1]= dl*s3[1] - dyuv[0]*s1[1] - dyuv[1]*s2[1]; } } } } /* else { Note! For raytracing winco is not set, important because thus means all shader input's need to have their variables set to zero else in-initialized values are used */ } /* ****************** ShadeSample ************************************** */ /* initialize per part, not per pixel! */ void shade_input_initialize(ShadeInput *shi, RenderPart *pa, RenderLayer *rl, int sample) { memset(shi, 0, sizeof(ShadeInput)); shi->sample= sample; shi->thread= pa->thread; shi->do_preview= R.r.scemode & R_NODE_PREVIEW; shi->lay= rl->lay; shi->layflag= rl->layflag; shi->passflag= rl->passflag; shi->combinedflag= ~rl->pass_xor; shi->mat_override= rl->mat_override; shi->light_override= rl->light_override; /* note shi.depth==0 means first hit, not raytracing */ } /* initialize per part, not per pixel! */ void shade_sample_initialize(ShadeSample *ssamp, RenderPart *pa, RenderLayer *rl) { int a, tot; tot= R.osa==0?1:R.osa; for(a=0; ashi[a], pa, rl, a); memset(&ssamp->shr[a], 0, sizeof(ShadeResult)); } ssamp->samplenr= 0; /* counter, detect shadow-reuse for shaders */ } /* Do AO or (future) GI */ void shade_samples_do_AO(ShadeSample *ssamp) { ShadeInput *shi; int sample; if(!(R.r.mode & R_SHADOW)) return; if(!(R.r.mode & R_RAYTRACE) && !(R.wrld.ao_gather_method == WO_AOGATHER_APPROX)) return; if(R.wrld.mode & WO_AMB_OCC) if(ssamp->shi[0].passflag & (SCE_PASS_COMBINED|SCE_PASS_AO)) for(sample=0, shi= ssamp->shi; sampletot; shi++, sample++) if(!(shi->mode & MA_SHLESS)) ambient_occlusion(shi); /* stores in shi->ao[] */ } void shade_samples_fill_with_ps(ShadeSample *ssamp, PixStr *ps, int x, int y) { ShadeInput *shi; float xs, ys; ssamp->tot= 0; for(shi= ssamp->shi; ps; ps= ps->next) { shade_input_set_triangle(shi, ps->obi, ps->facenr, 1); if(shi->vlr) { /* NULL happens for env material or for 'all z' */ unsigned short curmask= ps->mask; /* full osa is only set for OSA renders */ if(shi->vlr->flag & R_FULL_OSA) { short shi_cp= 0, samp; for(samp=0; sampmask= (1<samplenr= ssamp->samplenr++; shade_input_set_viewco(shi, xs, ys, (float)ps->z); shade_input_set_uv(shi); shade_input_set_normals(shi); shi_cp= 1; shi++; } } } else { if(R.osa) { short b= R.samples->centmask[curmask]; xs= (float)x + R.samples->centLut[b & 15] + 0.5f; ys= (float)y + R.samples->centLut[b>>4] + 0.5f; } else { xs= (float)x + 0.5f; 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); shi++; } /* total sample amount, shi->sample is static set in initialize */ if(shi!=ssamp->shi) ssamp->tot= (shi-1)->sample + 1; } } } /* shades samples, returns true if anything happened */ int shade_samples(ShadeSample *ssamp, PixStr *ps, int x, int y) { shade_samples_fill_with_ps(ssamp, ps, x, y); if(ssamp->tot) { ShadeInput *shi= ssamp->shi; ShadeResult *shr= ssamp->shr; int samp; /* if shadow or AO? */ shade_samples_do_AO(ssamp); /* if shade (all shadepinputs have same passflag) */ if(ssamp->shi[0].passflag & ~(SCE_PASS_Z|SCE_PASS_INDEXOB)) { for(samp=0; samptot; samp++, shi++, shr++) { shade_input_set_shade_texco(shi); shade_input_do_shade(shi, shr); } } return 1; } return 0; }