cgv
Loading...
Searching...
No Matches
dynamic_mesh.cxx
1#include "dynamic_mesh.h"
2
3#include <cgv/math/ftransform.h>
4#include <cgv/math/inv.h>
5
6namespace cgv {
7 namespace media {
8 namespace mesh {
9
10template <typename T>
12{
13 blend_shape bs = { mode, idx2_type(idx_type(blend_shape_data.size()),idx_type(blend_shape_data.size()+nr_data)),
14 idx2_type(idx_type(blend_shape_indices.size()), idx_type(blend_shape_indices.size()+nr_indices)) };
15 blend_shapes.push_back(bs);
16 return uint32_t(blend_shapes.size() - 1);
17}
18template <typename T>
20{
21 blend_shape_data.push_back(d);
22}
23template <typename T>
25{
26 blend_shape_indices.push_back(i);
27}
28template <typename T>
30{
31 const auto& bs = blend_shapes[bi];
32 switch (bs.mode) {
33 case blend_shape_mode::direct:
36 return true;
37 case blend_shape_mode::indexed:
38 for (idx_type i = bs.blend_shape_index_range[0]; i < bs.blend_shape_index_range[1]; ++i)
39 if (blend_shape_indices[i] == vi)
40 return true;
41 break;
42 case blend_shape_mode::range_indexed:
43 for (idx_type i = bs.blend_shape_index_range[0]; i < bs.blend_shape_index_range[1]; i+=2)
44 if (blend_shape_indices[i] <= vi && vi < blend_shape_indices[i+1])
45 return true;
46 break;
47 }
48 return false;
49}
50template <typename T>
52{
53 const auto& bs = blend_shapes[bi];
54 switch (bs.mode) {
55 case blend_shape_mode::direct:
56 return blend_shape_data[bi*this->get_nr_positions()+vi];
57 case blend_shape_mode::indexed:
58 for (idx_type i = bs.blend_shape_index_range[0]; i < bs.blend_shape_index_range[1]; ++i)
59 if (blend_shape_indices[i] == vi)
60 return blend_shape_data[i];
61 break;
62 case blend_shape_mode::range_indexed:
63 for (idx_type off = 0, i = bs.blend_shape_index_range[0]; i < bs.blend_shape_index_range[1];
64 off += blend_shape_indices[i+1]-blend_shape_indices[i], i+=2)
65 if (blend_shape_indices[i] <= vi && vi < blend_shape_indices[i+1])
66 return blend_shape_data[off + vi- blend_shape_indices[i]];
67 break;
68 }
69 return vec3_type(T(0));
70}
71template <typename T>
73{
74 return blend_shapes.size();
75}
76template <typename T>
77void dynamic_mesh<T>::set_vertex_weight_mode(vertex_weight_mode mode)
78{
79 weight_mode = mode;
80}
81template <typename T>
82void dynamic_mesh<T>::begin_vertex_weight_vertex()
83{
84 vertex_weight_index_begins.push_back(uint32_t(vertex_weight_data.size()));
85}
86template <typename T>
88{
89 switch (weight_mode) {
90 case vertex_weight_mode::dense:
91 return uint32_t(vi * get_nr_joints());
92 case vertex_weight_mode::sparse:
93 return vertex_weight_index_begins[vi];
94 case vertex_weight_mode::fixed:
95 return uint32_t(vi * max_nr_weights_per_vertex);
96 }
97 return -1;
98}
99template <typename T>
102 switch (weight_mode) {
103 case vertex_weight_mode::dense:
104 return uint32_t((vi+1)*get_nr_joints());
105 case vertex_weight_mode::sparse:
106 return uint32_t(vi >= vertex_weight_index_begins.size() ? vertex_weight_data.size() : vertex_weight_index_begins[vi]);
107 case vertex_weight_mode::fixed:
108 return uint32_t((vi+1)*max_nr_weights_per_vertex);
109 }
110 return -1;
111}
112template <typename T>
114{
115 switch (weight_mode) {
116 case vertex_weight_mode::dense:
117 return vertex_weight_data[vi * get_nr_joints() + ji];
118 default:
119 for (idx_type i = vertex_weight_begin(vi); i < vertex_weight_end(vi); ++i)
120 if (vertex_weight_indices[i] == ji)
121 return vertex_weight_data[i];
122 break;
123 }
124 return T(0);
126
127template <typename T>
129{
130 vertex_weight_data.push_back(w);
131}
132template <typename T>
134{
135 vertex_weight_indices.push_back(i);
137template <typename T>
139{
140 return vertex_weight_data.size();
141}
142template <typename T>
143size_t dynamic_mesh<T>::get_nr_vertex_weight_indices() const
144{
145 return vertex_weight_indices.size();
147template <typename T>
149{
150 return idx_type(joint_parents.size());
151}
152template <typename T>
153std::vector<typename dynamic_mesh<T>::mat4_type> dynamic_mesh<T>::compute_joint_transformations(const std::vector<vec3_type>& reference_joint_locations,
154 const vec3_type& translation, const std::vector<vec3_type>& target_spin_vectors) const
155{
156 std::vector<mat3_type> target_rotations;
157 for (const auto& sv : target_spin_vectors)
158 target_rotations.push_back(cgv::math::rotate3s<T>(sv));
159 return compute_joint_transformations(reference_joint_locations, translation, target_rotations);
160}
161template <typename T>
162std::vector<typename dynamic_mesh<T>::mat4_type> dynamic_mesh<T>::compute_joint_transformations(const std::vector<vec3_type>& reference_joint_locations,
163 const vec3_type& translation, const std::vector<mat3_type>& target_rotations) const
164{
165 // compute joint transformations in rest pose and in target pose
166 std::vector<mat4_type> Is, Ts;
167 mat4_type I = cgv::math::identity4<float>();
168 vec3_type& t = reinterpret_cast<vec3_type&>(I.col(3));
169 t = reference_joint_locations.front();
170 Is.push_back(I);
171 Ts.push_back(pose4(target_rotations.front(), t + translation));
172 unsigned ji;
173 for (ji = 1; ji < target_rotations.size(); ++ji) {
174 t = reference_joint_locations[ji] - reference_joint_locations[joint_parents[ji]];
175 Is.push_back(I);
176 Ts.push_back(pose4(target_rotations[ji], t));
177 }
178 // concatenate poses
179 for (ji = 1; ji < target_rotations.size(); ++ji) {
180 Is[ji] = Is[joint_parents[ji]] * Is[ji];
181 Ts[ji] = Ts[joint_parents[ji]] * Ts[ji];
182 }
183 // compute final rest pose to pose transformations
184 for (ji = 0; ji < target_rotations.size(); ++ji)
185 Ts[ji] = Ts[ji] * inv(Is[ji]);
186
187 return Ts;
188}
189
190
191template <typename T>
192void dynamic_mesh<T>::apply_blend_shapes(const std::vector<T>& weights, idx_type blend_shape_offset, bool only_add, bool use_parallel_implementation)
193{
194 if (!only_add)
195 this->positions = reference_positions;
196 if (use_parallel_implementation) {
197 // here we assume that all blend shapes have mode direct and address whole mesh
198
199 // first extract per blend shape pointers to the blend shape data start
200 std::vector<const vec3_type*> bs_ptrs;
201 int n = this->get_nr_positions();
202 for (size_t bi = blend_shape_offset; bi < weights.size() + blend_shape_offset; ++bi) {
203 const auto& bs = blend_shapes[bi];
204 assert(bs.mode == blend_shape_mode::direct);
205 assert(bs.blend_shape_data_range[1] - bs.blend_shape_data_range[0] == n);
206 bs_ptrs.push_back(&blend_shape_data[bs.blend_shape_data_range[0]]);
207 }
208 // next apply them to mesh positions
209#pragma omp parallel for
210 for (int vi = 0; vi < n; ++vi) {
211 vec3_type p(T(0));
212 for (int wi = 0; wi < weights.size(); ++wi)
213 p += weights[wi]*bs_ptrs[wi][vi];
214 this->position(vi) += p;
215 }
216 }
217 else {
218 for (idx_type bi = blend_shape_offset, wi = 0; wi < weights.size(); ++wi, ++bi) {
219 const auto& bs = blend_shapes[bi];
220 switch (bs.mode) {
221 case blend_shape_mode::direct:
222 for (int j=0, i = bs.blend_shape_data_range[0]; i < int(bs.blend_shape_data_range[1]); ++i, ++j)
223 this->positions[j] += weights[wi] * blend_shape_data[i];
224 break;
225 case blend_shape_mode::indexed:
226 for (uint32_t i = bs.blend_shape_data_range[0], j = bs.blend_shape_index_range[0]; i < bs.blend_shape_data_range[1]; ++i, ++j)
227 this->positions[blend_shape_indices[j]] += weights[wi] * blend_shape_data[i];
228 break;
229 case blend_shape_mode::range_indexed:
230 for (uint32_t i = bs.blend_shape_data_range[0], j = bs.blend_shape_index_range[0]; j < bs.blend_shape_index_range[1]; j += 2)
231 for (uint32_t k = blend_shape_indices[j]; k < blend_shape_indices[j + 1]; ++k, ++i)
232 this->positions[k] += weights[wi] * blend_shape_data[i];
233 break;
234 }
235 }
236 }
237}
238template <typename T>
239const std::vector<typename dynamic_mesh<T>::vec3_type>& dynamic_mesh<T>::get_intermediate_positions() const
240{
241 return intermediate_positions;
242}
243
244template <typename T>
245const std::vector<int32_t>& dynamic_mesh<T>::get_joint_parents() const
246{
247 return joint_parents;
248}
249template <typename T>
251{
252 return joint_parents;
253}
254template <typename T>
256{
257 reference_positions = this->positions;
258}
259template <typename T>
261{
262 intermediate_positions = this->positions;
263}
264template <typename T>
266{
267 this->positions = intermediate_positions;
268}
269
270template <typename T>
271void dynamic_mesh<T>::lbs(const std::vector<mat4_type>& joint_matrices, lbs_source_mode mode)
272{
273 std::vector<vec3_type> tmp;
274 if (mode == lbs_source_mode::position)
275 tmp = this->positions;
276 const std::vector<vec3_type>& P = mode == lbs_source_mode::position ? tmp : (
277 mode == lbs_source_mode::intermediate ? intermediate_positions : reference_positions);
278 switch (weight_mode) {
279 case vertex_weight_mode::dense:
280 for (size_t pi = 0, wi = 0; pi < P.size(); ++pi) {
281 vec4_type p = vec4_type(P[pi], 1.0f);
282 vec4_type q = vec4_type(0.0f);
283 for (unsigned ji = 0; ji < joint_parents.size(); ++ji, ++wi)
284 q += vertex_weight_data[wi] * (joint_matrices[ji] * p);
285 this->position(idx_type(pi)) = q;
286 }
287 break;
288 case vertex_weight_mode::sparse:
289 for (size_t pi = 0; pi < P.size(); ++pi) {
290 vec4_type p = vec4_type(P[pi], 1.0f);
291 vec4_type q = vec4_type(0.0f);
292 size_t beg = vertex_weight_index_begins[pi];
293 size_t end = pi+1 < P.size() ? vertex_weight_index_begins[pi+1] : vertex_weight_indices.size();
294 for (size_t wi = beg; wi < end; ++wi)
295 q += vertex_weight_data[wi] * (joint_matrices[vertex_weight_indices[wi]] * p);
296 this->position(idx_type(pi)) = q;
297 }
298 break;
299 case vertex_weight_mode::fixed:
300 for (size_t pi = 0; pi < P.size(); ++pi) {
301 vec4_type p = vec4_type(P[pi], 1.0f);
302 vec4_type q = vec4_type(0.0f);
303 size_t beg = vertex_weight_index_begins[pi];
304 size_t end = pi + 1 < P.size() ? vertex_weight_index_begins[pi + 1] : vertex_weight_indices.size();
305 for (size_t wi = beg; wi < end; ++wi)
306 q += vertex_weight_data[wi] * (joint_matrices[vertex_weight_indices[wi]] * p);
307 this->position(idx_type(pi)) = q;
308 }
309 break;
310 }
311}
312
313template class dynamic_mesh<float>;
314template class dynamic_mesh<double>;
315
316 }
317 }
318}
complete implementation of method actions that only call one method when entering a node
Definition action.h:113
fvec< T, N > & col(unsigned j)
reference a column of the matrix as a vector
Definition fmat.h:209
A vector with zero based index.
Definition fvec.h:26
The dynamic_mesh provides interpolation between several blend shapes of a mesh.
void add_blend_shape_data(const vec3_type &d)
Add another data point to the data buffer.
void recover_intermediate_positions()
copy intermediate positions to positions
std::vector< int32_t > & ref_joint_parents()
return mutable reference to joint parent vector
uint32_t add_blend_shape(blend_shape_mode mode, idx_type nr_data, idx_type nr_indices=0)
Add a new blend shape.
void lbs(const std::vector< mat4_type > &joint_matrices, lbs_source_mode mode)
perform linear blend skinning on reference positions or the current mesh position attribute
void store_in_intermediate_positions()
store current positions in intermediate positions
void store_in_reference_positions()
store current positions in reference positions
void add_blend_shape_index(idx_type i)
Add another index to the index buffer.
idx_type vertex_weight_begin(idx_type vi) const
return the begin index for vertex weights of given vertex
vec3_type get_blend_shape_vector(idx_type bi, idx_type vi) const
Returns one vertex of one blend shape.
const std::vector< int32_t > & get_joint_parents() const
return const reference to joint parent vector
bool has_blend_shape_vector(idx_type bi, idx_type vi) const
Query if a blend shape has a vertex with a given ID.
void apply_blend_shapes(const std::vector< T > &weights, idx_type blend_shape_offset=0, bool only_add=false, bool use_parallel_implementation=false)
this function applies weights.size() number of blend shapes starting at offset blend_shape_offset and...
blend_shape_mode
specifies how the blend shapes are stored
idx_type vertex_weight_end(idx_type vi) const
return the end index for vertex weights of given vertex
T get_vertex_weight(idx_type vi, idx_type ji) const
return the vertex weight of vertex vi and joint ji
const std::vector< vec3_type > & get_intermediate_positions() const
return const reference to intermediate position vector
lbs_source_mode
Which source to use for the Linear Blend Skinning.
std::vector< mat4_type > compute_joint_transformations(const std::vector< vec3_type > &reference_joint_locations, const vec3_type &translation, const std::vector< vec3_type > &target_spin_vectors) const
compute joint transformations from reference joint locations, target translation and target spin vect...
size_t get_nr_blend_shapes() const
Return how many blend shapes this mesh has.
cgv::type::uint32_type idx_type
define index type
Definition simple_mesh.h:30
the cgv namespace
Definition print.h:11
Captures where and how the blandshape data is stored.