From 5abae51a6ef5b0f1b817ef5ce4bff34fef5001cd Mon Sep 17 00:00:00 2001 From: Alexander Romanov Date: Tue, 26 Apr 2016 18:43:02 +1000 Subject: 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. --- release/scripts/startup/nodeitems_builtins.py | 1 + source/blender/blenkernel/BKE_DerivedMesh.h | 24 +- source/blender/blenkernel/BKE_mesh.h | 5 +- source/blender/blenkernel/intern/DerivedMesh.c | 402 ++++++++++++++------- source/blender/blenkernel/intern/cdderivedmesh.c | 24 +- source/blender/blenkernel/intern/customdata.c | 2 +- source/blender/blenkernel/intern/editderivedmesh.c | 235 +++++++----- source/blender/blenkernel/intern/material.c | 17 +- source/blender/blenkernel/intern/mesh_evaluate.c | 40 +- source/blender/blenkernel/intern/subsurf_ccg.c | 28 +- .../blender/gpu/shaders/gpu_shader_material.glsl | 18 +- source/blender/makesdna/DNA_material_types.h | 5 + .../nodes/shader/nodes/node_shader_normal_map.c | 126 ++++++- .../blender/render/extern/include/RE_shader_ext.h | 1 + .../blender/render/intern/include/render_types.h | 2 + .../blender/render/intern/include/renderdatabase.h | 4 +- source/blender/render/intern/source/bake_api.c | 2 +- .../blender/render/intern/source/convertblender.c | 60 +-- .../blender/render/intern/source/multires_bake.c | 2 +- .../blender/render/intern/source/renderdatabase.c | 41 ++- source/blender/render/intern/source/shadeinput.c | 37 +- .../Converter/BL_BlenderDataConversion.cpp | 2 +- 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; vindextype == 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; vindextype == 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); -- cgit v1.2.3