diff options
-rw-r--r-- | source/blender/blenkernel/BKE_mesh.h | 2 | ||||
-rw-r--r-- | source/blender/blenkernel/intern/subsurf_ccg.c | 2 | ||||
-rw-r--r-- | source/blender/render/extern/include/RE_shader_ext.h | 2 | ||||
-rw-r--r-- | source/blender/render/intern/include/renderdatabase.h | 2 | ||||
-rw-r--r-- | source/blender/render/intern/source/convertblender.c | 171 | ||||
-rw-r--r-- | source/blender/render/intern/source/rendercore.c | 6 | ||||
-rw-r--r-- | source/blender/render/intern/source/renderdatabase.c | 28 | ||||
-rw-r--r-- | source/blender/render/intern/source/shadeinput.c | 80 | ||||
-rw-r--r-- | source/blender/render/intern/source/texture.c | 8 |
9 files changed, 230 insertions, 71 deletions
diff --git a/source/blender/blenkernel/BKE_mesh.h b/source/blender/blenkernel/BKE_mesh.h index af531a0d50c..34d533cc98d 100644 --- a/source/blender/blenkernel/BKE_mesh.h +++ b/source/blender/blenkernel/BKE_mesh.h @@ -96,6 +96,8 @@ float (*mesh_getRefKeyCos(struct Mesh *me, int *numVerts_r))[3]; /* UvVertMap */ +#define STD_UV_CONNECT_LIMIT 0.0001f + typedef struct UvVertMap { struct UvMapVert **vert; struct UvMapVert *buf; diff --git a/source/blender/blenkernel/intern/subsurf_ccg.c b/source/blender/blenkernel/intern/subsurf_ccg.c index 0108c7a14bb..7a0c47237e7 100644 --- a/source/blender/blenkernel/intern/subsurf_ccg.c +++ b/source/blender/blenkernel/intern/subsurf_ccg.c @@ -241,7 +241,7 @@ static int ss_sync_from_uv(CCGSubSurf *ss, CCGSubSurf *origss, DerivedMesh *dm, EdgeHash *ehash; float creaseFactor = (float)ccgSubSurf_getSubdivisionLevels(ss); - limit[0]= limit[1]= 0.0001f; + limit[0]= limit[1]= STD_UV_CONNECT_LIMIT; vmap= make_uv_vert_map(mface, tface, totface, totvert, 0, limit); if (!vmap) return 0; diff --git a/source/blender/render/extern/include/RE_shader_ext.h b/source/blender/render/extern/include/RE_shader_ext.h index 8e3d60d4d80..e8403053e0b 100644 --- a/source/blender/render/extern/include/RE_shader_ext.h +++ b/source/blender/render/extern/include/RE_shader_ext.h @@ -134,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 strandco, tang[3], stress, winspeed[4]; + float strandco, tang[3], nmaptang[3], stress, winspeed[4]; float duplilo[3], dupliuv[3]; ShadeInputUV uv[8]; /* 8 = MAX_MTFACE */ diff --git a/source/blender/render/intern/include/renderdatabase.h b/source/blender/render/intern/include/renderdatabase.h index a204aa7876b..7576be6e0e6 100644 --- a/source/blender/render/intern/include/renderdatabase.h +++ b/source/blender/render/intern/include/renderdatabase.h @@ -64,6 +64,7 @@ typedef struct VlakTableNode { struct MCol *mcol; int totmtface, totmcol; float *surfnor; + float *tangent; struct RadFace **radface; } VlakTableNode; @@ -112,6 +113,7 @@ float *RE_vertren_get_winspeed(struct ObjectInstanceRen *obi, struct VertRen *ve struct MTFace *RE_vlakren_get_tface(struct ObjectRen *obr, VlakRen *ren, int n, char **name, int verify); struct MCol *RE_vlakren_get_mcol(struct ObjectRen *obr, VlakRen *ren, int n, char **name, int verify); float *RE_vlakren_get_surfnor(struct ObjectRen *obr, VlakRen *ren, int verify); +float *RE_vlakren_get_nmap_tangent(struct ObjectRen *obr, VlakRen *ren, int verify); RadFace **RE_vlakren_get_radface(struct ObjectRen *obr, VlakRen *ren, int verify); int RE_vlakren_get_normal(struct Render *re, struct ObjectInstanceRen *obi, struct VlakRen *vlr, float *nor); diff --git a/source/blender/render/intern/source/convertblender.c b/source/blender/render/intern/source/convertblender.c index 692ab871a19..40ee4b5d747 100644 --- a/source/blender/render/intern/source/convertblender.c +++ b/source/blender/render/intern/source/convertblender.c @@ -477,8 +477,53 @@ void tangent_from_uv(float *uv1, float *uv2, float *uv3, float *co1, float *co2, VecMulf(tang, -1.0f); } +/* For normal map tangents we need to detect uv boundaries, and only average + * tangents in case the uvs are connected. Alternative would be to store 1 + * tangent per face rather than 4 per face vertex, but that's not compatible + * with games */ + +typedef struct VertexTangent { + float tang[3], uv[2]; + struct VertexTangent *next; +} VertexTangent; + +static void sum_or_add_vertex_tangent(MemArena *arena, VertexTangent **vtang, float *tang, float *uv) +{ + VertexTangent *vt; + + /* find a tangent with connected uvs */ + for(vt= *vtang; vt; vt=vt->next) { + if(fabs(uv[0]-vt->uv[0]) < STD_UV_CONNECT_LIMIT && fabs(uv[1]-vt->uv[1]) < STD_UV_CONNECT_LIMIT) { + VECADD(vt->tang, vt->tang, tang); + return; + } + } + + /* if not found, append a new one */ + vt= BLI_memarena_alloc(arena, sizeof(VertexTangent)); + VECCOPY(vt->tang, tang); + vt->uv[0]= uv[0]; + vt->uv[1]= uv[1]; + + if(*vtang) + vt->next= *vtang; + *vtang= vt; +} + +static float *find_vertex_tangent(VertexTangent *vtang, float *uv) +{ + VertexTangent *vt; + static float nulltang[3] = {0.0f, 0.0f, 0.0f}; + + for(vt= vtang; vt; vt=vt->next) + if(fabs(uv[0]-vt->uv[0]) < STD_UV_CONNECT_LIMIT && fabs(uv[1]-vt->uv[1]) < STD_UV_CONNECT_LIMIT) + return vt->tang; + + return nulltang; /* shouldn't happen, except for nan or so */ +} + /* gets tangent from tface or orco */ -static void calc_tangent_vector(ObjectRen *obr, VlakRen *vlr) +static void calc_tangent_vector(ObjectRen *obr, VertexTangent **vtangents, MemArena *arena, VlakRen *vlr, int do_nmap_tangent, int do_tangent) { MTFace *tface= RE_vlakren_get_tface(obr, vlr, obr->actmtface, NULL, 0); VertRen *v1=vlr->v1, *v2=vlr->v2, *v3=vlr->v3, *v4=vlr->v4; @@ -504,30 +549,55 @@ static void calc_tangent_vector(ObjectRen *obr, VlakRen *vlr) tangent_from_uv(uv1, uv2, uv3, v1->co, v2->co, v3->co, vlr->n, tang); - tav= RE_vertren_get_tangent(obr, v1, 1); - VECADD(tav, tav, tang); - tav= RE_vertren_get_tangent(obr, v2, 1); - VECADD(tav, tav, tang); - tav= RE_vertren_get_tangent(obr, v3, 1); - VECADD(tav, tav, tang); - - if(v4) { - tangent_from_uv(uv1, uv3, uv4, v1->co, v3->co, v4->co, vlr->n, tang); - + if(do_tangent) { tav= RE_vertren_get_tangent(obr, v1, 1); VECADD(tav, tav, tang); - tav= RE_vertren_get_tangent(obr, v3, 1); + tav= RE_vertren_get_tangent(obr, v2, 1); VECADD(tav, tav, tang); - tav= RE_vertren_get_tangent(obr, v4, 1); + tav= RE_vertren_get_tangent(obr, v3, 1); VECADD(tav, tav, tang); } + + if(do_nmap_tangent) { + sum_or_add_vertex_tangent(arena, &vtangents[v1->index], tang, uv1); + sum_or_add_vertex_tangent(arena, &vtangents[v2->index], tang, uv2); + sum_or_add_vertex_tangent(arena, &vtangents[v3->index], tang, uv3); + } + + if(v4) { + tangent_from_uv(uv1, uv3, uv4, v1->co, v3->co, v4->co, vlr->n, tang); + + if(do_tangent) { + tav= RE_vertren_get_tangent(obr, v1, 1); + VECADD(tav, tav, tang); + tav= RE_vertren_get_tangent(obr, v3, 1); + VECADD(tav, tav, tang); + tav= RE_vertren_get_tangent(obr, v4, 1); + VECADD(tav, tav, tang); + } + + if(do_nmap_tangent) { + sum_or_add_vertex_tangent(arena, &vtangents[v1->index], tang, uv1); + sum_or_add_vertex_tangent(arena, &vtangents[v3->index], tang, uv3); + sum_or_add_vertex_tangent(arena, &vtangents[v4->index], tang, uv4); + } + } } -static void calc_vertexnormals(Render *re, ObjectRen *obr, int do_tangent) +static void calc_vertexnormals(Render *re, ObjectRen *obr, int do_tangent, int do_nmap_tangent) { + MemArena *arena= NULL; + VertexTangent **vtangents= NULL; int a; + if(do_nmap_tangent) { + arena= BLI_memarena_new(BLI_MEMARENA_STD_BUFSIZE); + BLI_memarena_use_calloc(arena); + + vtangents= MEM_callocN(sizeof(VertexTangent*)*obr->totvert, "VertexTangent"); + } + /* clear all vertex normals */ for(a=0; a<obr->totvert; a++) { VertRen *ver= RE_findOrAddVert(obr, a); @@ -600,10 +670,10 @@ static void calc_vertexnormals(Render *re, ObjectRen *obr, int do_tangent) v3->n[2] +=fac3*vlr->n[2]; } - if(do_tangent) { + if(do_nmap_tangent || do_tangent) { /* tangents still need to be calculated for flat faces too */ /* weighting removed, they are not vertexnormals */ - calc_tangent_vector(obr, vlr); + calc_tangent_vector(obr, vtangents, arena, vlr, do_nmap_tangent, do_tangent); } } @@ -622,6 +692,30 @@ static void calc_vertexnormals(Render *re, ObjectRen *obr, int do_tangent) if(f1[0]==0.0 && f1[1]==0.0 && f1[2]==0.0) VECCOPY(f1, vlr->n); } } + + if(do_nmap_tangent) { + VertRen *v1=vlr->v1, *v2=vlr->v2, *v3=vlr->v3, *v4=vlr->v4; + MTFace *tface= RE_vlakren_get_tface(obr, vlr, obr->actmtface, NULL, 0); + + if(tface) { + float *vtang, *ftang= RE_vlakren_get_nmap_tangent(obr, vlr, 1); + + vtang= find_vertex_tangent(vtangents[v1->index], tface->uv[0]); + VECCOPY(ftang, vtang); + Normalize(ftang); + vtang= find_vertex_tangent(vtangents[v2->index], tface->uv[1]); + VECCOPY(ftang+3, vtang); + Normalize(ftang+3); + vtang= find_vertex_tangent(vtangents[v3->index], tface->uv[2]); + VECCOPY(ftang+6, vtang); + Normalize(ftang+6); + if(v4) { + vtang= find_vertex_tangent(vtangents[v4->index], tface->uv[3]); + VECCOPY(ftang+9, vtang); + Normalize(ftang+9); + } + } + } } /* normalize vertex normals */ @@ -640,12 +734,18 @@ static void calc_vertexnormals(Render *re, ObjectRen *obr, int do_tangent) } } } + + + if(arena) + BLI_memarena_free(arena); + if(vtangents) + MEM_freeN(vtangents); } // NT same as calc_vertexnormals, but dont modify the existing vertex normals // only recalculate other render data. If this is at some point used for other things than fluidsim, // this could be made on option for the normal calc_vertexnormals -static void calc_fluidsimnormals(Render *re, ObjectRen *obr, int do_tangent) +static void calc_fluidsimnormals(Render *re, ObjectRen *obr, int do_nmap_tangent) { int a; @@ -692,13 +792,13 @@ static void calc_fluidsimnormals(Render *re, ObjectRen *obr, int do_tangent) } } - //if(do_tangent) + //if(do_nmap_tangent) // calc_tangent_vector(obr, vlr, fac1, fac2, fac3, fac4); } - if(do_tangent) { + if(do_nmap_tangent) { /* tangents still need to be calculated for flat faces too */ /* weighting removed, they are not vertexnormals */ - calc_tangent_vector(obr, vlr); + //calc_tangent_vector(obr, vlr); } } @@ -723,7 +823,7 @@ static void calc_fluidsimnormals(Render *re, ObjectRen *obr, int do_tangent) for(a=0; a<obr->totvert; a++) { VertRen *ver= RE_findOrAddVert(obr, a); Normalize(ver->n); - if(do_tangent) { + if(do_nmap_tangent) { float *tav= RE_vertren_get_tangent(obr, ver, 0); if(tav) Normalize(tav); } @@ -2053,7 +2153,7 @@ static int render_new_particle_system(Render *re, ObjectRen *obr, ParticleSystem } if(path && (ma->mode_l & MA_TANGENT_STR)==0) - calc_vertexnormals(re, obr, 0); + calc_vertexnormals(re, obr, 0, 0); return 1; } @@ -2334,7 +2434,7 @@ static void do_displacement(Render *re, ObjectRen *obr, float mat[][4], float im } /* Recalc vertex normals */ - calc_vertexnormals(re, obr, 0); + calc_vertexnormals(re, obr, 0, 0); } /* ------------------------------------------------------------------------- */ @@ -3013,7 +3113,8 @@ static void init_render_mesh(Render *re, ObjectRen *obr, int timeoffset) CustomDataMask mask; float xn, yn, zn, imat[3][3], mat[4][4]; //nor[3], float *orco=0; - int a, a1, ok, need_orco=0, need_stress=0, need_tangent=0, vertofs; + int need_orco=0, need_stress=0, need_nmap_tangent=0, need_tangent=0; + int a, a1, ok, vertofs; int end, do_autosmooth=0, totvert = 0; int useFluidmeshNormals= 0; // NT fluidsim, use smoothed normals? int use_original_normals= 0; @@ -3036,11 +3137,19 @@ static void init_render_mesh(Render *re, ObjectRen *obr, int timeoffset) if(ma->texco & TEXCO_STRESS) need_stress= 1; /* normalmaps, test if tangents needed, separated from shading */ - if ((ma->mode_l & MA_TANGENT_V) || (ma->mode_l & MA_NORMAP_TANG)) { + if(ma->mode_l & MA_TANGENT_V) { need_tangent= 1; if(me->mtface==NULL) need_orco= 1; } + if(ma->mode_l & MA_NORMAP_TANG) { + if(me->mtface==NULL) { + need_orco= 1; + need_tangent= 1; + } + need_nmap_tangent= 1; + } + /* radio faces need autosmooth, to separate shared vertices in corners */ if(re->r.mode & R_RADIO) if(ma->mode & MA_RADIO) @@ -3050,9 +3159,11 @@ static void init_render_mesh(Render *re, ObjectRen *obr, int timeoffset) if(re->flag & R_NEED_TANGENT) { /* exception for tangent space baking */ - need_tangent= 1; - if(me->mtface==NULL) + if(me->mtface==NULL) { need_orco= 1; + need_tangent= 1; + } + need_nmap_tangent= 1; } /* check autosmooth and displacement, we then have to skip only-verts optimize */ @@ -3292,7 +3403,7 @@ static void init_render_mesh(Render *re, ObjectRen *obr, int timeoffset) if(!timeoffset) { if (test_for_displace(re, ob ) ) { - calc_vertexnormals(re, obr, 0); + calc_vertexnormals(re, obr, 0, 0); if(do_autosmooth) do_displacement(re, obr, mat, imat); else @@ -3305,9 +3416,9 @@ static void init_render_mesh(Render *re, ObjectRen *obr, int timeoffset) if(useFluidmeshNormals) { // do not recalculate, only init render data - calc_fluidsimnormals(re, obr, need_tangent); + calc_fluidsimnormals(re, obr, need_tangent||need_nmap_tangent); } else { - calc_vertexnormals(re, obr, need_tangent); + calc_vertexnormals(re, obr, need_tangent, need_nmap_tangent); } if(need_stress) diff --git a/source/blender/render/intern/source/rendercore.c b/source/blender/render/intern/source/rendercore.c index 1d65f400634..32210080acb 100644 --- a/source/blender/render/intern/source/rendercore.c +++ b/source/blender/render/intern/source/rendercore.c @@ -1889,8 +1889,8 @@ static void bake_shade(void *handle, Object *ob, ShadeInput *shi, int quad, int VECCOPY(mat[2], tvn); } else { - VECCOPY(mat[0], shi->tang); - Crossf(mat[1], shi->vn, shi->tang); + VECCOPY(mat[0], shi->nmaptang); + Crossf(mat[1], shi->vn, shi->nmaptang); VECCOPY(mat[2], shi->vn); } @@ -2035,7 +2035,7 @@ static void do_bake_shade(void *handle, int x, int y, float u, float v) if(bs->type==RE_BAKE_NORMALS && R.r.bake_normal_space==R_BAKE_SPACE_TANGENT) { shade_input_set_shade_texco(shi); VECCOPY(tvn, shi->vn); - VECCOPY(ttang, shi->tang); + VECCOPY(ttang, shi->nmaptang); } /* if we are doing selected to active baking, find point on other face */ diff --git a/source/blender/render/intern/source/renderdatabase.c b/source/blender/render/intern/source/renderdatabase.c index d78b5936fd5..6bd82987397 100644 --- a/source/blender/render/intern/source/renderdatabase.c +++ b/source/blender/render/intern/source/renderdatabase.c @@ -106,7 +106,8 @@ #define RE_SURFNOR_ELEMS 3 #define RE_RADFACE_ELEMS 1 #define RE_SIMPLIFY_ELEMS 2 -#define RE_FACE_ELEMS 1 +#define RE_FACE_ELEMS 1 +#define RE_NMAP_TANGENT_ELEMS 12 float *RE_vertren_get_sticky(ObjectRen *obr, VertRen *ver, int verify) { @@ -364,6 +365,21 @@ float *RE_vlakren_get_surfnor(ObjectRen *obr, VlakRen *vlak, int verify) return surfnor + (vlak->index & 255)*RE_SURFNOR_ELEMS; } +float *RE_vlakren_get_nmap_tangent(ObjectRen *obr, VlakRen *vlak, int verify) +{ + float *tangent; + int nr= vlak->index>>8; + + tangent= obr->vlaknodes[nr].tangent; + if(tangent==NULL) { + if(verify) + tangent= obr->vlaknodes[nr].tangent= MEM_callocN(256*RE_NMAP_TANGENT_ELEMS*sizeof(float), "tangent table"); + else + return NULL; + } + return tangent + (vlak->index & 255)*RE_NMAP_TANGENT_ELEMS; +} + RadFace **RE_vlakren_get_radface(ObjectRen *obr, VlakRen *vlak, int verify) { RadFace **radface; @@ -384,7 +400,7 @@ VlakRen *RE_vlakren_copy(ObjectRen *obr, VlakRen *vlr) VlakRen *vlr1 = RE_findOrAddVlak(obr, obr->totvlak++); MTFace *mtface, *mtface1; MCol *mcol, *mcol1; - float *surfnor, *surfnor1; + float *surfnor, *surfnor1, *tangent, *tangent1; RadFace **radface, **radface1; int i, index = vlr1->index; char *name; @@ -408,6 +424,12 @@ VlakRen *RE_vlakren_copy(ObjectRen *obr, VlakRen *vlr) VECCOPY(surfnor1, surfnor); } + tangent= RE_vlakren_get_nmap_tangent(obr, vlr, 0); + if(tangent) { + tangent1= RE_vlakren_get_nmap_tangent(obr, vlr1, 1); + memcpy(tangent1, tangent, sizeof(float)*RE_NMAP_TANGENT_ELEMS); + } + radface= RE_vlakren_get_radface(obr, vlr, 0); if(radface) { radface1= RE_vlakren_get_radface(obr, vlr1, 1); @@ -773,6 +795,8 @@ void free_renderdata_vlaknodes(VlakTableNode *vlaknodes) MEM_freeN(vlaknodes[a].mcol); if(vlaknodes[a].surfnor) MEM_freeN(vlaknodes[a].surfnor); + if(vlaknodes[a].tangent) + MEM_freeN(vlaknodes[a].tangent); if(vlaknodes[a].radface) MEM_freeN(vlaknodes[a].radface); } diff --git a/source/blender/render/intern/source/shadeinput.c b/source/blender/render/intern/source/shadeinput.c index 29be0d710ca..49d09ac12aa 100644 --- a/source/blender/render/intern/source/shadeinput.c +++ b/source/blender/render/intern/source/shadeinput.c @@ -239,7 +239,7 @@ void shade_input_set_triangle_i(ShadeInput *shi, ObjectInstanceRen *obi, VlakRen shi->vlr= vlr; shi->obi= obi; shi->obr= obi->obr; - + shi->v1= vpp[i1]; shi->v2= vpp[i2]; shi->v3= vpp[i3]; @@ -382,6 +382,7 @@ void shade_input_set_strand_texco(ShadeInput *shi, StrandRen *strand, StrandVert if(mode & (MA_TANGENT_V|MA_NORMAP_TANG)) { VECCOPY(shi->tang, spoint->tan); + VECCOPY(shi->nmaptang, spoint->tan); } if(mode & MA_STR_SURFDIFF) { @@ -545,6 +546,7 @@ void shade_input_set_strand_texco(ShadeInput *shi, StrandRen *strand, StrandVert if((mode & MA_TANGENT_V)==0) { /* just prevent surprises */ shi->tang[0]= shi->tang[1]= shi->tang[2]= 0.0f; + shi->nmaptang[0]= shi->nmaptang[1]= shi->nmaptang[2]= 0.0f; } } } @@ -806,7 +808,7 @@ void shade_input_set_shade_texco(ShadeInput *shi) int mode= shi->mode; /* or-ed result for all nodes */ short texco= shi->mat->texco; - /* calculate dxno and tangents */ + /* calculate dxno */ if(shi->vlr->flag & R_SMOOTH) { if(shi->osatex && (texco & (TEXCO_NORM|TEXCO_REFL)) ) { @@ -822,47 +824,64 @@ void shade_input_set_shade_texco(ShadeInput *shi) 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; + } + + /* calc tangents */ + if (mode & (MA_TANGENT_V|MA_NORMAP_TANG) || R.flag & R_NEED_TANGENT) { + float *tangent, *s1, *s2, *s3; + float tl, tu, tv; + + if(shi->vlr->flag & R_SMOOTH) { + tl= l; + tu= u; + tv= v; + } + else { + /* qdn: flat faces have tangents too, + could pick either one, using average here */ + tl= 1.0f; + tu= 1.0f/3.0f; + tv= 1.0f/3.0f; + } + + shi->tang[0]= shi->tang[1]= shi->tang[2]= 0.0f; + shi->nmaptang[0]= shi->nmaptang[1]= shi->nmaptang[2]= 0.0f; + + if(mode & MA_TANGENT_V) { + s1 = RE_vertren_get_tangent(obr, v1, 0); + s2 = RE_vertren_get_tangent(obr, v2, 0); + s3 = RE_vertren_get_tangent(obr, v3, 0); - 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]); + shi->tang[0]= (tl*s3[0] - tu*s1[0] - tv*s2[0]); + shi->tang[1]= (tl*s3[1] - tu*s1[1] - tv*s2[1]); + shi->tang[2]= (tl*s3[2] - tu*s1[2] - tv*s2[2]); if(obi->flag & R_TRANSFORMED) normal_transform(obi->imat, shi->tang); - /* qdn: normalize just in case */ Normalize(shi->tang); + VECCOPY(shi->nmaptang, 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(mode & MA_NORMAP_TANG || R.flag & R_NEED_TANGENT) { + tangent= RE_vlakren_get_nmap_tangent(obr, shi->vlr, 0); + + if(tangent) { + s1= &tangent[shi->i1*3]; + s2= &tangent[shi->i2*3]; + s3= &tangent[shi->i3*3]; + + shi->nmaptang[0]= (tl*s3[0] - tu*s1[0] - tv*s2[0]); + shi->nmaptang[1]= (tl*s3[1] - tu*s1[1] - tv*s2[1]); + shi->nmaptang[2]= (tl*s3[2] - tu*s1[2] - tv*s2[2]); if(obi->flag & R_TRANSFORMED) - normal_transform(obi->imat, shi->tang); + normal_transform(obi->imat, shi->nmaptang); - Normalize(shi->tang); + Normalize(shi->nmaptang); } - else shi->tang[0]= shi->tang[1]= shi->tang[2]= 0.0f; } } @@ -1111,6 +1130,7 @@ void shade_input_set_shade_texco(ShadeInput *shi) if((mode & MA_TANGENT_V)==0) { /* just prevent surprises */ shi->tang[0]= shi->tang[1]= shi->tang[2]= 0.0f; + shi->nmaptang[0]= shi->nmaptang[1]= shi->nmaptang[2]= 0.0f; } } } diff --git a/source/blender/render/intern/source/texture.c b/source/blender/render/intern/source/texture.c index f418ec52985..377d72325f0 100644 --- a/source/blender/render/intern/source/texture.c +++ b/source/blender/render/intern/source/texture.c @@ -1781,11 +1781,11 @@ void do_material_tex(ShadeInput *shi) if(mtex->normapspace == MTEX_NSPACE_TANGENT) { /* qdn: tangent space */ float B[3], tv[3]; - Crossf(B, shi->vn, shi->tang); /* bitangent */ + Crossf(B, shi->vn, shi->nmaptang); /* bitangent */ /* transform norvec from tangent space to object surface in camera space */ - tv[0] = texres.nor[0]*shi->tang[0] + texres.nor[1]*B[0] + texres.nor[2]*shi->vn[0]; - tv[1] = texres.nor[0]*shi->tang[1] + texres.nor[1]*B[1] + texres.nor[2]*shi->vn[1]; - tv[2] = texres.nor[0]*shi->tang[2] + texres.nor[1]*B[2] + texres.nor[2]*shi->vn[2]; + tv[0] = texres.nor[0]*shi->nmaptang[0] + texres.nor[1]*B[0] + texres.nor[2]*shi->vn[0]; + tv[1] = texres.nor[0]*shi->nmaptang[1] + texres.nor[1]*B[1] + texres.nor[2]*shi->vn[1]; + tv[2] = texres.nor[0]*shi->nmaptang[2] + texres.nor[1]*B[2] + texres.nor[2]*shi->vn[2]; shi->vn[0]= facm*shi->vn[0] + fact*tv[0]; shi->vn[1]= facm*shi->vn[1] + fact*tv[1]; shi->vn[2]= facm*shi->vn[2] + fact*tv[2]; |