diff options
author | Alexander Romanov <a.romanov@blend4web.com> | 2016-04-26 11:43:02 +0300 |
---|---|---|
committer | Campbell Barton <ideasman42@gmail.com> | 2016-04-26 13:43:29 +0300 |
commit | 5abae51a6ef5b0f1b817ef5ce4bff34fef5001cd (patch) | |
tree | ca6d8f3595fd596fe978e4ad69a29bbc647be121 /source/blender/blenkernel/intern/editderivedmesh.c | |
parent | 98babfa2b86f768ebc0cff6c0d8ec34e18afd2af (diff) |
Support multiple tangents for BI render & viewport
Normal Map node support for GLSL mode and the internal render (multiple tangents support).
The Normal Map node is a useful node which is present in the Cycles render.
It makes it possible to use normal mapping without additional material node in a node tree.
This patch implements Normal Map node for GLSL mode and the internal render.
Previously only the active UV layer was used to calculate tangents.
Diffstat (limited to 'source/blender/blenkernel/intern/editderivedmesh.c')
-rw-r--r-- | source/blender/blenkernel/intern/editderivedmesh.c | 235 |
1 files changed, 138 insertions, 97 deletions
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; |