cgv
Loading...
Searching...
No Matches
dynamic_mesh.cxx
1#include "dynamic_mesh.h"
2
3#include <cgv/math/ftransform.h>
4
5namespace cgv {
6 namespace media {
7 namespace mesh {
8
9template <typename T>
11{
12 blend_shape bs = { mode, idx2_type(idx_type(blend_shape_data.size()),idx_type(blend_shape_data.size()+nr_data)),
13 idx2_type(idx_type(blend_shape_indices.size()), idx_type(blend_shape_indices.size()+nr_indices)) };
14 blend_shapes.push_back(bs);
15 return uint32_t(blend_shapes.size() - 1);
16}
17template <typename T>
19{
20 blend_shape_data.push_back(d);
21}
22template <typename T>
24{
25 blend_shape_indices.push_back(i);
26}
27template <typename T>
29{
30 const auto& bs = blend_shapes[bi];
31 switch (bs.mode) {
32 case blend_shape_mode::direct:
35 return true;
36 case blend_shape_mode::indexed:
37 for (idx_type i = bs.blend_shape_index_range[0]; i < bs.blend_shape_index_range[1]; ++i)
38 if (blend_shape_indices[i] == vi)
39 return true;
40 break;
41 case blend_shape_mode::range_indexed:
42 for (idx_type i = bs.blend_shape_index_range[0]; i < bs.blend_shape_index_range[1]; i+=2)
43 if (blend_shape_indices[i] <= vi && vi < blend_shape_indices[i+1])
44 return true;
45 break;
46 }
47 return false;
48}
49template <typename T>
51{
52 const auto& bs = blend_shapes[bi];
53 switch (bs.mode) {
54 case blend_shape_mode::direct:
55 return blend_shape_data[bi*this->get_nr_positions()+vi];
56 case blend_shape_mode::indexed:
57 for (idx_type i = bs.blend_shape_index_range[0]; i < bs.blend_shape_index_range[1]; ++i)
58 if (blend_shape_indices[i] == vi)
59 return blend_shape_data[i];
60 break;
61 case blend_shape_mode::range_indexed:
62 for (idx_type off = 0, i = bs.blend_shape_index_range[0]; i < bs.blend_shape_index_range[1];
63 off += blend_shape_indices[i+1]-blend_shape_indices[i], i+=2)
64 if (blend_shape_indices[i] <= vi && vi < blend_shape_indices[i+1])
65 return blend_shape_data[off + vi- blend_shape_indices[i]];
66 break;
67 }
68 return vec3_type(T(0));
69}
70template <typename T>
72{
73 return blend_shapes.size();
74}
75template <typename T>
76void dynamic_mesh<T>::set_vertex_weight_mode(vertex_weight_mode mode)
77{
78 weight_mode = mode;
79}
80template <typename T>
81void dynamic_mesh<T>::begin_vertex_weight_vertex()
82{
83 vertex_weight_index_begins.push_back(uint32_t(vertex_weight_data.size()));
84}
85template <typename T>
87{
88 switch (weight_mode) {
89 case vertex_weight_mode::dense:
90 return uint32_t(vi * get_nr_joints());
91 case vertex_weight_mode::sparse:
92 return vertex_weight_index_begins[vi];
93 case vertex_weight_mode::fixed:
94 return uint32_t(vi * max_nr_weights_per_vertex);
95 }
96 return -1;
98template <typename T>
100{
101 switch (weight_mode) {
102 case vertex_weight_mode::dense:
103 return uint32_t((vi+1)*get_nr_joints());
104 case vertex_weight_mode::sparse:
105 return uint32_t(vi >= vertex_weight_index_begins.size() ? vertex_weight_data.size() : vertex_weight_index_begins[vi]);
106 case vertex_weight_mode::fixed:
107 return uint32_t((vi+1)*max_nr_weights_per_vertex);
108 }
109 return -1;
110}
111template <typename T>
114 switch (weight_mode) {
115 case vertex_weight_mode::dense:
116 return vertex_weight_data[vi * get_nr_joints() + ji];
117 default:
118 for (idx_type i = vertex_weight_begin(vi); i < vertex_weight_end(vi); ++i)
119 if (vertex_weight_indices[i] == ji)
120 return vertex_weight_data[i];
121 break;
122 }
123 return T(0);
124}
126template <typename T>
128{
129 vertex_weight_data.push_back(w);
130}
131template <typename T>
133{
134 vertex_weight_indices.push_back(i);
135}
136template <typename T>
138{
139 return vertex_weight_data.size();
140}
141template <typename T>
143{
144 return vertex_weight_indices.size();
145}
146template <typename T>
149 return idx_type(joint_parents.size());
151template <typename T>
152std::vector<typename dynamic_mesh<T>::mat4_type> dynamic_mesh<T>::compute_joint_transformations(const std::vector<vec3_type>& reference_joint_locations,
153 const vec3_type& translation, const std::vector<vec3_type>& target_spin_vectors) const
154{
155 std::vector<mat3_type> target_rotations;
156 for (const auto& sv : target_spin_vectors)
157 target_rotations.push_back(cgv::math::rotate3s<T>(sv));
158 return compute_joint_transformations(reference_joint_locations, translation, target_rotations);
159}
160template <typename T>
161std::vector<typename dynamic_mesh<T>::mat4_type> dynamic_mesh<T>::compute_joint_transformations(const std::vector<vec3_type>& reference_joint_locations,
162 const vec3_type& translation, const std::vector<mat3_type>& target_rotations) const
163{
164 // compute joint transformations in rest pose and in target pose
165 std::vector<mat4_type> Is, Ts;
166 mat4_type I = cgv::math::identity4<float>();
167 vec3_type& t = reinterpret_cast<vec3_type&>(I.col(3));
168 t = reference_joint_locations.front();
169 Is.push_back(I);
170 Ts.push_back(pose4(target_rotations.front(), t + translation));
171 unsigned ji;
172 for (ji = 1; ji < target_rotations.size(); ++ji) {
173 t = reference_joint_locations[ji] - reference_joint_locations[joint_parents[ji]];
174 Is.push_back(I);
175 Ts.push_back(pose4(target_rotations[ji], t));
176 }
177 // concatenate poses
178 for (ji = 1; ji < target_rotations.size(); ++ji) {
179 Is[ji] = Is[joint_parents[ji]] * Is[ji];
180 Ts[ji] = Ts[joint_parents[ji]] * Ts[ji];
182 // compute final rest pose to pose transformations
183 for (ji = 0; ji < target_rotations.size(); ++ji)
184 Ts[ji] = Ts[ji] * inverse(Is[ji]);
185
186 return Ts;
187}
188
189
190template <typename T>
191void dynamic_mesh<T>::apply_blend_shapes(const std::vector<T>& weights, idx_type blend_shape_offset, bool only_add, bool use_parallel_implementation)
192{
193 if (!only_add)
194 this->positions = reference_positions;
195 if (use_parallel_implementation) {
196 // here we assume that all blend shapes have mode direct and address whole mesh
197
198 // first extract per blend shape pointers to the blend shape data start
199 std::vector<const vec3_type*> bs_ptrs;
200 int n = this->get_nr_positions();
201 for (size_t bi = blend_shape_offset; bi < weights.size() + blend_shape_offset; ++bi) {
202 const auto& bs = blend_shapes[bi];
203 assert(bs.mode == blend_shape_mode::direct);
204 assert(bs.blend_shape_data_range[1] - bs.blend_shape_data_range[0] == n);
205 bs_ptrs.push_back(&blend_shape_data[bs.blend_shape_data_range[0]]);
206 }
207 // next apply them to mesh positions
208#pragma omp parallel for
209 for (int vi = 0; vi < n; ++vi) {
210 vec3_type p(T(0));
211 for (int wi = 0; wi < weights.size(); ++wi)
212 p += weights[wi]*bs_ptrs[wi][vi];
213 this->position(vi) += p;
214 }
215 }
216 else {
217 for (idx_type bi = blend_shape_offset, wi = 0; wi < weights.size(); ++wi, ++bi) {
218 const auto& bs = blend_shapes[bi];
219 switch (bs.mode) {
220 case blend_shape_mode::direct:
221 for (int j=0, i = bs.blend_shape_data_range[0]; i < int(bs.blend_shape_data_range[1]); ++i, ++j)
222 this->positions[j] += weights[wi] * blend_shape_data[i];
223 break;
224 case blend_shape_mode::indexed:
225 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)
226 this->positions[blend_shape_indices[j]] += weights[wi] * blend_shape_data[i];
227 break;
228 case blend_shape_mode::range_indexed:
229 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)
230 for (uint32_t k = blend_shape_indices[j]; k < blend_shape_indices[j + 1]; ++k, ++i)
231 this->positions[k] += weights[wi] * blend_shape_data[i];
232 break;
233 }
234 }
235 }
236}
237template <typename T>
238const std::vector<typename dynamic_mesh<T>::vec3_type>& dynamic_mesh<T>::get_intermediate_positions() const
239{
240 return intermediate_positions;
241}
242
243template <typename T>
244const std::vector<int32_t>& dynamic_mesh<T>::get_joint_parents() const
245{
246 return joint_parents;
247}
248template <typename T>
250{
251 return joint_parents;
252}
253template <typename T>
255{
256 reference_positions = this->positions;
257}
258template <typename T>
260{
261 intermediate_positions = this->positions;
262}
263template <typename T>
265{
266 this->positions = intermediate_positions;
267}
268
269template <typename T>
270void dynamic_mesh<T>::lbs(const std::vector<mat4_type>& joint_matrices, lbs_source_mode mode)
271{
272 std::vector<vec3_type> tmp;
273 if (mode == lbs_source_mode::position)
274 tmp = this->positions;
275 const std::vector<vec3_type>& P = mode == lbs_source_mode::position ? tmp : (
276 mode == lbs_source_mode::intermediate ? intermediate_positions : reference_positions);
277 switch (weight_mode) {
278 case vertex_weight_mode::dense:
279 for (size_t pi = 0, wi = 0; pi < P.size(); ++pi) {
280 vec4_type p = vec4_type(P[pi], 1.0f);
281 vec4_type q = vec4_type(0.0f);
282 for (unsigned ji = 0; ji < joint_parents.size(); ++ji, ++wi)
283 q += vertex_weight_data[wi] * (joint_matrices[ji] * p);
284 this->position(idx_type(pi)) = q;
285 }
286 break;
287 case vertex_weight_mode::sparse:
288 for (size_t pi = 0; pi < P.size(); ++pi) {
289 vec4_type p = vec4_type(P[pi], 1.0f);
290 vec4_type q = vec4_type(0.0f);
291 size_t beg = vertex_weight_index_begins[pi];
292 size_t end = pi+1 < P.size() ? vertex_weight_index_begins[pi+1] : vertex_weight_indices.size();
293 for (size_t wi = beg; wi < end; ++wi)
294 q += vertex_weight_data[wi] * (joint_matrices[vertex_weight_indices[wi]] * p);
295 this->position(idx_type(pi)) = q;
296 }
297 break;
298 case vertex_weight_mode::fixed:
299 for (size_t pi = 0; pi < P.size(); ++pi) {
300 vec4_type p = vec4_type(P[pi], 1.0f);
301 vec4_type q = vec4_type(0.0f);
302 size_t beg = vertex_weight_index_begins[pi];
303 size_t end = pi + 1 < P.size() ? vertex_weight_index_begins[pi + 1] : vertex_weight_indices.size();
304 for (size_t wi = beg; wi < end; ++wi)
305 q += vertex_weight_data[wi] * (joint_matrices[vertex_weight_indices[wi]] * p);
306 this->position(idx_type(pi)) = q;
307 }
308 break;
309 }
310}
311
312template class dynamic_mesh<float>;
313template class dynamic_mesh<double>;
314
315 }
316 }
317}
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:29
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.