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:
Diffstat (limited to 'source/blender')
-rw-r--r--source/blender/blenkernel/BKE_mesh.h7
-rw-r--r--source/blender/blenkernel/intern/DerivedMesh.c2
-rw-r--r--source/blender/blenkernel/intern/customdata.c6
-rw-r--r--source/blender/blenkernel/intern/mesh_evaluate.c145
-rw-r--r--source/blender/makesdna/DNA_customdata_types.h7
-rw-r--r--source/blender/makesrna/intern/rna_mesh.c43
-rw-r--r--source/blender/makesrna/intern/rna_mesh_api.c40
7 files changed, 243 insertions, 7 deletions
diff --git a/source/blender/blenkernel/BKE_mesh.h b/source/blender/blenkernel/BKE_mesh.h
index 500b3d8cab5..e82689ec339 100644
--- a/source/blender/blenkernel/BKE_mesh.h
+++ b/source/blender/blenkernel/BKE_mesh.h
@@ -58,6 +58,7 @@ struct UvVertMap;
struct UvMapVert;
struct UvElementMap;
struct UvElement;
+struct ReportList;
#ifdef __cplusplus
extern "C" {
@@ -172,6 +173,12 @@ void BKE_mesh_normals_loop_split(
struct MVert *mverts, const int numVerts, struct MEdge *medges, const int numEdges,
struct MLoop *mloops, float (*r_loopnors)[3], const int numLoops,
struct MPoly *mpolys, float (*polynors)[3], const int numPolys, float split_angle);
+void BKE_mesh_loop_tangents_ex(
+ struct MVert *mverts, const int numVerts, struct MLoop *mloops, float (*r_looptangent)[4], float (*loopnors)[3],
+ struct MLoopUV *loopuv, const int numLoops, struct MPoly *mpolys, const int numPolys,
+ struct ReportList *reports);
+void BKE_mesh_loop_tangents(
+ struct Mesh *mesh, const char *uvmap, float (*r_looptangents)[4], struct ReportList *reports);
void BKE_mesh_calc_poly_normal(
struct MPoly *mpoly, struct MLoop *loopstart,
diff --git a/source/blender/blenkernel/intern/DerivedMesh.c b/source/blender/blenkernel/intern/DerivedMesh.c
index 341e8e671c7..8796bd54bd3 100644
--- a/source/blender/blenkernel/intern/DerivedMesh.c
+++ b/source/blender/blenkernel/intern/DerivedMesh.c
@@ -2612,6 +2612,7 @@ static void GetNormal(const SMikkTSpaceContext *pContext, float r_no[3], const i
normal_short_to_float_v3(r_no, no);
}
}
+
static void SetTSpace(const SMikkTSpaceContext *pContext, const float fvTangent[3], const float fSign, const int face_num, const int iVert)
{
//assert(vert_index >= 0 && vert_index < 4);
@@ -2621,7 +2622,6 @@ static void SetTSpace(const SMikkTSpaceContext *pContext, const float fvTangent[
pRes[3] = fSign;
}
-
void DM_add_tangent_layer(DerivedMesh *dm)
{
/* mesh vars */
diff --git a/source/blender/blenkernel/intern/customdata.c b/source/blender/blenkernel/intern/customdata.c
index 441a2b410ad..39b1a946720 100644
--- a/source/blender/blenkernel/intern/customdata.c
+++ b/source/blender/blenkernel/intern/customdata.c
@@ -1168,7 +1168,9 @@ static const LayerTypeInfo LAYERTYPEINFO[CD_NUMTYPES] = {
/* 37: CD_FREESTYLE_EDGE */
{sizeof(FreestyleEdge), "FreestyleEdge", 1, NULL, NULL, NULL, NULL, NULL, NULL},
/* 38: CD_FREESTYLE_FACE */
- {sizeof(FreestyleFace), "FreestyleFace", 1, NULL, NULL, NULL, NULL, NULL, NULL}
+ {sizeof(FreestyleFace), "FreestyleFace", 1, NULL, NULL, NULL, NULL, NULL, NULL},
+ /* 39: CD_MLOOPTANGENT */
+ {sizeof(float[4]), "", 0, NULL, NULL, NULL, NULL, NULL, NULL},
};
/* note, numbers are from trunk and need updating for bmesh */
@@ -1184,7 +1186,7 @@ static const char *LAYERTYPENAMES[CD_NUMTYPES] = {
/* 25-29 */ "CDMPoly", "CDMLoop", "CDShapeKeyIndex", "CDShapeKey", "CDBevelWeight",
/* 30-34 */ "CDSubSurfCrease", "CDOrigSpaceLoop", "CDPreviewLoopCol", "CDBMElemPyPtr", "CDPaintMask",
/* 35-36 */ "CDGridPaintMask", "CDMVertSkin",
- /* 37-38 */ "CDFreestyleEdge", "CDFreestyleFace"
+ /* 37-38 */ "CDFreestyleEdge", "CDFreestyleFace", "CDMLoopTangent",
};
diff --git a/source/blender/blenkernel/intern/mesh_evaluate.c b/source/blender/blenkernel/intern/mesh_evaluate.c
index 24362c1a817..9bafc9c4cb1 100644
--- a/source/blender/blenkernel/intern/mesh_evaluate.c
+++ b/source/blender/blenkernel/intern/mesh_evaluate.c
@@ -50,9 +50,11 @@
#include "BKE_customdata.h"
#include "BKE_mesh.h"
#include "BKE_multires.h"
+#include "BKE_report.h"
#include "BLI_strict_flags.h"
+#include "mikktspace.h"
// #define DEBUG_TIME
@@ -577,6 +579,149 @@ void BKE_mesh_normals_loop_split(MVert *mverts, const int UNUSED(numVerts), MEdg
/* -------------------------------------------------------------------- */
+/** \name Mesh Tangent Calculations
+ * \{ */
+
+/* Tangent space utils. */
+
+/* User data. */
+typedef struct {
+ MPoly *mpolys; /* faces */
+ MLoop *mloops; /* faces's vertices */
+ MVert *mverts; /* vertices */
+ MLoopUV *luvs; /* texture coordinates */
+ float (*lnors)[3]; /* loops' normals */
+ float (*tangents)[4]; /* output tangents */
+ int num_polys; /* number of polygons */
+} BKEMeshToTangent;
+
+/* Mikktspace's API */
+static int get_num_faces(const SMikkTSpaceContext *pContext)
+{
+ BKEMeshToTangent *p_mesh = (BKEMeshToTangent *)pContext->m_pUserData;
+ return p_mesh->num_polys;
+}
+
+static int get_num_verts_of_face(const SMikkTSpaceContext *pContext, const int face_idx)
+{
+ BKEMeshToTangent *p_mesh = (BKEMeshToTangent *)pContext->m_pUserData;
+ return p_mesh->mpolys[face_idx].totloop;
+}
+
+static void get_position(const SMikkTSpaceContext *pContext, float r_co[3], const int face_idx, const int vert_idx)
+{
+ BKEMeshToTangent *p_mesh = (BKEMeshToTangent *)pContext->m_pUserData;
+ const int loop_idx = p_mesh->mpolys[face_idx].loopstart + vert_idx;
+ copy_v3_v3(r_co, p_mesh->mverts[p_mesh->mloops[loop_idx].v].co);
+}
+
+static void get_texture_coordinate(const SMikkTSpaceContext *pContext, float r_uv[2], const int face_idx,
+ const int vert_idx)
+{
+ BKEMeshToTangent *p_mesh = (BKEMeshToTangent *)pContext->m_pUserData;
+ copy_v2_v2(r_uv, p_mesh->luvs[p_mesh->mpolys[face_idx].loopstart + vert_idx].uv);
+}
+
+static void get_normal(const SMikkTSpaceContext *pContext, float r_no[3], const int face_idx, const int vert_idx)
+{
+ BKEMeshToTangent *p_mesh = (BKEMeshToTangent *)pContext->m_pUserData;
+ copy_v3_v3(r_no, p_mesh->lnors[p_mesh->mpolys[face_idx].loopstart + vert_idx]);
+}
+
+static void set_tspace(const SMikkTSpaceContext *pContext, const float fv_tangent[3], const float face_sign,
+ const int face_idx, const int vert_idx)
+{
+ BKEMeshToTangent *p_mesh = (BKEMeshToTangent *)pContext->m_pUserData;
+ float *p_res = p_mesh->tangents[p_mesh->mpolys[face_idx].loopstart + vert_idx];
+ copy_v3_v3(p_res, fv_tangent);
+ p_res[3] = face_sign;
+}
+
+/**
+ * Compute simplified tangent space normals, i.e. tangent vector + sign of bi-tangent one, which combined with
+ * split normals can be used to recreate the full tangent space.
+ * Note: * The mesh should be made of only tris and quads!
+ */
+void BKE_mesh_loop_tangents_ex(MVert *mverts, const int UNUSED(numVerts), MLoop *mloops,
+ float (*r_looptangent)[4], float (*loopnors)[3], MLoopUV *loopuvs,
+ const int UNUSED(numLoops), MPoly *mpolys, const int numPolys, ReportList *reports)
+{
+ BKEMeshToTangent mesh_to_tangent = {NULL};
+ SMikkTSpaceContext s_context = {NULL};
+ SMikkTSpaceInterface s_interface = {NULL};
+
+ MPoly *mp;
+ int mp_index;
+
+ /* First check we do have a tris/quads only mesh. */
+ for (mp = mpolys, mp_index = 0; mp_index < numPolys; mp++, mp_index++) {
+ if (mp->totloop > 4) {
+ BKE_report(reports, RPT_ERROR, "Tangent space can only be computed for tris/quads, aborting...\n");
+ return;
+ }
+ }
+
+ /* Compute Mikktspace's tangent normals. */
+ mesh_to_tangent.mpolys = mpolys;
+ mesh_to_tangent.mloops = mloops;
+ mesh_to_tangent.mverts = mverts;
+ mesh_to_tangent.luvs = loopuvs;
+ mesh_to_tangent.lnors = loopnors;
+ mesh_to_tangent.tangents = r_looptangent;
+ mesh_to_tangent.num_polys = numPolys;
+
+ s_context.m_pUserData = &mesh_to_tangent;
+ s_context.m_pInterface = &s_interface;
+ s_interface.m_getNumFaces = get_num_faces;
+ s_interface.m_getNumVerticesOfFace = get_num_verts_of_face;
+ s_interface.m_getPosition = get_position;
+ s_interface.m_getTexCoord = get_texture_coordinate;
+ s_interface.m_getNormal = get_normal;
+ s_interface.m_setTSpaceBasic = set_tspace;
+
+ /* 0 if failed */
+ if (genTangSpaceDefault(&s_context) == false) {
+ BKE_report(reports, RPT_ERROR, "Mikktspace failed to generate tangents for this mesh!\n");
+ }
+}
+
+/**
+ * Wrapper around BKE_mesh_loop_tangents_ex, which takes care of most boiling code.
+ * Note: * There must be a valid loop's CD_NORMALS available.
+ * * The mesh should be made of only tris and quads!
+ */
+void BKE_mesh_loop_tangents(Mesh *mesh, const char *uvmap, float (*r_looptangents)[4], ReportList *reports)
+{
+ MLoopUV *loopuvs;
+ float (*loopnors)[3];
+
+ /* Check we have valid texture coordinates first! */
+ if (uvmap) {
+ loopuvs = CustomData_get_layer_named(&mesh->ldata, CD_MLOOPUV, uvmap);
+ }
+ else {
+ loopuvs = CustomData_get_layer(&mesh->ldata, CD_MLOOPUV);
+ }
+ if (!loopuvs) {
+ BKE_reportf(reports, RPT_ERROR, "Tangent space computation needs an UVMap, \"%s\" not found, aborting.\n", uvmap);
+ return;
+ }
+
+ loopnors = CustomData_get_layer(&mesh->ldata, CD_NORMAL);
+ if (!loopnors) {
+ BKE_report(reports, RPT_ERROR, "Tangent space computation needs loop normals, none found, aborting.\n");
+ return;
+ }
+
+ BKE_mesh_loop_tangents_ex(mesh->mvert, mesh->totvert, mesh->mloop, r_looptangents,
+ loopnors, loopuvs, mesh->totloop, mesh->mpoly, mesh->totpoly, reports);
+}
+
+/** \} */
+
+
+/* -------------------------------------------------------------------- */
+
/** \name Polygon Calculations
* \{ */
diff --git a/source/blender/makesdna/DNA_customdata_types.h b/source/blender/makesdna/DNA_customdata_types.h
index f6516492b8f..325c2a8df54 100644
--- a/source/blender/makesdna/DNA_customdata_types.h
+++ b/source/blender/makesdna/DNA_customdata_types.h
@@ -63,9 +63,10 @@ typedef struct CustomDataExternal {
* layers, each with a data type (e.g. MTFace, MDeformVert, etc.). */
typedef struct CustomData {
CustomDataLayer *layers; /* CustomDataLayers, ordered by type */
- int typemap[39]; /* runtime only! - maps types to indices of first layer of that type,
+ int typemap[40]; /* runtime only! - maps types to indices of first layer of that type,
* MUST be >= CD_NUMTYPES, but we cant use a define here.
* Correct size is ensured in CustomData_update_typemap assert() */
+ int pad[1];
int totlayer, maxlayer; /* number of layers, size of layers array */
int totsize; /* in editmode, total size of all data layers */
void *pool; /* Bmesh: Memory pool for allocation of blocks */
@@ -117,7 +118,8 @@ enum {
CD_MVERT_SKIN = 36,
CD_FREESTYLE_EDGE = 37,
CD_FREESTYLE_FACE = 38,
- CD_NUMTYPES = 39,
+ CD_MLOOPTANGENT = 39,
+ CD_NUMTYPES = 40,
};
/* Bits for CustomDataMask */
@@ -162,6 +164,7 @@ enum {
#define CD_MASK_MVERT_SKIN (1LL << CD_MVERT_SKIN)
#define CD_MASK_FREESTYLE_EDGE (1LL << CD_FREESTYLE_EDGE)
#define CD_MASK_FREESTYLE_FACE (1LL << CD_FREESTYLE_FACE)
+#define CD_MASK_MLOOPTANGENT (1LL << CD_MLOOPTANGENT)
/* CustomData.flag */
enum {
diff --git a/source/blender/makesrna/intern/rna_mesh.c b/source/blender/makesrna/intern/rna_mesh.c
index fe6f33abc8c..cf634f9c7d4 100644
--- a/source/blender/makesrna/intern/rna_mesh.c
+++ b/source/blender/makesrna/intern/rna_mesh.c
@@ -338,6 +338,29 @@ static void rna_MeshLoop_normal_get(PointerRNA *ptr, float *values)
}
}
+static void rna_MeshLoop_tangent_get(PointerRNA *ptr, float *values)
+{
+ Mesh *me = rna_mesh(ptr);
+ MLoop *ml = (MLoop *)ptr->data;
+ const float (*vec)[4] = CustomData_get(&me->ldata, (int)(ml - me->mloop), CD_MLOOPTANGENT);
+
+ if (!vec) {
+ zero_v3(values);
+ }
+ else {
+ copy_v3_v3(values, (const float *)vec);
+ }
+}
+
+static float rna_MeshLoop_bitangent_sign_get(PointerRNA *ptr)
+{
+ Mesh *me = rna_mesh(ptr);
+ MLoop *ml = (MLoop *)ptr->data;
+ const float (*vec)[4] = CustomData_get(&me->ldata, (int)(ml - me->mloop), CD_MLOOPTANGENT);
+
+ return (vec) ? (*vec)[3] : 0.0f;
+}
+
static void rna_MeshPolygon_normal_get(PointerRNA *ptr, float *values)
{
Mesh *me = rna_mesh(ptr);
@@ -1870,10 +1893,26 @@ static void rna_def_mloop(BlenderRNA *brna)
RNA_def_property_range(prop, -1.0f, 1.0f);
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
RNA_def_property_float_funcs(prop, "rna_MeshLoop_normal_get", NULL, NULL);
- RNA_def_property_ui_text(prop, "Loop Normal",
+ RNA_def_property_ui_text(prop, "Normal",
"Local space unit length split normal vector of this vertex for this polygon "
- "(only computed on demand!)");
+ "(must be computed beforehand using calc_normals_split or calc_tangents)");
+ prop = RNA_def_property(srna, "tangent", PROP_FLOAT, PROP_DIRECTION);
+ RNA_def_property_array(prop, 3);
+ RNA_def_property_range(prop, -1.0f, 1.0f);
+ RNA_def_property_clear_flag(prop, PROP_EDITABLE);
+ RNA_def_property_float_funcs(prop, "rna_MeshLoop_tangent_get", NULL, NULL);
+ RNA_def_property_ui_text(prop, "Tangent",
+ "Local space unit length tangent vector of this vertex for this polygon "
+ "(must be computed beforehand using calc_tangents)");
+
+ prop = RNA_def_property(srna, "bitangent_sign", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_range(prop, -1.0f, 1.0f);
+ RNA_def_property_clear_flag(prop, PROP_EDITABLE);
+ RNA_def_property_float_funcs(prop, "rna_MeshLoop_bitangent_sign_get", NULL, NULL);
+ RNA_def_property_ui_text(prop, "Bitangent Sign",
+ "Sign of the bitangent vector of this vertex for this polygon (must be computed "
+ "beforehand using calc_tangents, bitangent = bitangent_sign * cross(normal, tangent))");
}
static void rna_def_mpolygon(BlenderRNA *brna)
diff --git a/source/blender/makesrna/intern/rna_mesh_api.c b/source/blender/makesrna/intern/rna_mesh_api.c
index 34f21046a92..76097b04c99 100644
--- a/source/blender/makesrna/intern/rna_mesh_api.c
+++ b/source/blender/makesrna/intern/rna_mesh_api.c
@@ -34,6 +34,8 @@
#include "RNA_define.h"
+#include "DNA_customdata_types.h"
+
#include "BLI_sys_types.h"
#include "BLI_utildefines.h"
@@ -100,6 +102,32 @@ static void rna_Mesh_free_normals_split(Mesh *mesh)
CustomData_free_layers(&mesh->ldata, CD_NORMAL, mesh->totloop);
}
+static void rna_Mesh_calc_tangents(Mesh *mesh, ReportList *reports, const char *uvmap)
+{
+ float (*r_looptangents)[4];
+
+ if (CustomData_has_layer(&mesh->ldata, CD_MLOOPTANGENT)) {
+ r_looptangents = CustomData_get_layer(&mesh->ldata, CD_MLOOPTANGENT);
+ memset(r_looptangents, 0, sizeof(float[4]) * mesh->totloop);
+ }
+ else {
+ r_looptangents = CustomData_add_layer(&mesh->ldata, CD_MLOOPTANGENT, CD_CALLOC, NULL, mesh->totloop);
+ CustomData_set_layer_flag(&mesh->ldata, CD_MLOOPTANGENT, CD_FLAG_TEMPORARY);
+ }
+
+ /* Compute loop normals if needed. */
+ if (!CustomData_has_layer(&mesh->ldata, CD_NORMAL)) {
+ rna_Mesh_calc_normals_split(mesh, (float)M_PI);
+ }
+
+ BKE_mesh_loop_tangents(mesh, uvmap, r_looptangents, reports);
+}
+
+static void rna_Mesh_free_tangents(Mesh *mesh)
+{
+ CustomData_free_layers(&mesh->ldata, CD_MLOOPTANGENT, mesh->totloop);
+}
+
static void rna_Mesh_calc_smooth_groups(Mesh *mesh, int use_bitflags, int *r_poly_group_len,
int **r_poly_group, int *r_group_total)
{
@@ -141,6 +169,18 @@ void RNA_api_mesh(StructRNA *srna)
func = RNA_def_function(srna, "free_normals_split", "rna_Mesh_free_normals_split");
RNA_def_function_ui_description(func, "Free split vertex normals");
+ func = RNA_def_function(srna, "calc_tangents", "rna_Mesh_calc_tangents");
+ RNA_def_function_flag(func, FUNC_USE_REPORTS);
+ RNA_def_function_ui_description(func,
+ "Compute tangents and bitangent signs, to be used together with the split normals "
+ "to get a complete tangent space for normal mapping "
+ "(split normals are also computed if not yet present)");
+ parm = RNA_def_string(func, "uvmap", "", MAX_CUSTOMDATA_LAYER_NAME, "",
+ "Name of the UV map to use for tangent space computation");
+
+ func = RNA_def_function(srna, "free_tangents", "rna_Mesh_free_tangents");
+ RNA_def_function_ui_description(func, "Free tangents");
+
func = RNA_def_function(srna, "calc_tessface", "ED_mesh_calc_tessface");
RNA_def_function_ui_description(func, "Calculate face tessellation (supports editmode too)");