14#ifdef LAGRANGE_WITH_MIKKTSPACE
16 #include <lagrange/SurfaceMesh.h>
17 #include <lagrange/internal/find_attribute_utils.h>
18 #include <lagrange/utils/assert.h>
19 #include <lagrange/utils/safe_cast.h>
20 #include <lagrange/views.h>
22 #include <mikktspace.h>
44template <
typename Scalar,
typename Index,
int NVPF = 3,
int DIM = 3,
int UV_DIM = 2>
45lagrange::TangentBitangentResult compute_tangent_bitangent_mikktspace(
46 lagrange::SurfaceMesh<Scalar, Index>& mesh,
47 lagrange::TangentBitangentOptions options = {})
51 static_assert(NVPF == 3);
52 static_assert(DIM == 3);
53 static_assert(UV_DIM == 2);
55 lagrange::TangentBitangentResult result;
59 options.uv_attribute_name,
66 options.normal_attribute_name,
72 const size_t num_channels = (options.pad_with_sign ? 4 : 3);
76 options.tangent_attribute_name,
80 internal::ResetToDefault::No);
84 options.bitangent_attribute_name,
88 internal::ResetToDefault::No);
94 bool orthogonalize_bitangent;
96 span<const Scalar> position_values;
97 span<const Index> position_indices;
99 span<const Scalar> normal_values;
100 span<const Index> normal_indices;
102 span<const Scalar> uv_values;
103 span<const Index> uv_indices;
105 span<Scalar> tangents;
106 span<Scalar> bitangents;
111 data.num_channels =
static_cast<int>(num_channels);
112 data.orthogonalize_bitangent = options.orthogonalize_bitangent;
115 data.normal_values = mesh.template get_indexed_attribute<Scalar>(normal_id).values().get_all();
116 data.normal_indices =
117 mesh.template get_indexed_attribute<Scalar>(normal_id).indices().get_all();
118 data.uv_values = mesh.template get_indexed_attribute<Scalar>(uv_id).values().get_all();
119 data.uv_indices = mesh.template get_indexed_attribute<Scalar>(uv_id).indices().get_all();
120 data.tangents = mesh.template ref_attribute<Scalar>(result.
tangent_id).ref_all();
121 data.bitangents = mesh.template ref_attribute<Scalar>(result.
bitangent_id).ref_all();
123 SMikkTSpaceInterface mk_interface;
124 mk_interface.m_getNumFaces = [](
const SMikkTSpaceContext* pContext) {
125 auto _data =
reinterpret_cast<const LocalData*
>(pContext->m_pUserData);
126 return _data->num_facets;
128 mk_interface.m_getNumVerticesOfFace = [](
const SMikkTSpaceContext* pContext,
const int iFace) {
133 mk_interface.m_getPosition =
134 [](
const SMikkTSpaceContext* pContext,
float fvPosOut[],
const int iFace,
const int iVert) {
135 auto _data =
reinterpret_cast<const LocalData*
>(pContext->m_pUserData);
136 const Index v = _data->position_indices[iFace * NVPF + iVert];
137 auto pos = _data->position_values.subspan(v * DIM, DIM);
138 fvPosOut[0] =
static_cast<float>(pos[0]);
139 fvPosOut[1] =
static_cast<float>(pos[1]);
140 fvPosOut[2] =
static_cast<float>(pos[2]);
142 mk_interface.m_getNormal = [](
const SMikkTSpaceContext* pContext,
146 auto _data =
reinterpret_cast<const LocalData*
>(pContext->m_pUserData);
147 const Index v = _data->normal_indices[iFace * NVPF + iVert];
148 auto nrm = _data->normal_values.subspan(v * DIM, DIM);
149 fvNormOut[0] =
static_cast<float>(nrm[0]);
150 fvNormOut[1] =
static_cast<float>(nrm[1]);
151 fvNormOut[2] =
static_cast<float>(nrm[2]);
153 mk_interface.m_getTexCoord = [](
const SMikkTSpaceContext* pContext,
157 auto _data =
reinterpret_cast<const LocalData*
>(pContext->m_pUserData);
158 const Index v = _data->uv_indices[iFace * NVPF + iVert];
159 auto uv = _data->uv_values.subspan(v * UV_DIM, UV_DIM);
160 fvTexcOut[0] =
static_cast<float>(uv[0]);
161 fvTexcOut[1] =
static_cast<float>(uv[1]);
163 mk_interface.m_setTSpaceBasic = [](
const SMikkTSpaceContext* pContext,
164 const float fvTangent[],
168 auto _data =
reinterpret_cast<LocalData*
>(pContext->m_pUserData);
169 auto tangent = _data->tangents.subspan(
170 (iFace * NVPF + iVert) * _data->num_channels,
171 _data->num_channels);
172 tangent[0] =
static_cast<Scalar>(fvTangent[0]);
173 tangent[1] =
static_cast<Scalar>(fvTangent[1]);
174 tangent[2] =
static_cast<Scalar>(fvTangent[2]);
175 if (tangent.size() == 4) {
176 tangent[3] =
static_cast<Scalar>(fSign);
179 mk_interface.m_setTSpace = [](
const SMikkTSpaceContext* pContext,
180 const float fvTangent[],
181 const float fvBiTangent[],
184 const tbool bIsOrientationPreserving,
189 auto _data =
reinterpret_cast<LocalData*
>(pContext->m_pUserData);
190 const float fSign = bIsOrientationPreserving ? 1.0f : (-1.0f);
192 auto tangent = _data->tangents.subspan(
193 (iFace * NVPF + iVert) * _data->num_channels,
194 _data->num_channels);
195 tangent[0] =
static_cast<Scalar>(fvTangent[0]);
196 tangent[1] =
static_cast<Scalar>(fvTangent[1]);
197 tangent[2] =
static_cast<Scalar>(fvTangent[2]);
198 if (tangent.size() == 4) {
199 tangent[3] =
static_cast<Scalar>(fSign);
202 auto bitangent = _data->bitangents.subspan(
203 (iFace * NVPF + iVert) * _data->num_channels,
204 _data->num_channels);
205 if (_data->orthogonalize_bitangent) {
206 const Index v = _data->normal_indices[iFace * NVPF + iVert];
207 auto nrm = _data->normal_values.subspan(v * DIM, DIM);
208 Eigen::Vector3f n(nrm[0], nrm[1], nrm[2]);
209 Eigen::Vector3f t(fvTangent[0], fvTangent[1], fvTangent[2]);
210 Eigen::Vector3f b = fSign * n.cross(t);
211 bitangent[0] =
static_cast<Scalar>(b[0]);
212 bitangent[1] =
static_cast<Scalar>(b[1]);
213 bitangent[2] =
static_cast<Scalar>(b[2]);
215 bitangent[0] =
static_cast<Scalar>(fvBiTangent[0]);
216 bitangent[1] =
static_cast<Scalar>(fvBiTangent[1]);
217 bitangent[2] =
static_cast<Scalar>(fvBiTangent[2]);
219 if (bitangent.size() == 4) {
220 bitangent[3] =
static_cast<Scalar>(fSign);
224 SMikkTSpaceContext context;
225 context.m_pInterface = &mk_interface;
226 context.m_pUserData =
reinterpret_cast<void*
>(&data);
229 genTangSpaceDefault(&context);
lagrange::span< const ValueType > get_all() const
Returns a read-only view of the buffer spanning num elements x num channels.
Definition Attribute.cpp:512
Index get_dimension() const
Retrieves the dimension of the mesh vertices.
Definition SurfaceMesh.h:656
const Attribute< Index > & get_corner_to_vertex() const
Gets a read-only reference to the corner -> vertex id attribute.
Definition SurfaceMesh.cpp:1393
bool is_triangle_mesh() const
Whether the mesh must only contain triangular facets.
Definition SurfaceMesh.cpp:2098
Index get_num_facets() const
Retrieves the number of facets.
Definition SurfaceMesh.h:678
const Attribute< Scalar > & get_vertex_to_position() const
Gets a read-only reference to the vertex -> positions attribute.
Definition SurfaceMesh.cpp:1381
LA_CORE_API spdlog::logger & logger()
Retrieves the current logger.
Definition Logger.cpp:40
constexpr AttributeId invalid_attribute_id()
Invalid attribute id.
Definition AttributeFwd.h:76
@ Tangent
Mesh attribute can have dim or dim + 1 channels.
Definition AttributeFwd.h:59
@ Normal
Mesh attribute can have dim or dim + 1 channels.
Definition AttributeFwd.h:58
@ UV
Mesh attribute must have exactly 2 channels.
Definition AttributeFwd.h:62
@ Bitangent
Mesh attribute can have dim or dim + 1 channels.
Definition AttributeFwd.h:60
@ Scalar
Mesh attribute must have exactly 1 channel.
Definition AttributeFwd.h:56
@ Indexed
Indexed mesh attributes.
Definition AttributeFwd.h:45
@ Corner
Per-corner mesh attributes.
Definition AttributeFwd.h:37
#define la_runtime_assert(...)
Runtime assertion check.
Definition assert.h:174
constexpr auto safe_cast(SourceType value) -> std::enable_if_t<!std::is_same< SourceType, TargetType >::value, TargetType >
Perform safe cast from SourceType to TargetType, where "safe" means:
Definition safe_cast.h:50
AttributeId find_matching_attribute(const SurfaceMesh< Scalar, Index > &mesh, std::string_view name, BitField< AttributeElement > expected_element, AttributeUsage expected_usage, size_t expected_channels)
Find an attribute with a given name, ensuring the usage and element type match an expected target.
Definition find_attribute_utils.cpp:97
AttributeId find_or_create_attribute(SurfaceMesh< Scalar, Index > &mesh, std::string_view name, AttributeElement expected_element, AttributeUsage expected_usage, size_t expected_channels, ResetToDefault reset_tag)
Either retrieve or create an attribute with a prescribed name, element type and usage.
Definition find_attribute_utils.cpp:185
Main namespace for Lagrange.
AttributeId tangent_id
Tangent vector attribute id.
Definition compute_tangent_bitangent.h:77
AttributeId bitangent_id
Bitangent vector attribute id.
Definition compute_tangent_bitangent.h:80