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 /source/blender/blenkernel/intern/DerivedMesh.c
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.
Diffstat (limited to 'source/blender/blenkernel/intern/DerivedMesh.c')
-rw-r--r--source/blender/blenkernel/intern/DerivedMesh.c402
1 files changed, 268 insertions, 134 deletions
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);
+ }
}
}