Support multiple tangents for BI render & viewport
authorAlexander Romanov <a.romanov@blend4web.com>
Tue, 26 Apr 2016 08:43:02 +0000 (18:43 +1000)
committerCampbell Barton <ideasman42@gmail.com>
Tue, 26 Apr 2016 10:43:29 +0000 (20:43 +1000)
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.

22 files changed:
release/scripts/startup/nodeitems_builtins.py
source/blender/blenkernel/BKE_DerivedMesh.h
source/blender/blenkernel/BKE_mesh.h
source/blender/blenkernel/intern/DerivedMesh.c
source/blender/blenkernel/intern/cdderivedmesh.c
source/blender/blenkernel/intern/customdata.c
source/blender/blenkernel/intern/editderivedmesh.c
source/blender/blenkernel/intern/material.c
source/blender/blenkernel/intern/mesh_evaluate.c
source/blender/blenkernel/intern/subsurf_ccg.c
source/blender/gpu/shaders/gpu_shader_material.glsl
source/blender/makesdna/DNA_material_types.h
source/blender/nodes/shader/nodes/node_shader_normal_map.c
source/blender/render/extern/include/RE_shader_ext.h
source/blender/render/intern/include/render_types.h
source/blender/render/intern/include/renderdatabase.h
source/blender/render/intern/source/bake_api.c
source/blender/render/intern/source/convertblender.c
source/blender/render/intern/source/multires_bake.c
source/blender/render/intern/source/renderdatabase.c
source/blender/render/intern/source/shadeinput.c
source/gameengine/Converter/BL_BlenderDataConversion.cpp

index 780662148e04c035602a3bf21b8f272b9f82885d..9dca55ede001b9c7fba239525e908abc9aa71313 100644 (file)
@@ -160,6 +160,7 @@ shader_node_categories = [
         NodeItem("ShaderNodeMapping"),
         NodeItem("ShaderNodeVectorCurve"),
         NodeItem("ShaderNodeVectorTransform"),
+        NodeItem("ShaderNodeNormalMap"),
         ]),
     ShaderOldNodeCategory("SH_CONVERTOR", "Converter", items=[
         NodeItem("ShaderNodeValToRGB"),
index d7d6daa7e2a8c1b953584967441a02218a6b5053..7419b182c049b7382c0cc354b3f8b3204688d49a 100644 (file)
@@ -71,6 +71,7 @@
  *       as it is and stick with using BMesh and CDDM.
  */
 
+#include "DNA_defs.h"
 #include "DNA_customdata_types.h"
 #include "DNA_meshdata_types.h"
 
@@ -200,6 +201,8 @@ struct DerivedMesh {
        /* use for converting to BMesh which doesn't store bevel weight and edge crease by default */
        char cd_flag;
 
+       char tangent_mask; /* which tangent layers are calculated */
+
        /** Calculate vert and face normals */
        void (*calcNormals)(DerivedMesh *dm);
 
@@ -210,7 +213,9 @@ struct DerivedMesh {
        void (*calcLoopNormalsSpaceArray)(DerivedMesh *dm, const bool use_split_normals, const float split_angle,
                                          struct MLoopNorSpaceArray *r_lnors_spacearr);
 
-       void (*calcLoopTangents)(DerivedMesh *dm);
+       void (*calcLoopTangents)(
+               DerivedMesh *dm, bool calc_active_tangent,
+               const char (*tangent_names)[MAX_NAME], int tangent_names_count);
 
        /** Recalculates mesh tessellation */
        void (*recalcTessellation)(DerivedMesh *dm);
@@ -763,7 +768,7 @@ typedef struct DMVertexAttribs {
        struct {
                float (*array)[4];
                int em_offset, gl_index;
-       } tang;
+       } tang[MAX_MTFACE];
 
        struct {
                float (*array)[3];
@@ -779,7 +784,20 @@ void DM_vertex_attributes_from_gpu(
 
 void DM_draw_attrib_vertex(DMVertexAttribs *attribs, int a, int index, int vert, int loop);
 
-void DM_calc_loop_tangents(DerivedMesh *dm);
+void DM_calc_tangents_names_from_gpu(
+        const struct GPUVertexAttribs *gattribs,
+        char (*tangent_names)[MAX_NAME], int *tangent_names_count);
+void DM_add_named_tangent_layer_for_uv(
+        CustomData *uv_data, CustomData *tan_data, int numLoopData,
+        const char *layer_name);
+void DM_calc_loop_tangents_step_0(
+        const CustomData *loopData, bool calc_active_tangent,
+        const char (*tangent_names)[MAX_NAME], int tangent_names_count,
+        bool *rcalc_act, bool *rcalc_ren, int *ract_uv_n, int *rren_uv_n,
+        char *ract_uv_name, char *rren_uv_name, char *rtangent_mask);
+void DM_calc_loop_tangents(
+        DerivedMesh *dm, bool calc_active_tangent, const char (*tangent_names)[MAX_NAME],
+        int tangent_names_count);
 void DM_calc_auto_bump_scale(DerivedMesh *dm);
 
 /** Set object's bounding box based on DerivedMesh min/max data */
index a8f20a4ebc5082873b4a738415de1f3ab916050f..ac1f1576ebaf450b9223b5b22b68ccc15bd50ba6 100644 (file)
@@ -293,8 +293,9 @@ void BKE_mesh_loops_to_mface_corners(
 void BKE_mesh_loops_to_tessdata(
         struct CustomData *fdata, struct CustomData *ldata, struct CustomData *pdata, struct MFace *mface,
         int *polyindices, unsigned int (*loopindices)[4], const int num_faces);
-void BKE_mesh_tangent_loops_to_tessdata(struct CustomData *fdata, struct CustomData *ldata, struct MFace *mface,
-                                        int *polyindices, unsigned int (*loopindices)[4], const int num_faces);
+void BKE_mesh_tangent_loops_to_tessdata(
+        struct CustomData *fdata, struct CustomData *ldata, struct MFace *mface,
+        int *polyindices, unsigned int (*loopindices)[4], const int num_faces, const char *layer_name);
 int BKE_mesh_recalc_tessellation(
         struct CustomData *fdata, struct CustomData *ldata, struct CustomData *pdata,
         struct MVert *mvert,
index d120678c00599e2b254ba268b4be8365df39496d..57926e6a56aa33b99a79d9cee07f76c67591dc37 100644 (file)
@@ -49,6 +49,7 @@
 #include "BLI_math.h"
 #include "BLI_utildefines.h"
 #include "BLI_linklist.h"
+#include "BLI_task.h"
 
 #include "BKE_cdderivedmesh.h"
 #include "BKE_editmesh.h"
@@ -595,50 +596,49 @@ void DM_generate_tangent_tessface_data(DerivedMesh *dm, bool generate)
        int mf_idx;
 
        int *polyindex = CustomData_get_layer(fdata, CD_ORIGINDEX);
-       unsigned int (*loopindex)[4];
+       unsigned int (*loopindex)[4] = NULL;
 
        /* Should never occure, but better abort than segfault! */
        if (!polyindex)
                return;
 
        if (generate) {
-               for (int i = 0; i < ldata->totlayer; i++) {
-                       if (ldata->layers[i].type == CD_TANGENT) {
-                               CustomData_add_layer_named(fdata, CD_TANGENT, CD_CALLOC, NULL, totface, ldata->layers[i].name);
-                       }
-               }
-               CustomData_bmesh_update_active_layers(fdata, pdata, ldata);
-       }
-
-       BLI_assert(CustomData_from_bmeshpoly_test(fdata, pdata, ldata, true));
-
-       loopindex = MEM_mallocN(sizeof(*loopindex) * totface, __func__);
-
-       for (mf_idx = 0, mf = mface; mf_idx < totface; mf_idx++, mf++) {
-               const int mf_len = mf->v4 ? 4 : 3;
-               unsigned int *ml_idx = loopindex[mf_idx];
-               int i, not_done;
+               for (int j = 0; j < ldata->totlayer; j++) {
+                       if (ldata->layers[j].type == CD_TANGENT) {
+                               CustomData_add_layer_named(fdata, CD_TANGENT, CD_CALLOC, NULL, totface, ldata->layers[j].name);
+                               CustomData_bmesh_update_active_layers(fdata, pdata, ldata);
+
+                               if (!loopindex) {
+                                       loopindex = MEM_mallocN(sizeof(*loopindex) * totface, __func__);
+                                       for (mf_idx = 0, mf = mface; mf_idx < totface; mf_idx++, mf++) {
+                                               const int mf_len = mf->v4 ? 4 : 3;
+                                               unsigned int *ml_idx = loopindex[mf_idx];
+
+                                               /* Find out loop indices. */
+                                               /* NOTE: This assumes tessface are valid and in sync with loop/poly... Else, most likely, segfault! */
+                                               for (int i = mp[polyindex[mf_idx]].loopstart, not_done = mf_len; not_done; i++) {
+                                                       const int tf_v = BKE_MESH_TESSFACE_VINDEX_ORDER(mf, ml[i].v);
+                                                       if (tf_v != -1) {
+                                                               ml_idx[tf_v] = i;
+                                                               not_done--;
+                                                       }
+                                               }
+                                       }
+                               }
 
-               /* Find out loop indices. */
-               /* NOTE: This assumes tessface are valid and in sync with loop/poly... Else, most likely, segfault! */
-               for (i = mp[polyindex[mf_idx]].loopstart, not_done = mf_len; not_done; i++) {
-                       const int tf_v = BKE_MESH_TESSFACE_VINDEX_ORDER(mf, ml[i].v);
-                       if (tf_v != -1) {
-                               ml_idx[tf_v] = i;
-                               not_done--;
+                               /* NOTE: quad detection issue - fourth vertidx vs fourth loopidx:
+                                * Here, our tfaces' fourth vertex index is never 0 for a quad. However, we know our fourth loop index may be
+                                * 0 for quads (because our quads may have been rotated compared to their org poly, see tessellation code).
+                                * So we pass the MFace's, and BKE_mesh_loops_to_tessdata will use MFace->v4 index as quad test.
+                                */
+                               BKE_mesh_tangent_loops_to_tessdata(fdata, ldata, mface, polyindex, loopindex, totface, ldata->layers[j].name);
                        }
                }
+               if (loopindex)
+                       MEM_freeN(loopindex);
+               BLI_assert(CustomData_from_bmeshpoly_test(fdata, pdata, ldata, true));
        }
 
-       /* NOTE: quad detection issue - fourth vertidx vs fourth loopidx:
-        * Here, our tfaces' fourth vertex index is never 0 for a quad. However, we know our fourth loop index may be
-        * 0 for quads (because our quads may have been rotated compared to their org poly, see tessellation code).
-        * So we pass the MFace's, and BKE_mesh_loops_to_tessdata will use MFace->v4 index as quad test.
-        */
-       BKE_mesh_tangent_loops_to_tessdata(fdata, ldata, mface, polyindex, loopindex, totface);
-
-       MEM_freeN(loopindex);
-
        if (G.debug & G_DEBUG)
                printf("%s: Updated tessellated tangents of dm %p\n", __func__, dm);
 }
@@ -3207,96 +3207,28 @@ finally:
        pRes[3] = fSign;
 }
 
-void DM_calc_loop_tangents(DerivedMesh *dm)
+void DM_calc_tangents_names_from_gpu(
+        const GPUVertexAttribs *gattribs,
+        char (*tangent_names)[MAX_NAME], int *r_tangent_names_count)
 {
-       /* mesh vars */
-       const MLoopTri *looptri;
-       MVert *mvert;
-       MLoopUV *mloopuv;
-       MPoly *mpoly;
-       MLoop *mloop;
-       float (*orco)[3] = NULL, (*tangent)[4];
-       int /* totvert, */ totface;
-       float (*fnors)[3];
-       float (*tlnors)[3];
-
-       if (CustomData_get_layer_index(&dm->loopData, CD_TANGENT) != -1)
-               return;
-
-       fnors = dm->getPolyDataArray(dm, CD_NORMAL);
-       /* Note, we assume we do have tessellated loop normals at this point (in case it is object-enabled),
-        * have to check this is valid...
-        */
-       tlnors = dm->getLoopDataArray(dm, CD_NORMAL);
-
-       /* check we have all the needed layers */
-       /* totvert = dm->getNumVerts(dm); */ /* UNUSED */
-       looptri = dm->getLoopTriArray(dm);
-       totface = dm->getNumLoopTri(dm);
-
-       mvert = dm->getVertArray(dm);
-       mpoly = dm->getPolyArray(dm);
-       mloop = dm->getLoopArray(dm);
-       mloopuv = dm->getLoopDataArray(dm, CD_MLOOPUV);
-
-       if (!mloopuv) {
-               orco = dm->getVertDataArray(dm, CD_ORCO);
-               if (!orco)
-                       return;
-       }
-       
-       /* create tangent layer */
-       DM_add_loop_layer(dm, CD_TANGENT, CD_CALLOC, NULL);
-       tangent = DM_get_loop_data_layer(dm, CD_TANGENT);
-       
-#ifdef USE_LOOPTRI_DETECT_QUADS
-       int num_face_as_quad_map;
-       int *face_as_quad_map = NULL;
-
-       /* map faces to quads */
-       if (totface != dm->getNumPolys(dm)) {
-               /* over alloc, since we dont know how many ngon or quads we have */
-
-               /* map fake face index to looptri */
-               face_as_quad_map = MEM_mallocN(sizeof(int) * totface, __func__);
-               int i, j;
-               for (i = 0, j = 0; j < totface; i++, j++) {
-                       face_as_quad_map[i] = j;
-                       /* step over all quads */
-                       if (mpoly[looptri[j].poly].totloop == 4) {
-                               j++;  /* skips the nest looptri */
-                       }
+       int count = 0;
+       for (int b = 0; b < gattribs->totlayer; b++) {
+               if (gattribs->layer[b].type == CD_TANGENT) {
+                       strcpy(tangent_names[count++], gattribs->layer[b].name);
                }
-               num_face_as_quad_map = i;
-       }
-       else {
-               num_face_as_quad_map = totface;
        }
-#endif
+       *r_tangent_names_count = count;
+}
 
+static void DM_calc_loop_tangents_thread(TaskPool *UNUSED(pool), void *taskdata, int UNUSED(threadid))
+{
+       struct SGLSLMeshToTangent *mesh2tangent = taskdata;
        /* new computation method */
        {
-               SGLSLMeshToTangent mesh2tangent = {NULL};
                SMikkTSpaceContext sContext = {NULL};
                SMikkTSpaceInterface sInterface = {NULL};
 
-               mesh2tangent.precomputedFaceNormals = fnors;
-               mesh2tangent.precomputedLoopNormals = tlnors;
-               mesh2tangent.looptri = looptri;
-               mesh2tangent.mloopuv = mloopuv;
-               mesh2tangent.mpoly = mpoly;
-               mesh2tangent.mloop = mloop;
-               mesh2tangent.mvert = mvert;
-               mesh2tangent.orco = orco;
-               mesh2tangent.tangent = tangent;
-               mesh2tangent.numTessFaces = totface;
-
-#ifdef USE_LOOPTRI_DETECT_QUADS
-               mesh2tangent.face_as_quad_map = face_as_quad_map;
-               mesh2tangent.num_face_as_quad_map = num_face_as_quad_map;
-#endif
-
-               sContext.m_pUserData = &mesh2tangent;
+               sContext.m_pUserData = mesh2tangent;
                sContext.m_pInterface = &sInterface;
                sInterface.m_getNumFaces = dm_ts_GetNumFaces;
                sInterface.m_getNumVerticesOfFace = dm_ts_GetNumVertsOfFace;
@@ -3307,13 +3239,211 @@ void DM_calc_loop_tangents(DerivedMesh *dm)
 
                /* 0 if failed */
                genTangSpaceDefault(&sContext);
+       }
+}
+
+void DM_add_named_tangent_layer_for_uv(
+        CustomData *uv_data, CustomData *tan_data, int numLoopData,
+        const char *layer_name)
+{
+       if (CustomData_get_named_layer_index(tan_data, CD_TANGENT, layer_name) == -1 &&
+           CustomData_get_named_layer_index(uv_data, CD_MLOOPUV, layer_name) != -1)
+       {
+               CustomData_add_layer_named(
+                       tan_data, CD_TANGENT, CD_CALLOC, NULL,
+                       numLoopData, layer_name);
+       }
+}
+
+/**
+ * Here we get some useful information such as active uv layer name and search if it is already in tangent_names.
+ * Also, we calculate tangent_mask that works as a descriptor of tangents state.
+ * If tangent_mask has changed, then recalculate tangents.
+ */
+void DM_calc_loop_tangents_step_0(
+        const CustomData *loopData, bool calc_active_tangent,
+        const char (*tangent_names)[MAX_NAME], int tangent_names_count,
+        bool *rcalc_act, bool *rcalc_ren, int *ract_uv_n, int *rren_uv_n,
+        char *ract_uv_name, char *rren_uv_name, char *rtangent_mask) {
+       /* Active uv in viewport */
+       *ract_uv_n = CustomData_get_active_layer(loopData, CD_MLOOPUV);
+       ract_uv_name[0] = 0;
+       if (*ract_uv_n != -1) {
+               strcpy(ract_uv_name, loopData->layers[*ract_uv_n].name);
+       }
+
+       /* Active tangent in render */
+       *rren_uv_n = CustomData_get_render_layer(loopData, CD_MLOOPUV);
+       rren_uv_name[0] = 0;
+       if (*rren_uv_n != -1) {
+               strcpy(rren_uv_name, loopData->layers[*rren_uv_n].name);
+       }
+
+       /* If active tangent not in tangent_names we take it into account */
+       *rcalc_act = false;
+       *rcalc_ren = false;
+       for (int i = 0; i < tangent_names_count; i++) {
+               if (tangent_names[i][0] == 0) {
+                       calc_active_tangent = true;
+               }
+       }
+       if (calc_active_tangent) {
+               *rcalc_act = true;
+               *rcalc_ren = true;
+               for (int i = 0; i < tangent_names_count; i++) {
+                       if (STREQ(ract_uv_name, tangent_names[i]))
+                               *rcalc_act = false;
+                       if (STREQ(rren_uv_name, tangent_names[i]))
+                               *rcalc_ren = false;
+               }
+       }
+       *rtangent_mask = 0;
+
+       const int uv_layer_num = CustomData_number_of_layers(loopData, CD_MLOOPUV);
+       for (int n = 0; n < uv_layer_num; n++) {
+               const char *name = CustomData_get_layer_name(loopData, CD_MLOOPUV, n);
+               bool add = false;
+               for (int i = 0; i < tangent_names_count; i++) {
+                       if (tangent_names[i][0] && STREQ(tangent_names[i], name)) {
+                               add = true;
+                               break;
+                       }
+               }
+               if ((*rcalc_act && ract_uv_name[0] && STREQ(ract_uv_name, name)) ||
+                   (*rcalc_ren && rren_uv_name[0] && STREQ(rren_uv_name, name)))
+               {
+                       add = true;
+               }
+               if (add)
+                       *rtangent_mask |= 1 << n;
+       }
+}
+
+void DM_calc_loop_tangents(
+        DerivedMesh *dm, bool calc_active_tangent,
+        const char (*tangent_names)[MAX_NAME], int tangent_names_count)
+{
+       if (CustomData_number_of_layers(&dm->loopData, CD_MLOOPUV) == 0)
+               return;
+       int act_uv_n = -1;
+       int ren_uv_n = -1;
+       bool calc_act = false;
+       bool calc_ren = false;
+       char act_uv_name[MAX_NAME];
+       char ren_uv_name[MAX_NAME];
+       char tangent_mask = 0;
+       DM_calc_loop_tangents_step_0(
+               &dm->loopData, calc_active_tangent, tangent_names, tangent_names_count,
+               &calc_act, &calc_ren, &act_uv_n, &ren_uv_n, act_uv_name, ren_uv_name, &tangent_mask);
+       if ((dm->tangent_mask | tangent_mask) != dm->tangent_mask) {
+               /* Check we have all the needed layers */
+               MPoly *mpoly = dm->getPolyArray(dm);
+               const MLoopTri *looptri = dm->getLoopTriArray(dm);
+               int totface = dm->getNumLoopTri(dm);
+               /* Allocate needed tangent layers */
+               for (int i = 0; i < tangent_names_count; i++)
+                       if (tangent_names[i][0])
+                               DM_add_named_tangent_layer_for_uv(&dm->loopData, &dm->loopData, dm->numLoopData, tangent_names[i]);
+               if (calc_act && act_uv_name[0])
+                       DM_add_named_tangent_layer_for_uv(&dm->loopData, &dm->loopData, dm->numLoopData, act_uv_name);
+               if (calc_ren && ren_uv_name[0])
+                       DM_add_named_tangent_layer_for_uv(&dm->loopData, &dm->loopData, dm->numLoopData, ren_uv_name);
 
+#ifdef USE_LOOPTRI_DETECT_QUADS
+               int num_face_as_quad_map;
+               int *face_as_quad_map = NULL;
+
+               /* map faces to quads */
+               if (totface != dm->getNumPolys(dm)) {
+                       /* over alloc, since we dont know how many ngon or quads we have */
+
+                       /* map fake face index to looptri */
+                       face_as_quad_map = MEM_mallocN(sizeof(int) * totface, __func__);
+                       int k, j;
+                       for (k = 0, j = 0; j < totface; k++, j++) {
+                               face_as_quad_map[k] = j;
+                               /* step over all quads */
+                               if (mpoly[looptri[j].poly].totloop == 4) {
+                                       j++;  /* skips the nest looptri */
+                               }
+                       }
+                       num_face_as_quad_map = k;
+               }
+               else {
+                       num_face_as_quad_map = totface;
+               }
+#endif
+
+               /* Calculation */
+               {
+                       TaskScheduler *scheduler = BLI_task_scheduler_get();
+                       TaskPool *task_pool;
+                       task_pool = BLI_task_pool_create(scheduler, NULL);
+
+                       dm->tangent_mask = 0;
+                       /* Calculate tangent layers */
+                       SGLSLMeshToTangent data_array[MAX_MTFACE];
+                       const int tangent_layer_num = CustomData_number_of_layers(&dm->loopData, CD_TANGENT);
+                       for (int n = 0; n < tangent_layer_num; n++) {
+                               int index = CustomData_get_layer_index_n(&dm->loopData, CD_TANGENT, n);
+                               BLI_assert(n < MAX_MTFACE);
+                               SGLSLMeshToTangent *mesh2tangent = &data_array[n];
+                               mesh2tangent->numTessFaces = totface;
+#ifdef USE_LOOPTRI_DETECT_QUADS
+                               mesh2tangent->face_as_quad_map = face_as_quad_map;
+                               mesh2tangent->num_face_as_quad_map = num_face_as_quad_map;
+#endif
+                               mesh2tangent->mvert = dm->getVertArray(dm);
+                               mesh2tangent->mpoly = dm->getPolyArray(dm);
+                               mesh2tangent->mloop = dm->getLoopArray(dm);
+                               mesh2tangent->looptri = dm->getLoopTriArray(dm);
+                               /* Note, we assume we do have tessellated loop normals at this point (in case it is object-enabled),
+                                * have to check this is valid...
+                                */
+                               mesh2tangent->precomputedLoopNormals = dm->getLoopDataArray(dm, CD_NORMAL);
+                               mesh2tangent->precomputedFaceNormals = CustomData_get_layer(&dm->faceData, CD_NORMAL);
+
+                               mesh2tangent->orco = NULL;
+                               mesh2tangent->mloopuv = CustomData_get_layer_named(&dm->loopData, CD_MLOOPUV, dm->loopData.layers[index].name);
+                               if (!mesh2tangent->mloopuv) {
+                                       mesh2tangent->orco = dm->getVertDataArray(dm, CD_ORCO);
+                                       if (!mesh2tangent->orco)
+                                               continue;
+                               }
+                               mesh2tangent->tangent = dm->loopData.layers[index].data;
+
+                               /* Fill the resulting tangent_mask */
+                               int uv_ind = CustomData_get_named_layer_index(&dm->loopData, CD_MLOOPUV, dm->loopData.layers[index].name);
+                               int uv_start = CustomData_get_layer_index(&dm->loopData, CD_MLOOPUV);
+                               BLI_assert(uv_ind != -1 && uv_start != -1);
+                               BLI_assert(uv_ind - uv_start < MAX_MTFACE);
+                               dm->tangent_mask |= 1 << (uv_ind - uv_start);
+                               BLI_task_pool_push(task_pool, DM_calc_loop_tangents_thread, mesh2tangent, false, TASK_PRIORITY_LOW);
+                       }
+
+                       BLI_assert(dm->tangent_mask == tangent_mask);
+                       BLI_task_pool_work_and_wait(task_pool);
+                       BLI_task_pool_free(task_pool);
+               }
 #ifdef USE_LOOPTRI_DETECT_QUADS
                if (face_as_quad_map) {
                        MEM_freeN(face_as_quad_map);
                }
 #undef USE_LOOPTRI_DETECT_QUADS
+
 #endif
+
+               int uv_index, tan_index;
+
+               /* Update active layer index */
+               uv_index = CustomData_get_layer_index_n(&dm->loopData, CD_MLOOPUV, act_uv_n);
+               tan_index = CustomData_get_named_layer_index(&dm->loopData, CD_TANGENT, dm->loopData.layers[uv_index].name);
+               CustomData_set_layer_active_index(&dm->loopData, CD_TANGENT, tan_index);
+
+               /* Update render layer index */
+               uv_index = CustomData_get_layer_index_n(&dm->loopData, CD_MLOOPUV, ren_uv_n);
+               tan_index = CustomData_get_named_layer_index(&dm->loopData, CD_TANGENT, dm->loopData.layers[uv_index].name);
+               CustomData_set_layer_render_index(&dm->loopData, CD_TANGENT, tan_index);
        }
 }
 
@@ -3487,15 +3617,13 @@ void DM_vertex_attributes_from_gpu(DerivedMesh *dm, GPUVertexAttribs *gattribs,
        if (dm->auto_bump_scale <= 0.0f)
                DM_calc_auto_bump_scale(dm);
 
-       /* add a tangent layer if necessary */
-       for (b = 0; b < gattribs->totlayer; b++) {
-               if (gattribs->layer[b].type == CD_TANGENT) {
-                       if (CustomData_get_layer_index(&dm->loopData, CD_TANGENT) == -1) {
-                               dm->calcLoopTangents(dm);
-                       }
-                       break;
-               }
-       }
+       char tangent_names[MAX_MTFACE][MAX_NAME];
+       int tangent_names_count;
+       /* Add a tangent layer/layers. */
+       DM_calc_tangents_names_from_gpu(gattribs, tangent_names, &tangent_names_count);
+
+       if (tangent_names_count)
+               dm->calcLoopTangents(dm, false, (const char (*)[MAX_NAME])tangent_names, tangent_names_count);
 
        for (b = 0; b < gattribs->totlayer; b++) {
                if (gattribs->layer[b].type == CD_MTFACE) {
@@ -3541,20 +3669,24 @@ void DM_vertex_attributes_from_gpu(DerivedMesh *dm, GPUVertexAttribs *gattribs,
                }
                else if (gattribs->layer[b].type == CD_TANGENT) {
                        /* note, even with 'is_editmesh' this uses the derived-meshes loop data */
-                       layer = CustomData_get_layer_index(&dm->loopData, CD_TANGENT);
 
-                       attribs->tottang = 1;
+                       if (gattribs->layer[b].name[0])
+                               layer = CustomData_get_named_layer_index(&dm->loopData, CD_TANGENT, gattribs->layer[b].name);
+                       else
+                               layer = CustomData_get_active_layer_index(&dm->loopData, CD_TANGENT);
+
+                       a = attribs->tottang++;
 
                        if (layer != -1) {
-                               attribs->tang.array = dm->loopData.layers[layer].data;
-                               attribs->tang.em_offset = dm->loopData.layers[layer].offset;
+                               attribs->tang[a].array = dm->loopData.layers[layer].data;
+                               attribs->tang[a].em_offset = dm->loopData.layers[layer].offset;
                        }
                        else {
-                               attribs->tang.array = NULL;
-                               attribs->tang.em_offset = -1;
+                               attribs->tang[a].array = NULL;
+                               attribs->tang[a].em_offset = -1;
                        }
 
-                       attribs->tang.gl_index = gattribs->layer[b].glindex;
+                       attribs->tang[a].gl_index = gattribs->layer[b].glindex;
                }
                else if (gattribs->layer[b].type == CD_ORCO) {
                        /* original coordinates */
@@ -3636,10 +3768,12 @@ void DM_draw_attrib_vertex(DMVertexAttribs *attribs, int a, int index, int vert,
        }
 
        /* tangent for normal mapping */
-       if (attribs->tottang) {
-               /*const*/ float (*array)[4] = attribs->tang.array;
-               const float *tang = (array) ? array[loop] : zero;
-               glVertexAttrib4fv(attribs->tang.gl_index, tang);
+       for (b = 0; b < attribs->tottang; b++) {
+               if (attribs->tang[b].array) {
+                       /*const*/ float (*array)[4] = attribs->tang[b].array;
+                       const float *tang = (array) ? array[a * 4 + vert] : zero;
+                       glVertexAttrib4fv(attribs->tang[b].gl_index, tang);
+               }
        }
 }
 
index 519b7b4463719d27bd9acd4042bae74dbf6d3406..e6741657f47dd959940130cdd6297d79e3a230a2 100644 (file)
@@ -1049,11 +1049,13 @@ static void cdDM_drawMappedFacesGLSL(
                                                numdata++;
                                        }
                                }
-                               if (matconv[a].attribs.tottang && matconv[a].attribs.tang.array) {
-                                       matconv[a].datatypes[numdata].index = matconv[a].attribs.tang.gl_index;
-                                       matconv[a].datatypes[numdata].size = 4;
-                                       matconv[a].datatypes[numdata].type = GL_FLOAT;
-                                       numdata++;
+                               for (b = 0; b < matconv[a].attribs.tottang; b++) {
+                                       if (matconv[a].attribs.tang[b].array) {
+                                               matconv[a].datatypes[numdata].index = matconv[a].attribs.tang[b].gl_index;
+                                               matconv[a].datatypes[numdata].size = 4;
+                                               matconv[a].datatypes[numdata].type = GL_FLOAT;
+                                               numdata++;
+                                       }
                                }
                                if (numdata != 0) {
                                        matconv[a].numdata = numdata;
@@ -1105,11 +1107,13 @@ static void cdDM_drawMappedFacesGLSL(
                                                        offset += sizeof(unsigned char) * 4;
                                                }
                                        }
-                                       if (matconv[i].attribs.tottang && matconv[i].attribs.tang.array) {
-                                               const float (*looptang)[4] = (const float (*)[4])matconv[i].attribs.tang.array;
-                                               for (j = 0; j < mpoly->totloop; j++)
-                                                       copy_v4_v4((float *)&varray[offset + j * max_element_size], looptang[mpoly->loopstart + j]);
-                                               offset += sizeof(float) * 4;
+                                       for (b = 0; b < matconv[i].attribs.tottang; b++) {
+                                               if (matconv[i].attribs.tottang && matconv[i].attribs.tang[b].array) {
+                                                       const float (*looptang)[4] = (const float (*)[4])matconv[i].attribs.tang[b].array;
+                                                       for (j = 0; j < mpoly->totloop; j++)
+                                                               copy_v4_v4((float *)&varray[offset + j * max_element_size], looptang[mpoly->loopstart + j]);
+                                                       offset += sizeof(float) * 4;
+                                               }
                                        }
                                }
 
index a12d5434b301efe6af639e23d348e9b8912180e2..b0d0dc08126214ec408123352ea30abd5357d110 100644 (file)
@@ -1259,7 +1259,7 @@ static const LayerTypeInfo LAYERTYPEINFO[CD_NUMTYPES] = {
         layerDefault_mloopcol, layerEqual_mloopcol, layerMultiply_mloopcol, layerInitMinMax_mloopcol, 
         layerAdd_mloopcol, layerDoMinMax_mloopcol, layerCopyValue_mloopcol, NULL, NULL, NULL, layerMaxNum_mloopcol},
        /* 18: CD_TANGENT */
-       {sizeof(float) * 4 * 4, "", 0, NULL, NULL, NULL, NULL, NULL, NULL},
+       {sizeof(float) * 4 * 4, "", 0, N_("Tangent"), NULL, NULL, NULL, NULL, NULL},
        /* 19: CD_MDISPS */
        {sizeof(MDisps), "MDisps", 1, NULL, layerCopy_mdisps,
         layerFree_mdisps, NULL, layerSwap_mdisps, NULL,
index 96bdfe88722a9f263d0fec3e01756b0b3af17154..6c1174476640d9c13dbf653b5f14a299c498b88b 100644 (file)
@@ -44,6 +44,7 @@
 #include "BLI_math.h"
 #include "BLI_jitter.h"
 #include "BLI_bitmap.h"
+#include "BLI_task.h"
 
 #include "BKE_cdderivedmesh.h"
 #include "BKE_mesh.h"
@@ -451,118 +452,148 @@ finally:
        pRes[3] = fSign;
 }
 
+static void emDM_calc_loop_tangents_thread(TaskPool *UNUSED(pool), void *taskdata, int UNUSED(threadid))
+{
+       struct SGLSLEditMeshToTangent *mesh2tangent = taskdata;
+       /* new computation method */
+       {
+               SMikkTSpaceContext sContext = {NULL};
+               SMikkTSpaceInterface sInterface = {NULL};
+               sContext.m_pUserData = mesh2tangent;
+               sContext.m_pInterface = &sInterface;
+               sInterface.m_getNumFaces = emdm_ts_GetNumFaces;
+               sInterface.m_getNumVerticesOfFace = emdm_ts_GetNumVertsOfFace;
+               sInterface.m_getPosition = emdm_ts_GetPosition;
+               sInterface.m_getTexCoord = emdm_ts_GetTextureCoordinate;
+               sInterface.m_getNormal = emdm_ts_GetNormal;
+               sInterface.m_setTSpaceBasic = emdm_ts_SetTSpace;
+               /* 0 if failed */
+               genTangSpaceDefault(&sContext);
+       }
+}
+
 /**
  * \see #DM_calc_loop_tangents, same logic but used arrays instead of #BMesh data.
  *
  * \note This function is not so normal, its using `bm->ldata` as input, but output's to `dm->loopData`.
  * This is done because #CD_TANGENT is cache data used only for drawing.
  */
-static void emDM_calcLoopTangents(DerivedMesh *dm)
+
+static void emDM_calc_loop_tangents(
+        DerivedMesh *dm, bool calc_active_tangent,
+        const char (*tangent_names)[MAX_NAME], int tangent_names_count)
 {
        EditDerivedBMesh *bmdm = (EditDerivedBMesh *)dm;
        BMEditMesh *em = bmdm->em;
        BMesh *bm = bmdm->em->bm;
-
-       /* mesh vars */
-       int cd_loop_uv_offset;
-       float (*orco)[3] = NULL, (*tangent)[4];
-       int /* totvert, */ totface;
-       const float (*fnors)[3];
-       const float (*tlnors)[3];
-       char htype_index = BM_LOOP;
-
-       if (CustomData_get_layer_index(&dm->loopData, CD_TANGENT) != -1)
+       if (CustomData_number_of_layers(&bm->ldata, CD_MLOOPUV) == 0)
                return;
 
-       fnors = bmdm->polyNos;  /* dm->getPolyDataArray(dm, CD_NORMAL) */
-
-       /* Note, we assume we do have tessellated loop normals at this point (in case it is object-enabled),
-        * have to check this is valid...
-        */
-       tlnors = dm->getLoopDataArray(dm, CD_NORMAL);
-
-       /* check we have all the needed layers */
-       totface = em->tottri;
-
-       cd_loop_uv_offset = CustomData_get_offset(&bm->ldata, CD_MLOOPUV);
-
-       /* needed for indexing loop-tangents */
-       htype_index = BM_LOOP;
-       if (cd_loop_uv_offset == -1) {
-               orco = dm->getVertDataArray(dm, CD_ORCO);
-               if (!orco)
-                       return;
-               /* needed for orco lookups */
-               htype_index |= BM_VERT;
-       }
-
-       if (fnors) {
-               /* needed for face normal lookups */
-               htype_index |= BM_FACE;
-       }
-
-       BM_mesh_elem_index_ensure(bm, htype_index);
+       int act_uv_n = -1;
+       int ren_uv_n = -1;
+       bool calc_act = false;
+       bool calc_ren = false;
+       char act_uv_name[MAX_NAME];
+       char ren_uv_name[MAX_NAME];
+       char tangent_mask = 0;
+
+       DM_calc_loop_tangents_step_0(
+               &bm->ldata, calc_active_tangent, tangent_names, tangent_names_count,
+               &calc_act, &calc_ren, &act_uv_n, &ren_uv_n, act_uv_name, ren_uv_name, &tangent_mask);
+
+       if ((dm->tangent_mask | tangent_mask) != dm->tangent_mask) {
+               for (int i = 0; i < tangent_names_count; i++)
+                       if (tangent_names[i][0])
+                               DM_add_named_tangent_layer_for_uv(&bm->ldata, &dm->loopData, dm->numLoopData, tangent_names[i]);
+               if (calc_act && act_uv_name[0])
+                       DM_add_named_tangent_layer_for_uv(&bm->ldata, &dm->loopData, dm->numLoopData, act_uv_name);
+               if (calc_ren && ren_uv_name[0])
+                       DM_add_named_tangent_layer_for_uv(&bm->ldata, &dm->loopData, dm->numLoopData, ren_uv_name);
+               int totface = em->tottri;
+#ifdef USE_LOOPTRI_DETECT_QUADS
+               int num_face_as_quad_map;
+               int *face_as_quad_map = NULL;
 
-       /* create tangent layer */
-       DM_add_loop_layer(dm, CD_TANGENT, CD_CALLOC, NULL);
-       tangent = DM_get_loop_data_layer(dm, CD_TANGENT);
+               /* map faces to quads */
+               if (bmdm->em->tottri != bm->totface) {
+                       /* over alloc, since we dont know how many ngon or quads we have */
 
-#ifdef USE_LOOPTRI_DETECT_QUADS
-       int num_face_as_quad_map;
-       int *face_as_quad_map = NULL;
-
-       /* map faces to quads */
-       if (bmdm->em->tottri != bm->totface) {
-               /* over alloc, since we dont know how many ngon or quads we have */
-
-               /* map fake face index to looptri */
-               face_as_quad_map = MEM_mallocN(sizeof(int) * totface, __func__);
-               int i, j;
-               for (i = 0, j = 0; j < totface; i++, j++) {
-                       face_as_quad_map[i] = j;
-                       /* step over all quads */
-                       if (em->looptris[j][0]->f->len == 4) {
-                               j++;  /* skips the nest looptri */
+                       /* map fake face index to looptri */
+                       face_as_quad_map = MEM_mallocN(sizeof(int) * totface, __func__);
+                       int i, j;
+                       for (i = 0, j = 0; j < totface; i++, j++) {
+                               face_as_quad_map[i] = j;
+                               /* step over all quads */
+                               if (em->looptris[j][0]->f->len == 4) {
+                                       j++;  /* skips the nest looptri */
+                               }
                        }
+                       num_face_as_quad_map = i;
+               }
+               else {
+                       num_face_as_quad_map = totface;
                }
-               num_face_as_quad_map = i;
-       }
-       else {
-               num_face_as_quad_map = totface;
-       }
 #endif
-
-       /* new computation method */
-       {
-               SGLSLEditMeshToTangent mesh2tangent = {NULL};
-               SMikkTSpaceContext sContext = {NULL};
-               SMikkTSpaceInterface sInterface = {NULL};
-
-               mesh2tangent.precomputedFaceNormals = fnors;
-               mesh2tangent.precomputedLoopNormals = tlnors;
-               mesh2tangent.looptris = (const BMLoop *(*)[3])em->looptris;
-               mesh2tangent.cd_loop_uv_offset = cd_loop_uv_offset;
-               mesh2tangent.orco = (const float (*)[3])orco;
-               mesh2tangent.tangent = tangent;
-               mesh2tangent.numTessFaces = totface;
-
+               /* Calculation */
+               {
+                       TaskScheduler *scheduler = BLI_task_scheduler_get();
+                       TaskPool *task_pool;
+                       task_pool = BLI_task_pool_create(scheduler, NULL);
+
+                       dm->tangent_mask = 0;
+                       /* Calculate tangent layers */
+                       SGLSLEditMeshToTangent data_array[MAX_MTFACE];
+                       int index = 0;
+                       int n = 0;
+                       CustomData_update_typemap(&dm->loopData);
+                       const int tangent_layer_num = CustomData_number_of_layers(&dm->loopData, CD_TANGENT);
+                       for (n = 0; n < tangent_layer_num; n++) {
+                               index = CustomData_get_layer_index_n(&dm->loopData, CD_TANGENT, n);
+                               BLI_assert(n < MAX_MTFACE);
+                               SGLSLEditMeshToTangent *mesh2tangent = &data_array[n];
+                               mesh2tangent->numTessFaces = em->tottri;
 #ifdef USE_LOOPTRI_DETECT_QUADS
-               mesh2tangent.face_as_quad_map = face_as_quad_map;
-               mesh2tangent.num_face_as_quad_map = num_face_as_quad_map;
+                               mesh2tangent->face_as_quad_map = face_as_quad_map;
+                               mesh2tangent->num_face_as_quad_map = num_face_as_quad_map;
 #endif
+                               mesh2tangent->precomputedFaceNormals = bmdm->polyNos;  /* dm->getPolyDataArray(dm, CD_NORMAL) */
+                               /* Note, we assume we do have tessellated loop normals at this point (in case it is object-enabled),
+                                * have to check this is valid...
+                                */
+                               mesh2tangent->precomputedLoopNormals = CustomData_get_layer(&dm->loopData, CD_NORMAL);
+                               mesh2tangent->cd_loop_uv_offset = CustomData_get_n_offset(&bm->ldata, CD_MLOOPUV, n);
+
+                               /* needed for indexing loop-tangents */
+                               int htype_index = BM_LOOP;
+                               if (mesh2tangent->cd_loop_uv_offset == -1) {
+                                       mesh2tangent->orco = dm->getVertDataArray(dm, CD_ORCO);
+                                       if (!mesh2tangent->orco)
+                                               continue;
+                                       /* needed for orco lookups */
+                                       htype_index |= BM_VERT;
+                               }
+                               if (mesh2tangent->precomputedFaceNormals) {
+                                       /* needed for face normal lookups */
+                                       htype_index |= BM_FACE;
+                               }
+                               BM_mesh_elem_index_ensure(bm, htype_index);
+
+                               mesh2tangent->looptris = (const BMLoop *(*)[3])em->looptris;
+                               mesh2tangent->tangent = dm->loopData.layers[index].data;
+
+                               /* Fill the resulting tangent_mask */
+                               int uv_ind = CustomData_get_named_layer_index(&bm->ldata, CD_MLOOPUV, dm->loopData.layers[index].name);
+                               int uv_start = CustomData_get_layer_index(&bm->ldata, CD_MLOOPUV);
+                               BLI_assert(uv_ind != -1 && uv_start != -1);
+                               BLI_assert(uv_ind - uv_start < MAX_MTFACE);
+                               dm->tangent_mask |= 1 << (uv_ind - uv_start);
+                               BLI_task_pool_push(task_pool, emDM_calc_loop_tangents_thread, mesh2tangent, false, TASK_PRIORITY_LOW);
+                       }
 
-               sContext.m_pUserData = &mesh2tangent;
-               sContext.m_pInterface = &sInterface;
-               sInterface.m_getNumFaces = emdm_ts_GetNumFaces;
-               sInterface.m_getNumVerticesOfFace = emdm_ts_GetNumVertsOfFace;
-               sInterface.m_getPosition = emdm_ts_GetPosition;
-               sInterface.m_getTexCoord = emdm_ts_GetTextureCoordinate;
-               sInterface.m_getNormal = emdm_ts_GetNormal;
-               sInterface.m_setTSpaceBasic = emdm_ts_SetTSpace;
-
-               /* 0 if failed */
-               genTangSpaceDefault(&sContext);
-
+                       BLI_assert(dm->tangent_mask == tangent_mask);
+                       BLI_task_pool_work_and_wait(task_pool);
+                       BLI_task_pool_free(task_pool);
+               }
 #ifdef USE_LOOPTRI_DETECT_QUADS
                if (face_as_quad_map) {
                        MEM_freeN(face_as_quad_map);
@@ -570,6 +601,15 @@ static void emDM_calcLoopTangents(DerivedMesh *dm)
 #undef USE_LOOPTRI_DETECT_QUADS
 #endif
        }
+       /* Update active layer index */
+       int uv_index = CustomData_get_layer_index_n(&bm->ldata, CD_MLOOPUV, act_uv_n);
+       int tan_index = CustomData_get_named_layer_index(&dm->loopData, CD_TANGENT, bm->ldata.layers[uv_index].name);
+       CustomData_set_layer_active_index(&dm->loopData, CD_TANGENT, tan_index);
+
+       /* Update render layer index */
+       uv_index = CustomData_get_layer_index_n(&bm->ldata, CD_MLOOPUV, ren_uv_n);
+       tan_index = CustomData_get_named_layer_index(&dm->loopData, CD_TANGENT, bm->ldata.layers[uv_index].name);
+       CustomData_set_layer_render_index(&dm->loopData, CD_TANGENT, tan_index);
 }
 
 /** \} */
@@ -1419,15 +1459,16 @@ static void emdm_pass_attrib_vertex_glsl(const DMVertexAttribs *attribs, const B
                }
                glVertexAttrib4ubv(attribs->mcol[i].gl_index, col);
        }
-       if (attribs->tottang) {
+
+       for (i = 0; i < attribs->tottang; i++) {
                const float *tang;
-               if (attribs->tang.em_offset != -1) {
-                       tang = attribs->tang.array[BM_elem_index_get(loop)];
+               if (attribs->tang[i].em_offset != -1) {
+                       tang = attribs->tang[i].array[BM_elem_index_get(loop)];
                }
                else {
                        tang = zero;
                }
-               glVertexAttrib4fv(attribs->tang.gl_index, tang);
+               glVertexAttrib4fv(attribs->tang[i].gl_index, tang);
        }
 }
 
@@ -2218,7 +2259,7 @@ DerivedMesh *getEditDerivedBMesh(
        bmdm->dm.calcNormals = emDM_calcNormals;
        bmdm->dm.calcLoopNormals = emDM_calcLoopNormals;
        bmdm->dm.calcLoopNormalsSpaceArray = emDM_calcLoopNormalsSpaceArray;
-       bmdm->dm.calcLoopTangents = emDM_calcLoopTangents;
+       bmdm->dm.calcLoopTangents = emDM_calc_loop_tangents;
        bmdm->dm.recalcTessellation = emDM_recalcTessellation;
        bmdm->dm.recalcLoopTri = emDM_recalcLoopTri;
 
index 809b45d4b36fc319dd2eca7b41de020382e21505..1fec725dbb7c6177f02e3dcde0bda89c831b2934 100644 (file)
@@ -1148,7 +1148,7 @@ static void init_render_nodetree(bNodeTree *ntree, Material *basemat, int r_mode
 
        /* parses the geom+tex nodes */
        ntreeShaderGetTexcoMode(ntree, r_mode, &basemat->texco, &basemat->mode_l);
-
+       basemat->nmap_tangent_names_count = 0;
        for (node = ntree->nodes.first; node; node = node->next) {
                if (node->id) {
                        if (GS(node->id->name) == ID_MA) {
@@ -1170,6 +1170,21 @@ static void init_render_nodetree(bNodeTree *ntree, Material *basemat, int r_mode
                        else if (node->type == NODE_GROUP)
                                init_render_nodetree((bNodeTree *)node->id, basemat, r_mode, amb);
                }
+               else if (node->typeinfo->type == SH_NODE_NORMAL_MAP) {
+                       basemat->mode2_l |= MA_TANGENT_CONCRETE;
+                       NodeShaderNormalMap *nm = node->storage;
+                       bool taken_into_account = false;
+                       for (int i = 0; i < basemat->nmap_tangent_names_count; i++) {
+                               if (STREQ(basemat->nmap_tangent_names[i], nm->uv_map)) {
+                                       taken_into_account = true;
+                                       break;
+                               }
+                       }
+                       if (!taken_into_account) {
+                               BLI_assert(basemat->nmap_tangent_names_count < MAX_MTFACE + 1);
+                               strcpy(basemat->nmap_tangent_names[basemat->nmap_tangent_names_count++], nm->uv_map);
+                       }
+               }
        }
 }
 
index 83e020cf2ea7c31da3df7ca1e7c0745eaa42bd47..577a21285f8b2f7e8893c13c6584d960f1f87763 100644 (file)
@@ -2417,30 +2417,42 @@ void BKE_mesh_loops_to_tessdata(CustomData *fdata, CustomData *ldata, CustomData
        }
 }
 
-void BKE_mesh_tangent_loops_to_tessdata(CustomData *fdata, CustomData *ldata, MFace *mface,
-                                        int *polyindices, unsigned int (*loopindices)[4], const int num_faces)
+void BKE_mesh_tangent_loops_to_tessdata(
+        CustomData *fdata, CustomData *ldata, MFace *mface,
+        int *polyindices, unsigned int (*loopindices)[4], const int num_faces, const char *layer_name)
 {
        /* Note: performances are sub-optimal when we get a NULL mface, we could be ~25% quicker with dedicated code...
         *       Issue is, unless having two different functions with nearly the same code, there's not much ways to solve
         *       this. Better imho to live with it for now. :/ --mont29
         */
-       const bool hasLoopTangent = CustomData_has_layer(ldata, CD_TANGENT);
+
+       float (*ftangents)[4] = NULL;
+       float (*ltangents)[4] = NULL;
+
        int findex, j;
        const int *pidx;
        unsigned int (*lidx)[4];
 
-       if (hasLoopTangent) {
-               /* need to do for all uv maps at some point */
-               float (*ftangents)[4] = CustomData_get_layer(fdata, CD_TANGENT);
-               float (*ltangents)[4] = CustomData_get_layer(ldata, CD_TANGENT);
+       if (layer_name)
+               ltangents = CustomData_get_layer_named(ldata, CD_TANGENT, layer_name);
+       else
+               ltangents = CustomData_get_layer(ldata, CD_TANGENT);
 
-               for (findex = 0, pidx = polyindices, lidx = loopindices;
-                    findex < num_faces;
-                    pidx++, lidx++, findex++)
-               {
-                       int nverts = (mface ? mface[findex].v4 : (*lidx)[3]) ? 4 : 3;
-                       for (j = nverts; j--;) {
-                               copy_v4_v4(ftangents[findex * 4 + j], ltangents[(*lidx)[j]]);
+       if (ltangents) {
+               /* need to do for all uv maps at some point */
+               if (layer_name)
+                       ftangents = CustomData_get_layer_named(fdata, CD_TANGENT, layer_name);
+               else
+                       ftangents = CustomData_get_layer(fdata, CD_TANGENT);
+               if (ftangents) {
+                       for (findex = 0, pidx = polyindices, lidx = loopindices;
+                            findex < num_faces;
+                            pidx++, lidx++, findex++)
+                       {
+                               int nverts = (mface ? mface[findex].v4 : (*lidx)[3]) ? 4 : 3;
+                               for (j = nverts; j--;) {
+                                       copy_v4_v4(ftangents[findex * 4 + j], ltangents[(*lidx)[j]]);
+                               }
                        }
                }
        }
index 979943324114514ac6f2641e400cb87a2ad5b555..daa667fba71cdc6369dd457771cd5c4d87153129 100644 (file)
@@ -3016,11 +3016,13 @@ static void ccgDM_drawMappedFacesGLSL(DerivedMesh *dm,
                                                numdata++;
                                        }
                                }
-                               if (matconv[a].attribs.tottang && matconv[a].attribs.tang.array) {
-                                       matconv[a].datatypes[numdata].index = matconv[a].attribs.tang.gl_index;
-                                       matconv[a].datatypes[numdata].size = 4;
-                                       matconv[a].datatypes[numdata].type = GL_FLOAT;
-                                       numdata++;
+                               for (b = 0; b < matconv[a].attribs.tottang; b++) {
+                                       if (matconv[a].attribs.tottang && matconv[a].attribs.tang[b].array) {
+                                               matconv[a].datatypes[numdata].index = matconv[a].attribs.tang[b].gl_index;
+                                               matconv[a].datatypes[numdata].size = 4;
+                                               matconv[a].datatypes[numdata].type = GL_FLOAT;
+                                               numdata++;
+                                       }
                                }
                                if (numdata != 0) {
                                        matconv[a].numdata = numdata;
@@ -3105,15 +3107,17 @@ static void ccgDM_drawMappedFacesGLSL(DerivedMesh *dm,
                                                                                offset += sizeof(unsigned char) * 4;
                                                                        }
                                                                }
-                                                               if (matconv[i].attribs.tottang && matconv[i].attribs.tang.array) {
-                                                                       const float (*looptang)[4] = (const float (*)[4])matconv[i].attribs.tang.array + tot_loops;
+                                                               for (b = 0; b < matconv[i].attribs.tottang; b++) {
+                                                                       if (matconv[i].attribs.tottang && matconv[i].attribs.tang[b].array) {
+                                                                               const float (*looptang)[4] = (const float (*)[4])matconv[i].attribs.tang[b].array + tot_loops;
 
-                                                                       copy_v4_v4((float *)&varray[offset], looptang[0]);
-                                                                       copy_v4_v4((float *)&varray[offset + max_element_size], looptang[3]);
-                                                                       copy_v4_v4((float *)&varray[offset + 2 * max_element_size], looptang[2]);
-                                                                       copy_v4_v4((float *)&varray[offset + 3 * max_element_size], looptang[1]);
+                                                                               copy_v4_v4((float *)&varray[offset], looptang[0]);
+                                                                               copy_v4_v4((float *)&varray[offset + max_element_size], looptang[3]);
+                                                                               copy_v4_v4((float *)&varray[offset + 2 * max_element_size], looptang[2]);
+                                                                               copy_v4_v4((float *)&varray[offset + 3 * max_element_size], looptang[1]);
 
-                                                                       offset += sizeof(float) * 4;
+                                                                               offset += sizeof(float) * 4;
+                                                                       }
                                                                }
 
                                                                tot_loops += 4;
index 18468c1674f155adc378ff0cf23a3e1cfe41485f..72a59e6843de82663e6d14343083d197c4b61f5d 100644 (file)
@@ -135,6 +135,13 @@ void linearrgb_to_srgb(vec4 col_from, out vec4 col_to)
        col_to.a = col_from.a;
 }
 
+void color_to_normal(vec3 color, out vec3 normal)
+{
+       normal.x =  2.0 * ((color.r) - 0.5);
+       normal.y = -2.0 * ((color.g) - 0.5);
+       normal.z =  2.0 * ((color.b) - 0.5);
+}
+
 #define M_PI 3.14159265358979323846
 #define M_1_PI 0.31830988618379069
 
@@ -369,6 +376,10 @@ void vec_math_average(vec3 v1, vec3 v2, out vec3 outvec, out float outval)
        outval = length(outvec);
        outvec = normalize(outvec);
 }
+void vec_math_mix(float strength, vec3 v1, vec3 v2, out vec3 outvec)
+{
+       outvec = strength*v1 + (1 - strength) * v2;
+}
 
 void vec_math_dot(vec3 v1, vec3 v2, out vec3 outvec, out float outval)
 {
@@ -2701,9 +2712,12 @@ void node_object_info(out vec3 location, out float object_index, out float mater
        random = 0.0;
 }
 
-void node_normal_map(float strength, vec4 color, vec3 N, out vec3 result)
+void node_normal_map(vec4 tangent, vec3 normal, vec3 texnormal, out vec3 outnormal)
 {
-       result = N;
+       vec3 B = tangent.w * cross(normal, tangent.xyz);
+
+       outnormal = texnormal.x * tangent.xyz + texnormal.y * B + texnormal.z * normal;
+       outnormal = normalize(outnormal);
 }
 
 void node_bump(float strength, float dist, float height, vec3 N, out vec3 result)
index 8790f7366004f6d457474b3f32605094c666ea0d..0c500e366a7b7b89fc794fc94698536929b742d7 100644 (file)
@@ -197,6 +197,10 @@ typedef struct Material {
        short tot_slots;
        short pad4[3];
 
+       /* multiple tangent (Normal Map node) */
+       char nmap_tangent_names[9][64]; /* [MAX_MTFACE+1][MAX_NAME]; +1 for empty name */
+       int nmap_tangent_names_count, pad5;
+
        struct TexPaintSlot *texpaintslot; /* cached slot for painting. Make sure to recalculate before use
                                            * with refresh_texpaint_image_cache */
        ListBase gpumaterial;           /* runtime */
@@ -305,6 +309,7 @@ typedef struct Material {
 /* mode2 (is int) */
 #define MA_CASTSHADOW          (1 << 0)
 #define MA_MODE2_PIPELINE      (MA_CASTSHADOW)
+#define MA_TANGENT_CONCRETE    (1 << 1)
 
 /* mapflag */
 #define MA_MAPFLAG_UVPROJECT (1 << 0)
index 13bf2a0fe43479f309319b45546902e768dae0ea..c65fac7f09bc8bd963297a73120292b33408b9fe 100644 (file)
@@ -46,12 +46,127 @@ static void node_shader_init_normal_map(bNodeTree *UNUSED(ntree), bNode *node)
        node->storage = attr;
 }
 
-static int gpu_shader_normal_map(GPUMaterial *mat, bNode *UNUSED(node), bNodeExecData *UNUSED(execdata), GPUNodeStack *in, GPUNodeStack *out)
+static void node_shader_exec_normal_map(void *data, int UNUSED(thread), bNode *node, bNodeExecData *UNUSED(execdata), bNodeStack **in, bNodeStack **out)
+ {
+    float vecIn[3];
+    float strength;
+    float B[4];
+    float *T;
+    float *N;
+    int j;
+
+       if (data) {
+               ShadeInput *shi = ((ShaderCallData *)data)->shi;
+
+               NodeShaderNormalMap *nm = node->storage;
+
+               nodestack_get_vec(&strength, SOCK_FLOAT, in[0]);
+               nodestack_get_vec(vecIn, SOCK_VECTOR, in[1]);
+
+               vecIn[0] = -2 * (vecIn[0] - 0.5f);
+               vecIn[1] =  2 * (vecIn[1] - 0.5f);
+               vecIn[2] =  2 * (vecIn[2] - 0.5f);
+
+               CLAMP_MIN(strength, 0.0f);
+
+               N = shi->vno;
+               int uv_index = 0;
+               switch (nm->space) {
+                       case SHD_NORMAL_MAP_TANGENT:
+                               if (nm->uv_map[0]) {
+                                       /* find uv map by name */
+                                       for (int i = 0; i < shi->totuv; i++) {
+                                               if (STREQ(shi->uv[i].name, nm->uv_map)) {
+                                                       uv_index = i;
+                                                       break;
+                                               }
+                                       }
+                               }
+                               else {
+                                       uv_index = shi->actuv;
+                               }
+
+                               T = shi->tangents[uv_index];
+
+                               cross_v3_v3v3(B, N, T);
+                               mul_v3_fl(B, T[3]);
+
+                               for (j = 0; j < 3; j++)
+                                       out[0]->vec[j] = vecIn[0] * T[j] + vecIn[1] * B[j] + vecIn[2] * N[j];
+                               interp_v3_v3v3(out[0]->vec, N, out[0]->vec, strength);
+                               break;
+
+                       case SHD_NORMAL_MAP_OBJECT:
+                       case SHD_NORMAL_MAP_BLENDER_OBJECT:
+                               mul_mat3_m4_v3((float (*)[4])RE_object_instance_get_matrix(shi->obi, RE_OBJECT_INSTANCE_MATRIX_LOCALTOVIEW), vecIn);
+                               interp_v3_v3v3(out[0]->vec, N, vecIn, strength);
+                               break;
+
+                       case SHD_NORMAL_MAP_WORLD:
+                       case SHD_NORMAL_MAP_BLENDER_WORLD:
+                               mul_mat3_m4_v3((float (*)[4])RE_render_current_get_matrix(RE_VIEW_MATRIX), vecIn);
+                               interp_v3_v3v3(out[0]->vec, N, vecIn, strength);
+                               break;
+               }
+               normalize_v3(out[0]->vec);
+       }
+}
+
+static int gpu_shader_normal_map(GPUMaterial *mat, bNode *node, bNodeExecData *UNUSED(execdata), GPUNodeStack *in, GPUNodeStack *out)
 {
-       GPUNodeLink *normal;
-       GPU_link(mat, "direction_transform_m4v3", GPU_builtin(GPU_VIEW_NORMAL), GPU_builtin(GPU_INVERSE_VIEW_MATRIX), &normal);
+       int r;
+       NodeShaderNormalMap *nm = node->storage;
+       GPUNodeLink *negnorm;
+       GPUNodeLink *realnorm;
+       GPUNodeLink *strength;
+
+       float d[4] = {0, 0, 0, 0};
+
+       if (in[0].link)
+               strength = in[0].link;
+       else
+               strength = GPU_uniform(in[0].vec);
+
+       if (in[1].link) {
+               r = GPU_link(mat, "color_to_normal", in[1].link, &realnorm);
+               if (!r) return r;
+               r = GPU_link(mat, "mtex_negate_texnormal", realnorm,  &realnorm);
+       }
+       else
+               r = 1;
+
+       GPU_link(mat, "math_max", strength, GPU_uniform(d), &strength);
+       GPU_link(mat, "vec_math_negate", GPU_builtin(GPU_VIEW_NORMAL), &negnorm);
+       switch (nm->space) {
+               case SHD_NORMAL_MAP_TANGENT:
+                       if (in[1].link) {
+                               r = GPU_link(mat, "node_normal_map", GPU_attribute(CD_TANGENT, nm->uv_map), negnorm, realnorm, &out[0].link);
+                               if (!r) return r;
+                       }
+                       break;
+               case SHD_NORMAL_MAP_OBJECT:
+               case SHD_NORMAL_MAP_BLENDER_OBJECT:
+                       if (in[1].link) {
+                               r = GPU_link(mat, "direction_transform_m4v3", realnorm, GPU_builtin(GPU_LOC_TO_VIEW_MATRIX),  &out[0].link);
+                               if (!r) return r;
+                       }
+                       break;
+               case SHD_NORMAL_MAP_WORLD:
+               case SHD_NORMAL_MAP_BLENDER_WORLD:
+                       if (in[1].link) {
+                               r = GPU_link(mat, "direction_transform_m4v3", realnorm, GPU_builtin(GPU_VIEW_MATRIX),  &out[0].link);
+                               if (!r) return r;
+                       }
+                       break;
+       }
+       if (out[0].link) {
+               r = GPU_link(mat, "vec_math_mix", strength, out[0].link, negnorm,  &out[0].link);
+               if (!r) return r;
 
-       return GPU_stack_link(mat, "node_normal_map", in, out, normal);
+               r = GPU_link(mat, "vect_normalize", out[0].link, &out[0].link);
+               if (!r) return r;
+       }
+       return r;
 }
 
 /* node type definition */
@@ -60,12 +175,13 @@ void register_node_type_sh_normal_map(void)
        static bNodeType ntype;
 
        sh_node_type_base(&ntype, SH_NODE_NORMAL_MAP, "Normal Map", NODE_CLASS_OP_VECTOR, 0);
-       node_type_compatibility(&ntype, NODE_NEW_SHADING);
+       node_type_compatibility(&ntype, NODE_NEW_SHADING | NODE_OLD_SHADING);
        node_type_socket_templates(&ntype, sh_node_normal_map_in, sh_node_normal_map_out);
        node_type_size_preset(&ntype, NODE_SIZE_MIDDLE);
        node_type_init(&ntype, node_shader_init_normal_map);
        node_type_storage(&ntype, "NodeShaderNormalMap", node_free_standard_storage, node_copy_standard_storage);
        node_type_gpu(&ntype, gpu_shader_normal_map);
+       node_type_exec(&ntype, NULL, NULL, node_shader_exec_normal_map);
 
        nodeRegisterType(&ntype);
 }
index 12b97aedbd30cc3702d015d8b7ff9ef6d805699f..8b6dfb88b73938a7a7cf69433908854a822f645d 100644 (file)
@@ -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 */
index cef3a073084c6aec3c67ee50ee139807d966aaee..6de5da3795a1b2fdfd5bc44c8d4229e797f37115 100644 (file)
@@ -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 */
index 167ebc580305aa904e46fb5234ee183f0412569d..b576d69d80642f974530e525a851a19d7230c6c1 100644 (file)
@@ -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);
 
index eff021c9b14970482fed1417e226823a6ce547a7..1a0ef4e64d4ca692f4528642b4a1d353c257b321 100644 (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);
index ccf54cb6bcd0c395a144215a1b37780b4fa0e8f0..b6ee88de29017aaf8917c311c06f47508f19883e 100644 (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);
index 8eb6e7000ab0976d342dfe60d4494f2218abd6c8..8c6d9c5f951f5630ed4503c329290652604c369a 100644 (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);
                }
index e8db096c9a557c01ec577eae4f0028a1d0d46043..d3d26011a57770e561daf795750307a7855626fe 100644 (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);
        }
index e60a5a70a7fea4bbaa0d4c7ca291d880d7849976..6e01921a6a7aa32b9f876b65f49ab6ca540a7923 100644 (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];
+                                       }
+                               }
                        }
                }
        }
index c2cfd8808a9443e99d68449362054b73cbaa1e56..ec99de45918a63c49bc3f86848b7d6cc92d61583 100644 (file)
@@ -962,7 +962,7 @@ RAS_MeshObject* BL_ConvertMesh(Mesh* mesh, Object* blenderobj, KX_Scene* scene,
                if (CustomData_get_layer_index(&dm->faceData, CD_TANGENT) == -1) {
                        bool generate_data = false;
                        if (CustomData_get_layer_index(&dm->loopData, CD_TANGENT) == -1) {
-                               DM_calc_loop_tangents(dm);
+                               DM_calc_loop_tangents(dm, true, NULL, 0);
                                generate_data = true;
                        }
                        DM_generate_tangent_tessface_data(dm, generate_data);