diff options
author | Alexander Romanov <a.romanov@blend4web.com> | 2016-04-26 11:43:02 +0300 |
---|---|---|
committer | Campbell Barton <ideasman42@gmail.com> | 2016-04-26 13:43:29 +0300 |
commit | 5abae51a6ef5b0f1b817ef5ce4bff34fef5001cd (patch) | |
tree | ca6d8f3595fd596fe978e4ad69a29bbc647be121 /source/blender/render | |
parent | 98babfa2b86f768ebc0cff6c0d8ec34e18afd2af (diff) |
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.
Diffstat (limited to 'source/blender/render')
8 files changed, 97 insertions, 52 deletions
diff --git a/source/blender/render/extern/include/RE_shader_ext.h b/source/blender/render/extern/include/RE_shader_ext.h index 12b97aedbd3..8b6dfb88b73 100644 --- a/source/blender/render/extern/include/RE_shader_ext.h +++ b/source/blender/render/extern/include/RE_shader_ext.h @@ -139,6 +139,7 @@ typedef struct ShadeInput { float refcol[4], displace[3]; float strandco, tang[3], nmapnorm[3], nmaptang[4], stress, winspeed[4]; float duplilo[3], dupliuv[3]; + float tangents[8][4]; /* 8 = MAX_MTFACE */ ShadeInputUV uv[8]; /* 8 = MAX_MTFACE */ ShadeInputCol col[8]; /* 8 = MAX_MCOL */ diff --git a/source/blender/render/intern/include/render_types.h b/source/blender/render/intern/include/render_types.h index cef3a073084..6de5da3795a 100644 --- a/source/blender/render/intern/include/render_types.h +++ b/source/blender/render/intern/include/render_types.h @@ -334,6 +334,8 @@ typedef struct ObjectRen { char (*mcol)[MAX_CUSTOMDATA_LAYER_NAME]; int actmtface, actmcol, bakemtface; + char tangent_mask; /* which tangent layer should be calculated */ + float obmat[4][4]; /* only used in convertblender.c, for instancing */ /* used on makeraytree */ diff --git a/source/blender/render/intern/include/renderdatabase.h b/source/blender/render/intern/include/renderdatabase.h index 167ebc58030..b576d69d806 100644 --- a/source/blender/render/intern/include/renderdatabase.h +++ b/source/blender/render/intern/include/renderdatabase.h @@ -76,7 +76,7 @@ typedef struct VlakTableNode { int *origindex; int totmtface, totmcol; float *surfnor; - float *tangent; + float *tangent_arrays[MAX_MTFACE]; struct RadFace **radface; } VlakTableNode; @@ -137,7 +137,7 @@ struct MTFace *RE_vlakren_get_tface(struct ObjectRen *obr, VlakRen *ren, int n, struct MCol *RE_vlakren_get_mcol(struct ObjectRen *obr, VlakRen *ren, int n, char **name, int verify); int *RE_vlakren_get_origindex(struct ObjectRen *obr, VlakRen *vlak, 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); +float *RE_vlakren_get_nmap_tangent(ObjectRen *obr, VlakRen *vlak, int index, bool verify); RadFace **RE_vlakren_get_radface(struct ObjectRen *obr, VlakRen *ren, int verify); void RE_vlakren_get_normal(struct Render *re, struct ObjectInstanceRen *obi, struct VlakRen *vlr, float *nor); diff --git a/source/blender/render/intern/source/bake_api.c b/source/blender/render/intern/source/bake_api.c index eff021c9b14..1a0ef4e64d4 100644 --- a/source/blender/render/intern/source/bake_api.c +++ b/source/blender/render/intern/source/bake_api.c @@ -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); diff --git a/source/blender/render/intern/source/convertblender.c b/source/blender/render/intern/source/convertblender.c index ccf54cb6bcd..b6ee88de290 100644 --- a/source/blender/render/intern/source/convertblender.c +++ b/source/blender/render/intern/source/convertblender.c @@ -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); diff --git a/source/blender/render/intern/source/multires_bake.c b/source/blender/render/intern/source/multires_bake.c index 8eb6e7000ab..8c6d9c5f951 100644 --- a/source/blender/render/intern/source/multires_bake.c +++ b/source/blender/render/intern/source/multires_bake.c @@ -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); } diff --git a/source/blender/render/intern/source/renderdatabase.c b/source/blender/render/intern/source/renderdatabase.c index e8db096c9a5..d3d26011a57 100644 --- a/source/blender/render/intern/source/renderdatabase.c +++ b/source/blender/render/intern/source/renderdatabase.c @@ -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); } diff --git a/source/blender/render/intern/source/shadeinput.c b/source/blender/render/intern/source/shadeinput.c index e60a5a70a7f..6e01921a6a7 100644 --- a/source/blender/render/intern/source/shadeinput.c +++ b/source/blender/render/intern/source/shadeinput.c @@ -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]; + } + } } } } |