Support multiple tangents for BI render & viewport

Normal Map node support for GLSL mode and the internal render (multiple tangents support).

The Normal Map node is a useful node which is present in the Cycles render.
It makes it possible to use normal mapping without additional material node in a node tree.
This patch implements Normal Map node for GLSL mode and the internal render.

Previously only the active UV layer was used to calculate tangents.
This commit is contained in:
2016-04-26 18:43:02 +10:00
committed by Campbell Barton
parent 98babfa2b8
commit 5abae51a6e
22 changed files with 751 additions and 341 deletions

View File

@@ -425,7 +425,7 @@ static TriTessFace *mesh_calc_tri_tessface(
if (tangent) {
DM_ensure_normals(dm);
DM_calc_loop_tangents(dm);
DM_calc_loop_tangents(dm, true, NULL, 0);
tspace = dm->getLoopDataArray(dm, CD_TANGENT);
BLI_assert(tspace);

View File

@@ -304,7 +304,7 @@ static void calc_tangent_vector(ObjectRen *obr, VlakRen *vlr, int do_tangent)
typedef struct {
ObjectRen *obr;
int mtface_index;
} SRenderMeshToTangent;
/* interface */
@@ -337,7 +337,7 @@ static void GetTextureCoordinate(const SMikkTSpaceContext *pContext, float r_uv[
//assert(vert_index>=0 && vert_index<4);
SRenderMeshToTangent *pMesh = (SRenderMeshToTangent *) pContext->m_pUserData;
VlakRen *vlr= RE_findOrAddVlak(pMesh->obr, face_num);
MTFace *tface= RE_vlakren_get_tface(pMesh->obr, vlr, pMesh->obr->actmtface, NULL, 0);
MTFace *tface= RE_vlakren_get_tface(pMesh->obr, vlr, pMesh->mtface_index, NULL, 0);
const float *coord;
if (tface != NULL) {
@@ -371,7 +371,7 @@ static void SetTSpace(const SMikkTSpaceContext *pContext, const float fvTangent[
//assert(vert_index>=0 && vert_index<4);
SRenderMeshToTangent *pMesh = (SRenderMeshToTangent *) pContext->m_pUserData;
VlakRen *vlr = RE_findOrAddVlak(pMesh->obr, face_num);
float *ftang = RE_vlakren_get_nmap_tangent(pMesh->obr, vlr, 1);
float *ftang = RE_vlakren_get_nmap_tangent(pMesh->obr, vlr, pMesh->mtface_index, true);
if (ftang!=NULL) {
copy_v3_v3(&ftang[iVert*4+0], fvTangent);
ftang[iVert*4+3]=fSign;
@@ -457,7 +457,12 @@ static void calc_vertexnormals(Render *UNUSED(re), ObjectRen *obr, bool do_verte
sInterface.m_getNormal = GetNormal;
sInterface.m_setTSpaceBasic = SetTSpace;
genTangSpaceDefault(&sContext);
for (a = 0; a < MAX_MTFACE; a++) {
if (obr->tangent_mask & 1 << a) {
mesh2tangent.mtface_index = a;
genTangSpaceDefault(&sContext);
}
}
}
}
@@ -3113,7 +3118,8 @@ static void init_render_mesh(Render *re, ObjectRen *obr, int timeoffset)
float xn, yn, zn, imat[3][3], mat[4][4]; //nor[3],
float *orco = NULL;
short (*loop_nors)[4][3] = NULL;
bool need_orco = false, need_stress = false, need_nmap_tangent = false, need_tangent = false, need_origindex = false;
bool need_orco = false, need_stress = false, need_tangent = false, need_origindex = false;
bool need_nmap_tangent_concrete = false;
int a, a1, ok, vertofs;
int end, totvert = 0;
bool do_autosmooth = false, do_displace = false;
@@ -3148,9 +3154,11 @@ static void init_render_mesh(Render *re, ObjectRen *obr, int timeoffset)
if (ma->mode_l & MA_NORMAP_TANG) {
if (me->mtpoly==NULL) {
need_orco= 1;
need_tangent= 1;
}
need_nmap_tangent= 1;
need_tangent= 1;
}
if (ma->mode2_l & MA_TANGENT_CONCRETE) {
need_nmap_tangent_concrete = true;
}
}
}
@@ -3161,7 +3169,7 @@ static void init_render_mesh(Render *re, ObjectRen *obr, int timeoffset)
need_orco= 1;
need_tangent= 1;
}
need_nmap_tangent= 1;
need_nmap_tangent_concrete = true;
}
/* check autosmooth and displacement, we then have to skip only-verts optimize
@@ -3274,14 +3282,13 @@ static void init_render_mesh(Render *re, ObjectRen *obr, int timeoffset)
/* store customdata names, because DerivedMesh is freed */
RE_set_customdata_names(obr, &dm->faceData);
/* add tangent layer if we need one */
if (need_nmap_tangent!=0 && CustomData_get_layer_index(&dm->faceData, CD_TANGENT) == -1) {
bool generate_data = false;
if (CustomData_get_layer_index(&dm->loopData, CD_TANGENT) == -1) {
dm->calcLoopTangents(dm);
generate_data = true;
}
DM_generate_tangent_tessface_data(dm, generate_data);
/* add tangent layers if we need */
if ((ma->nmap_tangent_names_count && need_nmap_tangent_concrete) || need_tangent) {
dm->calcLoopTangents(
dm, need_tangent,
(const char (*)[MAX_NAME])ma->nmap_tangent_names, ma->nmap_tangent_names_count);
obr->tangent_mask = dm->tangent_mask;
DM_generate_tangent_tessface_data(dm, need_nmap_tangent_concrete || need_tangent);
}
/* still to do for keys: the correct local texture coordinate */
@@ -3401,7 +3408,7 @@ static void init_render_mesh(Render *re, ObjectRen *obr, int timeoffset)
CustomDataLayer *layer;
MTFace *mtface, *mtf;
MCol *mcol, *mc;
int index, mtfn= 0, mcn= 0, mtng=0, mln = 0, vindex;
int index, mtfn= 0, mcn= 0, mln = 0, vindex;
char *name;
int nr_verts = v4!=0 ? 4 : 3;
@@ -3424,17 +3431,24 @@ static void init_render_mesh(Render *re, ObjectRen *obr, int timeoffset)
for (vindex=0; vindex<nr_verts; vindex++)
mc[vindex]=mcol[a*4+rev_tab[vindex]];
}
else if (layer->type == CD_TANGENT && mtng < 1) {
if (need_nmap_tangent != 0) {
const float * tangent = (const float *) layer->data;
float * ftang = RE_vlakren_get_nmap_tangent(obr, vlr, 1);
else if (layer->type == CD_TANGENT) {
if (need_nmap_tangent_concrete || need_tangent) {
int uv_start = CustomData_get_layer_index(&dm->faceData, CD_MTFACE);
int uv_index = CustomData_get_named_layer_index(&dm->faceData, CD_MTFACE, layer->name);
BLI_assert(uv_start >= 0 && uv_index >= 0);
if ((uv_start < 0 || uv_index < 0))
continue;
int n = uv_index - uv_start;
const float *tangent = (const float *) layer->data;
float *ftang = RE_vlakren_get_nmap_tangent(obr, vlr, n, true);
for (vindex=0; vindex<nr_verts; vindex++) {
copy_v4_v4(ftang+vindex*4, tangent+a*16+rev_tab[vindex]*4);
mul_mat3_m4_v3(mat, ftang+vindex*4);
normalize_v3(ftang+vindex*4);
}
}
mtng++;
}
else if (layer->type == CD_TESSLOOPNORMAL && mln < 1) {
if (loop_nors) {
@@ -3542,7 +3556,7 @@ static void init_render_mesh(Render *re, ObjectRen *obr, int timeoffset)
}
if (recalc_normals!=0 || need_tangent!=0)
calc_vertexnormals(re, obr, recalc_normals, need_tangent, need_nmap_tangent);
calc_vertexnormals(re, obr, recalc_normals, need_tangent, need_nmap_tangent_concrete);
}
MEM_SAFE_FREE(loop_nors);

View File

@@ -456,7 +456,7 @@ static void do_multires_bake(MultiresBakeRender *bkr, Image *ima, bool require_t
if (require_tangent) {
if (CustomData_get_layer_index(&dm->loopData, CD_TANGENT) == -1)
DM_calc_loop_tangents(dm);
DM_calc_loop_tangents(dm, true, NULL, 0);
pvtangent = DM_get_loop_data_layer(dm, CD_TANGENT);
}

View File

@@ -70,6 +70,7 @@
#include "DNA_material_types.h"
#include "DNA_meshdata_types.h"
#include "DNA_texture_types.h"
#include "DNA_listBase.h"
#include "DNA_particle_types.h"
#include "BKE_customdata.h"
@@ -380,19 +381,28 @@ 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 *RE_vlakren_get_nmap_tangent(ObjectRen *obr, VlakRen *vlak, int index, bool verify)
{
float *tangent;
float **tangents;
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");
tangents = obr->vlaknodes[nr].tangent_arrays;
if (index + 1 > 8) {
return NULL;
}
index = index < 0 ? 0: index;
if (tangents[index] == NULL) {
if (verify) {
tangents[index] = MEM_callocN(256*RE_NMAP_TANGENT_ELEMS*sizeof(float), "tangent table");
}
else
return NULL;
}
return tangent + (vlak->index & 255)*RE_NMAP_TANGENT_ELEMS;
return tangents[index] + (vlak->index & 255)*RE_NMAP_TANGENT_ELEMS;
}
RadFace **RE_vlakren_get_radface(ObjectRen *obr, VlakRen *vlak, int verify)
@@ -415,7 +425,8 @@ VlakRen *RE_vlakren_copy(ObjectRen *obr, VlakRen *vlr)
VlakRen *vlr1 = RE_findOrAddVlak(obr, obr->totvlak++);
MTFace *mtface, *mtface1;
MCol *mcol, *mcol1;
float *surfnor, *surfnor1, *tangent, *tangent1;
float *surfnor, *surfnor1;
float *tangent, *tangent1;
int *origindex, *origindex1;
RadFace **radface, **radface1;
int i, index = vlr1->index;
@@ -447,9 +458,11 @@ VlakRen *RE_vlakren_copy(ObjectRen *obr, VlakRen *vlr)
copy_v3_v3(surfnor1, surfnor);
}
tangent= RE_vlakren_get_nmap_tangent(obr, vlr, 0);
if (tangent) {
tangent1= RE_vlakren_get_nmap_tangent(obr, vlr1, 1);
for (i=0; i < MAX_MTFACE; i++) {
tangent = RE_vlakren_get_nmap_tangent(obr, vlr, i, false);
if (!tangent)
continue;
tangent1 = RE_vlakren_get_nmap_tangent(obr, vlr1, i, true);
memcpy(tangent1, tangent, sizeof(float)*RE_NMAP_TANGENT_ELEMS);
}
@@ -790,8 +803,10 @@ void free_renderdata_vlaknodes(VlakTableNode *vlaknodes)
MEM_freeN(vlaknodes[a].origindex);
if (vlaknodes[a].surfnor)
MEM_freeN(vlaknodes[a].surfnor);
if (vlaknodes[a].tangent)
MEM_freeN(vlaknodes[a].tangent);
for (int b = 0; b < MAX_MTFACE; b++) {
if (vlaknodes[a].tangent_arrays[b])
MEM_freeN(vlaknodes[a].tangent_arrays[b]);
}
if (vlaknodes[a].radface)
MEM_freeN(vlaknodes[a].radface);
}

View File

@@ -884,7 +884,10 @@ void shade_input_set_shade_texco(ShadeInput *shi)
float u = shi->u, v = shi->v;
float l = 1.0f + u + v, dl;
int mode = shi->mode; /* or-ed result for all nodes */
int mode2 = shi->mode2;
short texco = shi->mat->texco;
const bool need_mikk_tangent = (mode & MA_NORMAP_TANG || R.flag & R_NEED_TANGENT);
const bool need_mikk_tangent_concrete = (mode2 & MA_TANGENT_CONCRETE) != 0;
/* calculate dxno */
if (shi->vlr->flag & R_SMOOTH) {
@@ -905,8 +908,8 @@ void shade_input_set_shade_texco(ShadeInput *shi)
}
/* calc tangents */
if (mode & (MA_TANGENT_V | MA_NORMAP_TANG) || R.flag & R_NEED_TANGENT) {
const float *tangent, *s1, *s2, *s3;
if (mode & (MA_TANGENT_V | MA_NORMAP_TANG) || mode2 & MA_TANGENT_CONCRETE || R.flag & R_NEED_TANGENT) {
const float *s1, *s2, *s3;
float tl, tu, tv;
if (shi->vlr->flag & R_SMOOTH) {
@@ -943,14 +946,18 @@ void shade_input_set_shade_texco(ShadeInput *shi)
}
}
if (mode & MA_NORMAP_TANG || R.flag & R_NEED_TANGENT) {
tangent = RE_vlakren_get_nmap_tangent(obr, shi->vlr, 0);
if (need_mikk_tangent || need_mikk_tangent_concrete) {
int j1 = shi->i1, j2 = shi->i2, j3 = shi->i3;
float c0[3], c1[3], c2[3];
int acttang = obr->actmtface;
if (tangent) {
int j1 = shi->i1, j2 = shi->i2, j3 = shi->i3;
float c0[3], c1[3], c2[3];
vlr_set_uv_indices(shi->vlr, &j1, &j2, &j3);
vlr_set_uv_indices(shi->vlr, &j1, &j2, &j3);
/* cycle through all tangent in vlakren */
for (int i = 0; i < MAX_MTFACE; i++) {
const float *tangent = RE_vlakren_get_nmap_tangent(obr, shi->vlr, i, false);
if (!tangent)
continue;
copy_v3_v3(c0, &tangent[j1 * 4]);
copy_v3_v3(c1, &tangent[j2 * 4]);
@@ -966,13 +973,19 @@ void shade_input_set_shade_texco(ShadeInput *shi)
/* we don't normalize the interpolated TBN tangent
* corresponds better to how it's done in game engines */
shi->nmaptang[0] = (tl * c2[0] - tu * c0[0] - tv * c1[0]);
shi->nmaptang[1] = (tl * c2[1] - tu * c0[1] - tv * c1[1]);
shi->nmaptang[2] = (tl * c2[2] - tu * c0[2] - tv * c1[2]);
shi->tangents[i][0] = (tl * c2[0] - tu * c0[0] - tv * c1[0]);
shi->tangents[i][1] = (tl * c2[1] - tu * c0[1] - tv * c1[1]);
shi->tangents[i][2] = (tl * c2[2] - tu * c0[2] - tv * c1[2]);
/* the sign is the same for all 3 vertices of any
* non degenerate triangle. */
shi->nmaptang[3] = tangent[j1 * 4 + 3];
shi->tangents[i][3] = tangent[j1 * 4 + 3];
if (acttang == i && need_mikk_tangent) {
for (int m = 0; m < 4; m++) {
shi->nmaptang[m] = shi->tangents[i][m];
}
}
}
}
}