Remove shear from BT_normalized_linear, add BT_componentwise and BT_componentwise_quat

This commit is contained in:
David Rose 2006-01-19 01:03:12 +00:00
parent a998cf46cd
commit 34c1491fbb
9 changed files with 408 additions and 105 deletions

View File

@ -82,16 +82,17 @@ get_value(int, TYPENAME AnimChannel<SwitchType>::ValueType &) {
#endif
////////////////////////////////////////////////////////////////////
// Function: AnimChannel::get_value_no_scale
// Function: AnimChannel::get_value_no_scale_share
// Access: Public, Virtual
// Description: Returns the value associated with the current frame,
// with no scale components. This only makes sense for
// a matrix-type channel, although for fiddly technical
// reasons the function exists for all channels.
// with no scale or share components. This only makes
// sense for a matrix-type channel, although for fiddly
// technical reasons the function exists for all
// channels.
////////////////////////////////////////////////////////////////////
template<class SwitchType>
void AnimChannel<SwitchType>::
get_value_no_scale(int frame, ValueType &value) {
get_value_no_scale_shear(int frame, ValueType &value) {
get_value(frame, value);
}
@ -104,10 +105,60 @@ get_value_no_scale(int frame, ValueType &value) {
////////////////////////////////////////////////////////////////////
template<class SwitchType>
void AnimChannel<SwitchType>::
get_scale(int, float scale[3]) {
scale[0] = 1.0f;
scale[1] = 1.0f;
scale[2] = 1.0f;
get_scale(int, LVecBase3f &scale) {
nassertv(false);
}
////////////////////////////////////////////////////////////////////
// Function: AnimChannel::get_hpr
// Access: Public, Virtual
// Description: Returns the h, p, and r components associated
// with the current frame. As above, this only makes
// sense for a matrix-type channel.
////////////////////////////////////////////////////////////////////
template<class SwitchType>
void AnimChannel<SwitchType>::
get_hpr(int, LVecBase3f &hpr) {
nassertv(false);
}
////////////////////////////////////////////////////////////////////
// Function: AnimChannel::get_quat
// Access: Public, Virtual
// Description: Returns the rotation component associated with the
// current frame, expressed as a quaternion. As above,
// this only makes sense for a matrix-type channel.
////////////////////////////////////////////////////////////////////
template<class SwitchType>
void AnimChannel<SwitchType>::
get_quat(int, LQuaternionf &quat) {
nassertv(false);
}
////////////////////////////////////////////////////////////////////
// Function: AnimChannel::get_pos
// Access: Public, Virtual
// Description: Returns the x, y, and z translation components
// associated with the current frame. As above, this
// only makes sense for a matrix-type channel.
////////////////////////////////////////////////////////////////////
template<class SwitchType>
void AnimChannel<SwitchType>::
get_pos(int, LVecBase3f &pos) {
nassertv(false);
}
////////////////////////////////////////////////////////////////////
// Function: AnimChannel::get_shear
// Access: Public, Virtual
// Description: Returns the a, b, and c shear components associated
// with the current frame. As above, this only makes
// sense for a matrix-type channel.
////////////////////////////////////////////////////////////////////
template<class SwitchType>
void AnimChannel<SwitchType>::
get_shear(int, LVecBase3f &shear) {
nassertv(false);
}

View File

@ -47,12 +47,13 @@ public:
PUBLISHED:
virtual void get_value(int frame, ValueType &value)=0;
// These two functions only have meaning for matrix types.
virtual void get_value_no_scale(int frame, ValueType &value);
virtual void get_scale(int frame, float scale[3]);
// The second parameter above should really by LVector3f instead of
// float[3], but there seems to be a compiler bug in EGCS that
// doesn't like that. So we have this kludge for now.
// These transform-component methods only have meaning for matrix types.
virtual void get_value_no_scale_shear(int frame, ValueType &value);
virtual void get_scale(int frame, LVecBase3f &scale);
virtual void get_hpr(int frame, LVecBase3f &hpr);
virtual void get_quat(int frame, LQuaternionf &quat);
virtual void get_pos(int frame, LVecBase3f &pos);
virtual void get_shear(int frame, LVecBase3f &shear);
virtual TypeHandle get_value_type() const;

View File

@ -80,14 +80,14 @@ get_value(int, LMatrix4f &mat) {
}
////////////////////////////////////////////////////////////////////
// Function: AnimChannelMatrixDynamic::get_value_no_scale
// Function: AnimChannelMatrixDynamic::get_value_no_scale_shear
// Access: Public, Virtual
// Description: Gets the value of the channel at the indicated frame,
// without any scale information.
// without any scale or shear information.
////////////////////////////////////////////////////////////////////
void AnimChannelMatrixDynamic::
get_value_no_scale(int frame, LMatrix4f &mat) {
if (_value->has_scale()) {
get_value_no_scale_shear(int frame, LMatrix4f &mat) {
if (_value->has_scale() || _value->has_shear()) {
compose_matrix(mat, LVecBase3f(1.0f, 1.0f, 1.0f),
_value->get_hpr(), _value->get_pos());
} else {
@ -101,11 +101,56 @@ get_value_no_scale(int frame, LMatrix4f &mat) {
// Description: Gets the scale value at the indicated frame.
////////////////////////////////////////////////////////////////////
void AnimChannelMatrixDynamic::
get_scale(int frame, float scale[3]) {
const LVecBase3f &sc = _value->get_scale();
scale[0] = sc[0];
scale[1] = sc[1];
scale[2] = sc[2];
get_scale(int frame, LVecBase3f &scale) {
scale = _value->get_scale();
}
////////////////////////////////////////////////////////////////////
// Function: AnimChannelMatrixDynamic::get_hpr
// Access: Public, Virtual
// Description: Returns the h, p, and r components associated
// with the current frame. As above, this only makes
// sense for a matrix-type channel.
////////////////////////////////////////////////////////////////////
void AnimChannelMatrixDynamic::
get_hpr(int, LVecBase3f &hpr) {
hpr = _value->get_hpr();
}
////////////////////////////////////////////////////////////////////
// Function: AnimChannelMatrixDynamic::get_quat
// Access: Public, Virtual
// Description: Returns the rotation component associated with the
// current frame, expressed as a quaternion. As above,
// this only makes sense for a matrix-type channel.
////////////////////////////////////////////////////////////////////
void AnimChannelMatrixDynamic::
get_quat(int, LQuaternionf &quat) {
quat = _value->get_quat();
}
////////////////////////////////////////////////////////////////////
// Function: AnimChannelMatrixDynamic::get_pos
// Access: Public, Virtual
// Description: Returns the x, y, and z translation components
// associated with the current frame. As above, this
// only makes sense for a matrix-type channel.
////////////////////////////////////////////////////////////////////
void AnimChannelMatrixDynamic::
get_pos(int, LVecBase3f &pos) {
pos = _value->get_pos();
}
////////////////////////////////////////////////////////////////////
// Function: AnimChannelMatrixDynamic::get_shear
// Access: Public, Virtual
// Description: Returns the a, b, and c shear components associated
// with the current frame. As above, this only makes
// sense for a matrix-type channel.
////////////////////////////////////////////////////////////////////
void AnimChannelMatrixDynamic::
get_shear(int, LVecBase3f &shear) {
shear = _value->get_shear();
}
////////////////////////////////////////////////////////////////////

View File

@ -48,8 +48,13 @@ protected:
public:
virtual bool has_changed(int last_frame, int this_frame);
virtual void get_value(int frame, LMatrix4f &mat);
virtual void get_value_no_scale(int frame, LMatrix4f &value);
virtual void get_scale(int frame, float scale[3]);
virtual void get_value_no_scale_shear(int frame, LMatrix4f &value);
virtual void get_scale(int frame, LVecBase3f &scale);
virtual void get_hpr(int frame, LVecBase3f &hpr);
virtual void get_quat(int frame, LQuaternionf &quat);
virtual void get_pos(int frame, LVecBase3f &pos);
virtual void get_shear(int frame, LVecBase3f &shear);
PUBLISHED:
void set_value(const LMatrix4f &value);

View File

@ -106,19 +106,22 @@ get_value(int frame, LMatrix4f &mat) {
}
////////////////////////////////////////////////////////////////////
// Function: AnimChannelMatrixXfmTable::get_value_no_scale
// Function: AnimChannelMatrixXfmTable::get_value_no_scale_shear
// Access: Public, Virtual
// Description: Gets the value of the channel at the indicated frame,
// without any scale information.
// without any scale or shear information.
////////////////////////////////////////////////////////////////////
void AnimChannelMatrixXfmTable::
get_value_no_scale(int frame, LMatrix4f &mat) {
get_value_no_scale_shear(int frame, LMatrix4f &mat) {
float components[num_matrix_components];
components[0] = 1.0f;
components[1] = 1.0f;
components[2] = 1.0f;
components[3] = 0.0f;
components[4] = 0.0f;
components[5] = 0.0f;
for (int i = 3; i < num_matrix_components; i++) {
for (int i = 6; i < num_matrix_components; i++) {
if (_tables[i].empty()) {
components[i] = get_default_value(i);
} else {
@ -135,23 +138,99 @@ get_value_no_scale(int frame, LMatrix4f &mat) {
// Description: Gets the scale value at the indicated frame.
////////////////////////////////////////////////////////////////////
void AnimChannelMatrixXfmTable::
get_scale(int frame, float scale[3]) {
get_scale(int frame, LVecBase3f &scale) {
for (int i = 0; i < 3; i++) {
if (_tables[i].empty()) {
scale[i] = get_default_value(i);
scale[i] = 1.0f;
} else {
scale[i] = _tables[i][frame % _tables[i].size()];
}
}
}
////////////////////////////////////////////////////////////////////
// Function: AnimChannelMatrixXfmTable::get_hpr
// Access: Public, Virtual
// Description: Returns the h, p, and r components associated
// with the current frame. As above, this only makes
// sense for a matrix-type channel.
////////////////////////////////////////////////////////////////////
void AnimChannelMatrixXfmTable::
get_hpr(int frame, LVecBase3f &hpr) {
for (int i = 0; i < 3; i++) {
if (_tables[i + 6].empty()) {
hpr[i] = 0.0f;
} else {
hpr[i] = _tables[i + 6][frame % _tables[i + 6].size()];
}
}
}
////////////////////////////////////////////////////////////////////
// Function: AnimChannelMatrixXfmTable::get_quat
// Access: Public, Virtual
// Description: Returns the rotation component associated with the
// current frame, expressed as a quaternion. As above,
// this only makes sense for a matrix-type channel.
////////////////////////////////////////////////////////////////////
void AnimChannelMatrixXfmTable::
get_quat(int frame, LQuaternionf &quat) {
LVecBase3f hpr;
for (int i = 0; i < 3; i++) {
if (_tables[i + 6].empty()) {
hpr[i] = 0.0f;
} else {
hpr[i] = _tables[i + 6][frame % _tables[i + 6].size()];
}
}
quat.set_hpr(hpr);
}
////////////////////////////////////////////////////////////////////
// Function: AnimChannelMatrixXfmTable::get_pos
// Access: Public, Virtual
// Description: Returns the x, y, and z translation components
// associated with the current frame. As above, this
// only makes sense for a matrix-type channel.
////////////////////////////////////////////////////////////////////
void AnimChannelMatrixXfmTable::
get_pos(int frame, LVecBase3f &pos) {
for (int i = 0; i < 3; i++) {
if (_tables[i + 9].empty()) {
pos[i] = 0.0f;
} else {
pos[i] = _tables[i + 9][frame % _tables[i + 9].size()];
}
}
}
////////////////////////////////////////////////////////////////////
// Function: AnimChannelMatrixXfmTable::get_shear
// Access: Public, Virtual
// Description: Returns the a, b, and c shear components associated
// with the current frame. As above, this only makes
// sense for a matrix-type channel.
////////////////////////////////////////////////////////////////////
void AnimChannelMatrixXfmTable::
get_shear(int frame, LVecBase3f &shear) {
for (int i = 0; i < 3; i++) {
if (_tables[i + 3].empty()) {
shear[i] = 0.0f;
} else {
shear[i] = _tables[i + 3][frame % _tables[i + 3].size()];
}
}
}
////////////////////////////////////////////////////////////////////
// Function: AnimChannelMatrixXfmTable::set_table
// Access: Public
// Description: Assigns the indicated table. table_id is one of 'i',
// 'j', 'k', for scale, 'h', 'p', 'r', for rotation, and
// 'x', 'y', 'z', for translation. The new table must
// have either zero, one, or get_num_frames() frames.
// 'j', 'k', for scale, 'a', 'b', 'c' for shear, 'h',
// 'p', 'r', for rotation, and 'x', 'y', 'z', for
// translation. The new table must have either zero,
// one, or get_num_frames() frames.
////////////////////////////////////////////////////////////////////
void AnimChannelMatrixXfmTable::
set_table(char table_id, const CPTA_float &table) {

View File

@ -47,8 +47,13 @@ public:
virtual bool has_changed(int last_frame, int this_frame);
virtual void get_value(int frame, LMatrix4f &mat);
virtual void get_value_no_scale(int frame, LMatrix4f &value);
virtual void get_scale(int frame, float scale[3]);
virtual void get_value_no_scale_shear(int frame, LMatrix4f &value);
virtual void get_scale(int frame, LVecBase3f &scale);
virtual void get_hpr(int frame, LVecBase3f &hpr);
virtual void get_quat(int frame, LQuaternionf &quat);
virtual void get_pos(int frame, LVecBase3f &pos);
virtual void get_shear(int frame, LVecBase3f &shear);
static INLINE bool is_valid_id(char table_id);

View File

@ -70,74 +70,181 @@ get_blend_value(const PartBundle *root) {
} else {
// A blend of two or more values.
if (root->get_blend_type() == PartBundle::BT_linear) {
// An ordinary, linear blend.
_value = 0.0f;
float net = 0.0f;
PartBundle::ChannelBlend::const_iterator cbi;
for (cbi = blend.begin(); cbi != blend.end(); ++cbi) {
AnimControl *control = (*cbi).first;
float effect = (*cbi).second;
nassertv(effect != 0.0f);
int channel_index = control->get_channel_index();
nassertv(channel_index >= 0 && channel_index < (int)_channels.size());
ChannelType *channel = DCAST(ChannelType, _channels[channel_index]);
nassertv(channel != NULL);
ValueType v;
channel->get_value(control->get_frame(), v);
_value += v * effect;
net += effect;
switch (root->get_blend_type()) {
case PartBundle::BT_single:
// This one shouldn't be possible.
nassertv(false);
case PartBundle::BT_linear:
{
// An ordinary, linear blend.
_value = 0.0f;
float net = 0.0f;
PartBundle::ChannelBlend::const_iterator cbi;
for (cbi = blend.begin(); cbi != blend.end(); ++cbi) {
AnimControl *control = (*cbi).first;
float effect = (*cbi).second;
nassertv(effect != 0.0f);
int channel_index = control->get_channel_index();
nassertv(channel_index >= 0 && channel_index < (int)_channels.size());
ChannelType *channel = DCAST(ChannelType, _channels[channel_index]);
nassertv(channel != NULL);
ValueType v;
channel->get_value(control->get_frame(), v);
_value += v * effect;
net += effect;
}
nassertv(net != 0.0f);
_value /= net;
}
break;
nassertv(net != 0.0f);
_value /= net;
} else if (root->get_blend_type() == PartBundle::BT_normalized_linear) {
// A normalized linear blend. This means we do a linear blend
// without scales, normalize the scale components of the
// resulting matrix to eliminate artificially-introduced scales,
// and then reapply the scales.
// Perhaps we should treat shear the same as a scale here?
_value = 0.0f;
LVector3f scale(0.0f, 0.0f, 0.0f);
float net = 0.0f;
PartBundle::ChannelBlend::const_iterator cbi;
for (cbi = blend.begin(); cbi != blend.end(); ++cbi) {
AnimControl *control = (*cbi).first;
float effect = (*cbi).second;
nassertv(effect != 0.0f);
int channel_index = control->get_channel_index();
nassertv(channel_index >= 0 && channel_index < (int)_channels.size());
ChannelType *channel = DCAST(ChannelType, _channels[channel_index]);
nassertv(channel != NULL);
ValueType v;
channel->get_value_no_scale(control->get_frame(), v);
LVector3f s;
channel->get_scale(control->get_frame(), &s[0]);
_value += v * effect;
scale += s * effect;
net += effect;
case PartBundle::BT_normalized_linear:
{
// A normalized linear blend. This means we do a linear blend
// without scales or shears, normalize the scale and shear
// components of the resulting matrix to eliminate
// artificially-introduced scales, and then reapply the
// scales and shears.
_value = 0.0f;
LVecBase3f scale(0.0f, 0.0f, 0.0f);
LVecBase3f shear(0.0f, 0.0f, 0.0f);
float net = 0.0f;
PartBundle::ChannelBlend::const_iterator cbi;
for (cbi = blend.begin(); cbi != blend.end(); ++cbi) {
AnimControl *control = (*cbi).first;
float effect = (*cbi).second;
nassertv(effect != 0.0f);
int channel_index = control->get_channel_index();
nassertv(channel_index >= 0 && channel_index < (int)_channels.size());
ChannelType *channel = DCAST(ChannelType, _channels[channel_index]);
nassertv(channel != NULL);
ValueType v;
channel->get_value_no_scale_shear(control->get_frame(), v);
LVecBase3f iscale, ishear;
channel->get_scale(control->get_frame(), iscale);
channel->get_shear(control->get_frame(), ishear);
_value += v * effect;
scale += iscale * effect;
shear += ishear * effect;
net += effect;
}
nassertv(net != 0.0f);
_value /= net;
scale /= net;
shear /= net;
// Now rebuild the matrix with the correct scale values.
LVector3f false_scale, false_shear, hpr, translate;
decompose_matrix(_value, false_scale, false_shear, hpr, translate);
compose_matrix(_value, scale, shear, hpr, translate);
}
break;
nassertv(net != 0.0f);
_value /= net;
scale /= net;
case PartBundle::BT_componentwise:
{
// Componentwise linear, including componentwise H, P, and R.
LVecBase3f scale(0.0f, 0.0f, 0.0f);
LVecBase3f hpr(0.0f, 0.0f, 0.0f);
LVecBase3f pos(0.0f, 0.0f, 0.0f);
LVecBase3f shear(0.0f, 0.0f, 0.0f);
float net = 0.0f;
PartBundle::ChannelBlend::const_iterator cbi;
for (cbi = blend.begin(); cbi != blend.end(); ++cbi) {
AnimControl *control = (*cbi).first;
float effect = (*cbi).second;
nassertv(effect != 0.0f);
int channel_index = control->get_channel_index();
nassertv(channel_index >= 0 && channel_index < (int)_channels.size());
ChannelType *channel = DCAST(ChannelType, _channels[channel_index]);
nassertv(channel != NULL);
LVecBase3f iscale, ihpr, ipos, ishear;
channel->get_scale(control->get_frame(), iscale);
channel->get_hpr(control->get_frame(), ihpr);
channel->get_pos(control->get_frame(), ipos);
channel->get_shear(control->get_frame(), ishear);
scale += iscale * effect;
hpr += ihpr * effect;
pos += ipos * effect;
shear += ishear * effect;
net += effect;
}
nassertv(net != 0.0f);
scale /= net;
hpr /= net;
pos /= net;
shear /= net;
compose_matrix(_value, scale, shear, hpr, pos);
}
break;
// Now rebuild the matrix with the correct scale values.
case PartBundle::BT_componentwise_quat:
{
// Componentwise linear, except for rotation, which is a
// quaternion.
LVecBase3f scale(0.0f, 0.0f, 0.0f);
LQuaternionf quat(0.0f, 0.0f, 0.0f, 0.0f);
LVecBase3f pos(0.0f, 0.0f, 0.0f);
LVecBase3f shear(0.0f, 0.0f, 0.0f);
float net = 0.0f;
PartBundle::ChannelBlend::const_iterator cbi;
for (cbi = blend.begin(); cbi != blend.end(); ++cbi) {
AnimControl *control = (*cbi).first;
float effect = (*cbi).second;
nassertv(effect != 0.0f);
int channel_index = control->get_channel_index();
nassertv(channel_index >= 0 && channel_index < (int)_channels.size());
ChannelType *channel = DCAST(ChannelType, _channels[channel_index]);
nassertv(channel != NULL);
LVecBase3f iscale, ipos, ishear;
LQuaternionf iquat;
channel->get_scale(control->get_frame(), iscale);
channel->get_quat(control->get_frame(), iquat);
channel->get_pos(control->get_frame(), ipos);
channel->get_shear(control->get_frame(), ishear);
scale += iscale * effect;
quat += iquat * effect;
pos += ipos * effect;
shear += ishear * effect;
net += effect;
}
nassertv(net != 0.0f);
scale /= net;
quat /= net;
pos /= net;
shear /= net;
LVector3f false_scale, shear, hpr, translate;
decompose_matrix(_value, false_scale, shear, hpr, translate);
compose_matrix(_value, scale, shear, hpr, translate);
// There should be no need to normalize the quaternion,
// assuming all of the input quaternions were already
// normalized.
_value = LMatrix4f::scale_shear_mat(scale, shear) * quat;
_value.set_row(3, pos);
}
break;
}
}
}

View File

@ -24,6 +24,7 @@
#include "movingPart.h"
#include "animChannel.h"
#include "animChannelFixed.h"
#include "cmath.h"
EXPORT_TEMPLATE_CLASS(EXPCL_PANDA, EXPTP_PANDA, MovingPart<ACMatrixSwitchType>);

View File

@ -82,13 +82,22 @@ PUBLISHED:
BT_linear,
// BT_normalized_linear is a compromise on BT_linear. The matrix
// is blended linearly without the scale component, and the
// blended scale component is applied separately. This keeps all
// of the character's body parts in the correct size and shape.
// However, if the hierarchy is disconnected, body parts can fly
// off. It's essential the skeleton hierarchy be completely
// connected to use this blend mode successully.
// is blended linearly without the scale and shear components, and
// the blended scale and shear components are applied separately.
// This keeps all of the character's body parts in the correct
// size and shape. However, if the hierarchy is disconnected,
// body parts can fly off. It's essential the skeleton hierarchy
// be completely connected to use this blend mode successully.
BT_normalized_linear,
// BT_componentwise linearly blends all components separately,
// including H, P, and R, and recomposes the matrix.
BT_componentwise,
// BT_componentwise_quat linearly blends all components
// separately, except for rotation which is blended as a
// quaternion.
BT_componentwise_quat,
};
void set_blend_type(BlendType bt);