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

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlexander Romanov <a.romanov@blend4web.com>2016-04-26 11:43:02 +0300
committerCampbell Barton <ideasman42@gmail.com>2016-04-26 13:43:29 +0300
commit5abae51a6ef5b0f1b817ef5ce4bff34fef5001cd (patch)
treeca6d8f3595fd596fe978e4ad69a29bbc647be121
parent98babfa2b86f768ebc0cff6c0d8ec34e18afd2af (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.
-rw-r--r--release/scripts/startup/nodeitems_builtins.py1
-rw-r--r--source/blender/blenkernel/BKE_DerivedMesh.h24
-rw-r--r--source/blender/blenkernel/BKE_mesh.h5
-rw-r--r--source/blender/blenkernel/intern/DerivedMesh.c402
-rw-r--r--source/blender/blenkernel/intern/cdderivedmesh.c24
-rw-r--r--source/blender/blenkernel/intern/customdata.c2
-rw-r--r--source/blender/blenkernel/intern/editderivedmesh.c235
-rw-r--r--source/blender/blenkernel/intern/material.c17
-rw-r--r--source/blender/blenkernel/intern/mesh_evaluate.c40
-rw-r--r--source/blender/blenkernel/intern/subsurf_ccg.c28
-rw-r--r--source/blender/gpu/shaders/gpu_shader_material.glsl18
-rw-r--r--source/blender/makesdna/DNA_material_types.h5
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_normal_map.c126
-rw-r--r--source/blender/render/extern/include/RE_shader_ext.h1
-rw-r--r--source/blender/render/intern/include/render_types.h2
-rw-r--r--source/blender/render/intern/include/renderdatabase.h4
-rw-r--r--source/blender/render/intern/source/bake_api.c2
-rw-r--r--source/blender/render/intern/source/convertblender.c60
-rw-r--r--source/blender/render/intern/source/multires_bake.c2
-rw-r--r--source/blender/render/intern/source/renderdatabase.c41
-rw-r--r--source/blender/render/intern/source/shadeinput.c37
-rw-r--r--source/gameengine/Converter/BL_BlenderDataConversion.cpp2
22 files changed, 744 insertions, 334 deletions
diff --git a/release/scripts/startup/nodeitems_builtins.py b/release/scripts/startup/nodeitems_builtins.py
index 780662148e0..9dca55ede00 100644
--- a/release/scripts/startup/nodeitems_builtins.py
+++ b/release/scripts/startup/nodeitems_builtins.py
@@ -160,6 +160,7 @@ shader_node_categories = [
NodeItem("ShaderNodeMapping"),
NodeItem("ShaderNodeVectorCurve"),
NodeItem("ShaderNodeVectorTransform"),
+ NodeItem("ShaderNodeNormalMap"),
]),
ShaderOldNodeCategory("SH_CONVERTOR", "Converter", items=[
NodeItem("ShaderNodeValToRGB"),
diff --git a/source/blender/blenkernel/BKE_DerivedMesh.h b/source/blender/blenkernel/BKE_DerivedMesh.h
index d7d6daa7e2a..7419b182c04 100644
--- a/source/blender/blenkernel/BKE_DerivedMesh.h
+++ b/source/blender/blenkernel/BKE_DerivedMesh.h
@@ -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 */
diff --git a/source/blender/blenkernel/BKE_mesh.h b/source/blender/blenkernel/BKE_mesh.h
index a8f20a4ebc5..ac1f1576eba 100644
--- a/source/blender/blenkernel/BKE_mesh.h
+++ b/source/blender/blenkernel/BKE_mesh.h
@@ -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,
diff --git a/source/blender/blenkernel/intern/DerivedMesh.c b/source/blender/blenkernel/intern/DerivedMesh.c
index d120678c005..57926e6a56a 100644
--- a/source/blender/blenkernel/intern/DerivedMesh.c
+++ b/source/blender/blenkernel/intern/DerivedMesh.c
@@ -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);
+ }
}
}
diff --git a/source/blender/blenkernel/intern/cdderivedmesh.c b/source/blender/blenkernel/intern/cdderivedmesh.c
index 519b7b44637..e6741657f47 100644
--- a/source/blender/blenkernel/intern/cdderivedmesh.c
+++ b/source/blender/blenkernel/intern/cdderivedmesh.c
@@ -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;
+ }
}
}
diff --git a/source/blender/blenkernel/intern/customdata.c b/source/blender/blenkernel/intern/customdata.c
index a12d5434b30..b0d0dc08126 100644
--- a/source/blender/blenkernel/intern/customdata.c
+++ b/source/blender/blenkernel/intern/customdata.c
@@ -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,
diff --git a/source/blender/blenkernel/intern/editderivedmesh.c b/source/blender/blenkernel/intern/editderivedmesh.c
index 96bdfe88722..6c117447664 100644
--- a/source/blender/blenkernel/intern/editderivedmesh.c
+++ b/source/blender/blenkernel/intern/editderivedmesh.c
@@ -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;
diff --git a/source/blender/blenkernel/intern/material.c b/source/blender/blenkernel/intern/material.c
index 809b45d4b36..1fec725dbb7 100644
--- a/source/blender/blenkernel/intern/material.c
+++ b/source/blender/blenkernel/intern/material.c
@@ -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);
+ }
+ }
}
}
diff --git a/source/blender/blenkernel/intern/mesh_evaluate.c b/source/blender/blenkernel/intern/mesh_evaluate.c
index 83e020cf2ea..577a21285f8 100644
--- a/source/blender/blenkernel/intern/mesh_evaluate.c
+++ b/source/blender/blenkernel/intern/mesh_evaluate.c
@@ -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]]);
+ }
}
}
}
diff --git a/source/blender/blenkernel/intern/subsurf_ccg.c b/source/blender/blenkernel/intern/subsurf_ccg.c
index 97994332411..daa667fba71 100644
--- a/source/blender/blenkernel/intern/subsurf_ccg.c
+++ b/source/blender/blenkernel/intern/subsurf_ccg.c
@@ -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;
diff --git a/source/blender/gpu/shaders/gpu_shader_material.glsl b/source/blender/gpu/shaders/gpu_shader_material.glsl
index 18468c1674f..72a59e6843d 100644
--- a/source/blender/gpu/shaders/gpu_shader_material.glsl
+++ b/source/blender/gpu/shaders/gpu_shader_material.glsl
@@ -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)
diff --git a/source/blender/makesdna/DNA_material_types.h b/source/blender/makesdna/DNA_material_types.h
index 8790f736600..0c500e366a7 100644
--- a/source/blender/makesdna/DNA_material_types.h
+++ b/source/blender/makesdna/DNA_material_types.h
@@ -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)
diff --git a/source/blender/nodes/shader/nodes/node_shader_normal_map.c b/source/blender/nodes/shader/nodes/node_shader_normal_map.c
index 13bf2a0fe43..c65fac7f09b 100644
--- a/source/blender/nodes/shader/nodes/node_shader_normal_map.c
+++ b/source/blender/nodes/shader/nodes/node_shader_normal_map.c
@@ -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);
}
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];
+ }
+ }
}
}
}
diff --git a/source/gameengine/Converter/BL_BlenderDataConversion.cpp b/source/gameengine/Converter/BL_BlenderDataConversion.cpp
index c2cfd8808a9..ec99de45918 100644
--- a/source/gameengine/Converter/BL_BlenderDataConversion.cpp
+++ b/source/gameengine/Converter/BL_BlenderDataConversion.cpp
@@ -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);