Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
path: root/source
diff options
context:
space:
mode:
authorBrecht Van Lommel <brechtvanlommel@pandora.be>2008-03-07 18:38:56 +0300
committerBrecht Van Lommel <brechtvanlommel@pandora.be>2008-03-07 18:38:56 +0300
commit5b3dc15880b698a53f4e87c9efe2bb35139aaf25 (patch)
tree4c26a3468ed2ed7b48c9a940730d485e0d96f10b /source
parentf13dc2aac1d83a5c6636aa1cacef9d27cdac05d5 (diff)
Normal map tangents are now not always averaged at vertices anymore,
but only when the UV's are connected. That fixes some artifacts when baking and using tangent space normal maps. It does mean increased memory usage because it now stores 4 tangents per face like UV's, and increased processing time, but there's no simple way around that.
Diffstat (limited to 'source')
-rw-r--r--source/blender/blenkernel/BKE_mesh.h2
-rw-r--r--source/blender/blenkernel/intern/subsurf_ccg.c2
-rw-r--r--source/blender/render/extern/include/RE_shader_ext.h2
-rw-r--r--source/blender/render/intern/include/renderdatabase.h2
-rw-r--r--source/blender/render/intern/source/convertblender.c171
-rw-r--r--source/blender/render/intern/source/rendercore.c6
-rw-r--r--source/blender/render/intern/source/renderdatabase.c28
-rw-r--r--source/blender/render/intern/source/shadeinput.c80
-rw-r--r--source/blender/render/intern/source/texture.c8
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];