14#include <lagrange/Attribute.h>
15#include <lagrange/SurfaceMesh.h>
16#include <lagrange/attribute_names.h>
17#include <lagrange/utils/assert.h>
18#include <lagrange/views.h>
48template <
typename Scalar,
typename Index>
52 const std::vector<Eigen::Transform<Scalar, 3, Eigen::TransformTraits::Affine>>& transforms,
53 const Eigen::Matrix<Scalar, Eigen::Dynamic, Eigen::Dynamic>& weights,
54 const Eigen::Matrix<Scalar, Eigen::Dynamic, 1>& weight_complement = {})
59 (weight_complement.rows() == 0) || (weight_complement.rows() == mesh.get_num_vertices()));
61 const Index num_vertices = mesh.get_num_vertices();
62 const size_t num_handles = transforms.size();
68 for (Index v = 0; v < num_vertices; ++v) {
69 const Eigen::Matrix<Scalar, 3, 1> orig = original_view.row(v);
70 Scalar weight_sum = 0;
71 for (
size_t h = 0; h < num_handles; ++h) {
72 Scalar weight = weights(v, h);
74 verts.row(v) += weight * (transforms[h] * orig);
78 if (weight_complement.rows() > 0 && weight_complement(v) > 0) {
79 verts.row(v) += (weight_complement(v) * orig);
80 weight_sum += weight_complement(v);
83 verts.row(v) /= weight_sum;
96template <
typename Scalar,
typename Index>
100 const std::vector<Eigen::Transform<Scalar, 3, Eigen::TransformTraits::Affine>>& transforms)
105 auto& weight_attr = mesh.template get_attribute<Scalar>(weight_id);
107 Eigen::Matrix<Scalar, Eigen::Dynamic, Eigen::Dynamic> weights =
matrix_view(weight_attr);
112template <
typename Scalar,
typename Index>
119 Eigen::Matrix<Scalar, Eigen::Dynamic, Eigen::Dynamic>
weights;
125 Eigen::Matrix<Index, Eigen::Dynamic, Eigen::Dynamic>
indices;
138template <
typename Scalar,
typename Index>
140 const Eigen::Matrix<Scalar, Eigen::Dynamic, Eigen::Dynamic>& weights,
142 const Eigen::Matrix<Scalar, Eigen::Dynamic, 1>& weight_complement =
143 Eigen::Matrix<Scalar, Eigen::Dynamic, 1>())
145 const Index num_vertices = Index(weights.rows());
146 const Index num_handles = Index(weights.cols());
147 Index num_implicit_handle = 0;
150 if (weight_complement.rows() > 0 &&
151 weight_complement.maxCoeff() > std::numeric_limits<Scalar>::epsilon()) {
154 num_implicit_handle = 1;
158 const Index num_handles_max = Index(n) - num_implicit_handle;
159 const Index num_handles_used = std::min(num_handles, num_handles_max);
163 result.
weights.resize(num_vertices, n);
164 result.
indices.resize(num_vertices, n);
165 if (num_handles < Index(n)) {
171 if (num_handles <= num_handles_max) {
174 for (Index i = 0; i < num_vertices; ++i) {
175 for (Index j = 0; j < num_handles; ++j) {
177 result.
weights(i, j) = weights(i, j);
184 for (Index i = 0; i < num_vertices; ++i) {
185 std::vector<Index> tmp(num_handles);
186 std::iota(tmp.begin(), tmp.end(), 0);
189 tmp.begin() + num_handles_used,
191 [&weights, i](
const Index a,
const Index b) ->
bool {
192 return weights(i, a) > weights(i, b);
195 for (Index j = 0; j < num_handles_used; ++j) {
197 result.
weights(i, j) = weights(i, tmp[j]);
202 if (num_implicit_handle > 0) {
204 for (Index i = 0; i < num_vertices; ++i) {
205 result.
indices(i, num_handles_used) = num_handles_used;
206 result.
weights(i, num_handles_used) = weight_complement(i);
211 if (num_handles > num_handles_max) {
212 for (Index i = 0; i < num_vertices; ++i) {
213 Scalar s = result.
weights.row(i).sum();
230template <
typename Scalar,
typename Index,
typename WeightScalar = Scalar>
233 const Eigen::Matrix<WeightScalar, Eigen::Dynamic, Eigen::Dynamic>& weights)
235 return mesh.template create_attribute<WeightScalar>(
240 {weights.data(), size_t(weights.size())});
255 typename WeightScalar = Scalar,
256 typename WeightIndex = Index>
259 const Eigen::Matrix<WeightScalar, Eigen::Dynamic, Eigen::Dynamic>& weights,
262 auto result = skinning_extract_n<WeightScalar, WeightIndex>(weights, n);
263 auto bone_id = mesh.template create_attribute<WeightIndex>(
267 result.indices.cols(),
268 {result.indices.data(), size_t(result.indices.size())});
270 auto weight_id = mesh.template create_attribute<WeightScalar>(
274 result.weights.cols(),
275 {result.weights.data(), size_t(result.weights.size())});
276 return {bone_id, weight_id};
Derived attribute class that stores the actual information.
Definition: Attribute.h:153
uint32_t AttributeId
Identified to be used to access an attribute.
Definition: AttributeFwd.h:73
constexpr AttributeId invalid_attribute_id()
Invalid attribute id.
Definition: AttributeFwd.h:76
@ Vector
Mesh attribute can have any number of channels (including 1 channel).
@ Vertex
Per-vertex mesh attributes.
Definition: AttributeFwd.h:28
ConstRowMatrixView< ValueType > matrix_view(const Attribute< ValueType > &attribute)
Returns a read-only view of a given attribute in the form of an Eigen matrix.
Definition: views.cpp:35
RowMatrixView< Scalar > vertex_ref(SurfaceMesh< Scalar, Index > &mesh)
Returns a writable view of the mesh vertices in the form of an Eigen matrix.
Definition: views.cpp:150
#define la_runtime_assert(...)
Runtime assertion check.
Definition: assert.h:169
nullptr_t, size_t, ptrdiff_t basic_ostream bad_weak_ptr extent, remove_extent, is_array,...
Definition: attribute_string_utils.h:21
lagrange::AttributeId weights_to_mesh_attribute(SurfaceMesh< Scalar, Index > &mesh, const Eigen::Matrix< WeightScalar, Eigen::Dynamic, Eigen::Dynamic > &weights)
Imports the weights matrix as weight attributes of the mesh.
Definition: skinning.h:231
std::pair< lagrange::AttributeId, lagrange::AttributeId > weights_to_indexed_mesh_attribute(SurfaceMesh< Scalar, Index > &mesh, const Eigen::Matrix< WeightScalar, Eigen::Dynamic, Eigen::Dynamic > &weights, int n)
Imports the weights matrix as indexed weight attributes of the mesh.
Definition: skinning.h:257
void skinning_deform(SurfaceMesh< Scalar, Index > &mesh, const lagrange::Attribute< Scalar > &original_vertices, const std::vector< Eigen::Transform< Scalar, 3, Eigen::TransformTraits::Affine > > &transforms, const Eigen::Matrix< Scalar, Eigen::Dynamic, Eigen::Dynamic > &weights, const Eigen::Matrix< Scalar, Eigen::Dynamic, 1 > &weight_complement={})
Performs linear blend skinning deformation on a mesh.
Definition: skinning.h:49
SkinningExtractNResult< Scalar, Index > skinning_extract_n(const Eigen::Matrix< Scalar, Eigen::Dynamic, Eigen::Dynamic > &weights, int n, const Eigen::Matrix< Scalar, Eigen::Dynamic, 1 > &weight_complement=Eigen::Matrix< Scalar, Eigen::Dynamic, 1 >())
From a weight matrix |V| x |H|, constructs a weight matrix |V| x n, where n is an arbitrary contraint...
Definition: skinning.h:139
static constexpr std::string_view indexed_weight
Indexed skinning weights, with a fixed number (typically 4) specified for each vertex.
Definition: attribute_names.h:69
static constexpr std::string_view weight
Skinning weights, with all joints specified for each vertex.
Definition: attribute_names.h:63
static constexpr std::string_view indexed_joint
Indexed skinning index, with a fixed number (typically 4) specified for each vertex.
Definition: attribute_names.h:75