Panda3D
Loading...
Searching...
No Matches
movingPartMatrix.cxx
Go to the documentation of this file.
1/**
2 * PANDA 3D SOFTWARE
3 * Copyright (c) Carnegie Mellon University. All rights reserved.
4 *
5 * All use of this software is subject to the terms of the revised BSD
6 * license. You should have received a copy of this license along
7 * with this source code in a file named "LICENSE."
8 *
9 * @file movingPartMatrix.cxx
10 * @author drose
11 * @date 1999-02-23
12 */
13
14#include "movingPartMatrix.h"
17#include "compose_matrix.h"
18#include "datagram.h"
19#include "datagramIterator.h"
20#include "bamReader.h"
21#include "bamWriter.h"
22#include "config_chan.h"
23
25
26TypeHandle MovingPartMatrix::_type_handle;
27
28/**
29 *
30 */
31MovingPartMatrix::
32~MovingPartMatrix() {
33}
34
35
36/**
37 * Creates and returns a new AnimChannel that is not part of any hierarchy,
38 * but that returns the default value associated with this part.
39 */
42 LVecBase3 pos, hpr, scale, shear;
43 decompose_matrix(_default_value, pos, hpr, scale, shear);
44 return new AnimChannelMatrixFixed(get_name(), pos, hpr, scale);
45}
46
47/**
48 * Attempts to blend the various matrix values indicated, and sets the _value
49 * member to the resulting matrix.
50 */
52get_blend_value(const PartBundle *root) {
53 // If a forced channel is set on this particular joint, we always return
54 // that value instead of performing the blend. Furthermore, the frame
55 // number is always 0 for the forced channel.
56 if (_forced_channel != nullptr) {
57 ChannelType *channel = DCAST(ChannelType, _forced_channel);
58 channel->get_value(0, _value);
59 return;
60 }
61
62 PartBundle::CDReader cdata(root->_cycler);
63
64 if (cdata->_blend.empty()) {
65 // No channel is bound; supply the default value.
66 if (restore_initial_pose) {
67 _value = _default_value;
68 }
69
70 } else if (_effective_control != nullptr &&
71 !cdata->_frame_blend_flag) {
72 // A single value, the normal case.
73 ChannelType *channel = DCAST(ChannelType, _effective_channel);
74 channel->get_value(_effective_control->get_frame(), _value);
75
76 } else {
77 // A blend of two or more values, either between multiple different
78 // animations, or between consecutive frames of the same animation (or
79 // both).
80 switch (cdata->_blend_type) {
81 case PartBundle::BT_linear:
82 {
83 // An ordinary, linear blend.
84 LMatrix4 net_value = LMatrix4::zeros_mat();
85 PN_stdfloat net_effect = 0.0f;
86
87 PartBundle::ChannelBlend::const_iterator cbi;
88 for (cbi = cdata->_blend.begin(); cbi != cdata->_blend.end(); ++cbi) {
89 AnimControl *control = (*cbi).first;
90 PN_stdfloat effect = (*cbi).second;
91 nassertv(effect != 0.0f);
92
93 int channel_index = control->get_channel_index();
94 nassertv(channel_index >= 0 && channel_index < (int)_channels.size());
95 ChannelType *channel = DCAST(ChannelType, _channels[channel_index]);
96 if (channel != nullptr) {
97 ValueType v;
98 channel->get_value(control->get_frame(), v);
99
100 if (!cdata->_frame_blend_flag) {
101 // Hold the current frame until the next one is ready.
102 net_value += v * effect;
103 } else {
104 // Blend between successive frames.
105 PN_stdfloat frac = (PN_stdfloat)control->get_frac();
106 net_value += v * (effect * (1.0f - frac));
107
108 channel->get_value(control->get_next_frame(), v);
109 net_value += v * (effect * frac);
110 }
111 net_effect += effect;
112 }
113 }
114
115 if (net_effect == 0.0f) {
116 if (restore_initial_pose) {
117 _value = _default_value;
118 }
119 } else {
120 _value = net_value / net_effect;
121 }
122 }
123 break;
124
125 case PartBundle::BT_normalized_linear:
126 {
127 // A normalized linear blend. This means we do a linear blend without
128 // scales or shears, normalize the scale and shear components of the
129 // resulting matrix to eliminate artificially-introduced scales, and
130 // then reapply the scales and shears.
131
132 LMatrix4 net_value = LMatrix4::zeros_mat();
133 LVecBase3 scale(0.0f, 0.0f, 0.0f);
134 LVecBase3 shear(0.0f, 0.0f, 0.0f);
135 PN_stdfloat net_effect = 0.0f;
136
137 PartBundle::ChannelBlend::const_iterator cbi;
138 for (cbi = cdata->_blend.begin(); cbi != cdata->_blend.end(); ++cbi) {
139 AnimControl *control = (*cbi).first;
140 PN_stdfloat effect = (*cbi).second;
141 nassertv(effect != 0.0f);
142
143 ChannelType *channel = nullptr;
144 int channel_index = control->get_channel_index();
145 if (channel_index >= 0 && channel_index < (int)_channels.size()) {
146 channel = DCAST(ChannelType, _channels[channel_index]);
147 }
148 if (channel != nullptr) {
149 int frame = control->get_frame();
150 ValueType v;
151 LVecBase3 iscale, ishear;
152 channel->get_value_no_scale_shear(frame, v);
153 channel->get_scale(frame, iscale);
154 channel->get_shear(frame, ishear);
155
156 if (!cdata->_frame_blend_flag) {
157 // Hold the current frame until the next one is ready.
158 net_value += v * effect;
159 scale += iscale * effect;
160 shear += ishear * effect;
161 } else {
162 // Blend between successive frames.
163 PN_stdfloat frac = (PN_stdfloat)control->get_frac();
164 PN_stdfloat e0 = effect * (1.0f - frac);
165 net_value += v * e0;
166 scale += iscale * e0;
167 shear += ishear * e0;
168
169 int next_frame = control->get_next_frame();
170 channel->get_value_no_scale_shear(next_frame, v);
171 channel->get_scale(next_frame, iscale);
172 channel->get_shear(next_frame, ishear);
173 PN_stdfloat e1 = effect * frac;
174 net_value += v * e1;
175 scale += iscale * e1;
176 shear += ishear * e1;
177 }
178 net_effect += effect;
179 }
180 }
181
182 if (net_effect == 0.0f) {
183 if (restore_initial_pose) {
184 _value = _default_value;
185 }
186
187 } else {
188 net_value /= net_effect;
189 scale /= net_effect;
190 shear /= net_effect;
191
192 // Now rebuild the matrix with the correct scale values.
193
194 LVector3 false_scale, false_shear, hpr, translate;
195 decompose_matrix(net_value, false_scale, false_shear, hpr, translate);
196 compose_matrix(_value, scale, shear, hpr, translate);
197 }
198 }
199 break;
200
201 case PartBundle::BT_componentwise:
202 {
203 // Componentwise linear, including componentwise H, P, and R.
204 LVecBase3 scale(0.0f, 0.0f, 0.0f);
205 LVecBase3 hpr(0.0f, 0.0f, 0.0f);
206 LVecBase3 pos(0.0f, 0.0f, 0.0f);
207 LVecBase3 shear(0.0f, 0.0f, 0.0f);
208 PN_stdfloat net_effect = 0.0f;
209
210 PartBundle::ChannelBlend::const_iterator cbi;
211 for (cbi = cdata->_blend.begin(); cbi != cdata->_blend.end(); ++cbi) {
212 AnimControl *control = (*cbi).first;
213 PN_stdfloat effect = (*cbi).second;
214 nassertv(effect != 0.0f);
215
216 ChannelType *channel = nullptr;
217 int channel_index = control->get_channel_index();
218 if (channel_index >= 0 && channel_index < (int)_channels.size()) {
219 channel = DCAST(ChannelType, _channels[channel_index]);
220 }
221 if (channel != nullptr) {
222 int frame = control->get_frame();
223 LVecBase3 iscale, ihpr, ipos, ishear;
224 channel->get_scale(frame, iscale);
225 channel->get_hpr(frame, ihpr);
226 channel->get_pos(frame, ipos);
227 channel->get_shear(frame, ishear);
228
229 if (!cdata->_frame_blend_flag) {
230 // Hold the current frame until the next one is ready.
231 scale += iscale * effect;
232 hpr += ihpr * effect;
233 pos += ipos * effect;
234 shear += ishear * effect;
235 } else {
236 // Blend between successive frames.
237 PN_stdfloat frac = (PN_stdfloat)control->get_frac();
238 PN_stdfloat e0 = effect * (1.0f - frac);
239
240 scale += iscale * e0;
241 hpr += ihpr * e0;
242 pos += ipos * e0;
243 shear += ishear * e0;
244
245 int next_frame = control->get_next_frame();
246 channel->get_scale(next_frame, iscale);
247 channel->get_hpr(next_frame, ihpr);
248 channel->get_pos(next_frame, ipos);
249 channel->get_shear(next_frame, ishear);
250 PN_stdfloat e1 = effect * frac;
251
252 scale += iscale * e1;
253 hpr += ihpr * e1;
254 pos += ipos * e1;
255 shear += ishear * e1;
256 }
257 net_effect += effect;
258 }
259 }
260
261 if (net_effect == 0.0f) {
262 if (restore_initial_pose) {
263 _value = _default_value;
264 }
265
266 } else {
267 scale /= net_effect;
268 hpr /= net_effect;
269 pos /= net_effect;
270 shear /= net_effect;
271
272 compose_matrix(_value, scale, shear, hpr, pos);
273 }
274 }
275 break;
276
277 case PartBundle::BT_componentwise_quat:
278 {
279 // Componentwise linear, except for rotation, which is a quaternion.
280 LVecBase3 scale(0.0f, 0.0f, 0.0f);
281 LQuaternion quat(0.0f, 0.0f, 0.0f, 0.0f);
282 LVecBase3 pos(0.0f, 0.0f, 0.0f);
283 LVecBase3 shear(0.0f, 0.0f, 0.0f);
284 PN_stdfloat net_effect = 0.0f;
285
286 PartBundle::ChannelBlend::const_iterator cbi;
287 for (cbi = cdata->_blend.begin(); cbi != cdata->_blend.end(); ++cbi) {
288 AnimControl *control = (*cbi).first;
289 PN_stdfloat effect = (*cbi).second;
290 nassertv(effect != 0.0f);
291
292 ChannelType *channel = nullptr;
293 int channel_index = control->get_channel_index();
294 if (channel_index >= 0 && channel_index < (int)_channels.size()) {
295 channel = DCAST(ChannelType, _channels[channel_index]);
296 }
297 if (channel != nullptr) {
298 int frame = control->get_frame();
299 LVecBase3 iscale, ipos, ishear;
300 LQuaternion iquat;
301 channel->get_scale(frame, iscale);
302 channel->get_quat(frame, iquat);
303 channel->get_pos(frame, ipos);
304 channel->get_shear(frame, ishear);
305
306 if (!cdata->_frame_blend_flag) {
307 // Hold the current frame until the next one is ready.
308 scale += iscale * effect;
309 quat += iquat * effect;
310 pos += ipos * effect;
311 shear += ishear * effect;
312
313 } else {
314 // Blend between successive frames.
315 PN_stdfloat frac = (PN_stdfloat)control->get_frac();
316 PN_stdfloat e0 = effect * (1.0f - frac);
317
318 scale += iscale * e0;
319 quat += iquat * e0;
320 pos += ipos * e0;
321 shear += ishear * e0;
322
323 int next_frame = control->get_next_frame();
324 channel->get_scale(next_frame, iscale);
325 channel->get_quat(next_frame, iquat);
326 channel->get_pos(next_frame, ipos);
327 channel->get_shear(next_frame, ishear);
328 PN_stdfloat e1 = effect * frac;
329
330 scale += iscale * e1;
331 quat += iquat * e1;
332 pos += ipos * e1;
333 shear += ishear * e1;
334 }
335 net_effect += effect;
336 }
337 }
338
339 if (net_effect == 0.0f) {
340 if (restore_initial_pose) {
341 _value = _default_value;
342 }
343
344 } else {
345 scale /= net_effect;
346 quat /= net_effect;
347 pos /= net_effect;
348 shear /= net_effect;
349
350 // There should be no need to normalize the quaternion, assuming all
351 // of the input quaternions were already normalized.
352
353 _value = LMatrix4::scale_shear_mat(scale, shear) * quat;
354 _value.set_row(3, pos);
355 }
356 }
357 break;
358 }
359 }
360}
361
362/**
363 * Freezes this particular joint so that it will always hold the specified
364 * transform. Returns true if this is a joint that can be so frozen, false
365 * otherwise. This is called internally by PartBundle::freeze_joint().
366 */
368apply_freeze_matrix(const LVecBase3 &pos, const LVecBase3 &hpr, const LVecBase3 &scale) {
369 _forced_channel = new AnimChannelMatrixFixed(get_name(), pos, hpr, scale);
370 return true;
371}
372
373/**
374 * Specifies a node to influence this particular joint so that it will always
375 * hold the node's transform. Returns true if this is a joint that can be so
376 * controlled, false otherwise. This is called internally by
377 * PartBundle::control_joint().
378 */
382 chan->set_value_node(node);
383 _forced_channel = chan;
384 return true;
385}
386
387/**
388 * Factory method to generate a MovingPartMatrix object
389 */
393 DatagramIterator scan;
394 BamReader *manager;
395
396 parse_params(params, scan, manager);
397 me->fillin(scan, manager);
398 return me;
399}
400
401/**
402 * Factory method to generate a MovingPartMatrix object
403 */
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
void parse_params(const FactoryParams &params, DatagramIterator &scan, BamReader *&manager)
Takes in a FactoryParams, passed from a WritableFactory into any TypedWritable's make function,...
Definition bamReader.I:275
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
Parent class for all animation channels.
An animation channel that accepts a matrix each frame from some dynamic input provided by code.
set_value_node
Specifies a node whose transform will be queried each frame to implicitly specify the transform of th...
A specialization on AnimChannel to add all the special matrix component operations.
virtual void get_scale(int frame, LVecBase3 &scale)
Returns the x, y, and z scale components associated with the current frame.
Definition animChannel.I:80
virtual void get_hpr(int frame, LVecBase3 &hpr)
Returns the h, p, and r components associated with the current frame.
Definition animChannel.I:90
virtual void get_quat(int frame, LQuaternion &quat)
Returns the rotation component associated with the current frame, expressed as a quaternion.
virtual void get_pos(int frame, LVecBase3 &pos)
Returns the x, y, and z translation components associated with the current frame.
virtual void get_value_no_scale_shear(int frame, ValueType &value)
Returns the value associated with the current frame, with no scale or share components.
Definition animChannel.I:70
virtual void get_shear(int frame, LVecBase3 &shear)
Returns the a, b, and c shear components associated with the current frame.
Controls the timing of a character animation.
Definition animControl.h:38
int get_channel_index() const
Returns the particular channel index associated with this AnimControl.
Definition animControl.I:52
get_frame
Returns the current integer frame number.
get_next_frame
Returns the current integer frame number + 1, constrained to the range 0 <= f < get_num_frames().
get_frac
Returns the fractional part of the current frame.
This is the fundamental interface for extracting binary objects from a Bam file, as generated by a Ba...
Definition bamReader.h:110
static WritableFactory * get_factory()
Returns the global WritableFactory for generating TypedWritable objects.
Definition bamReader.I:177
This template class calls PipelineCycler::read_unlocked(), and then provides a transparent read-only ...
A class to retrieve the individual data elements previously stored in a Datagram.
An instance of this class is passed to the Factory when requesting it to do its business and construc...
void register_factory(TypeHandle handle, CreateFunc *func, void *user_data=nullptr)
Registers a new kind of thing the Factory will be able to create.
Definition factory.I:73
This is a particular kind of MovingPart that accepts a matrix each frame.
virtual void get_blend_value(const PartBundle *root)
Attempts to blend the various matrix values indicated, and sets the _value member to the resulting ma...
static TypedWritable * make_MovingPartMatrix(const FactoryParams &params)
Factory method to generate a MovingPartMatrix object.
virtual AnimChannelBase * make_default_channel() const
Creates and returns a new AnimChannel that is not part of any hierarchy, but that returns the default...
virtual bool apply_control(PandaNode *node)
Specifies a node to influence this particular joint so that it will always hold the node's transform.
static void register_with_read_factory()
Factory method to generate a MovingPartMatrix object.
virtual bool apply_freeze_matrix(const LVecBase3 &pos, const LVecBase3 &hpr, const LVecBase3 &scale)
Freezes this particular joint so that it will always hold the specified transform.
This is the template instantiation of MovingPartBase, on the particular type of value provided by the...
Definition movingPart.h:27
A basic node of the scene graph or data graph.
Definition pandaNode.h:65
This is the root of a MovingPart hierarchy.
Definition partBundle.h:46
TypeHandle is the identifier used to differentiate C++ class types.
Definition typeHandle.h:81
Base class for objects that can be written to and read from Bam files.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.