don't recompute character vertices if animation is unchanged

This commit is contained in:
David Rose 2002-02-19 18:50:32 +00:00
parent 54c440e9e1
commit 2fc11e2a9f
12 changed files with 151 additions and 52 deletions

View File

@ -87,11 +87,19 @@ write_with_value(ostream &out, int indent_level) const {
////////////////////////////////////////////////////////////////////
// Function: MovingPartBase::do_update
// Access: Public, Virtual
// Description:
// Description: Recursively update this particular part and all of
// its descendents for the current frame. This is not
// really public and is not intended to be called
// directly; it is called from the top of the tree by
// PartBundle::update().
//
// The return value is true if any part has changed,
// false otherwise.
////////////////////////////////////////////////////////////////////
void MovingPartBase::
bool MovingPartBase::
do_update(PartBundle *root, PartGroup *parent,
bool parent_changed, bool anim_changed) {
bool any_changed = false;
bool needs_update = anim_changed;
// See if any of the channel values have changed since last time.
@ -102,9 +110,9 @@ do_update(PartBundle *root, PartGroup *parent,
++bci) {
AnimControl *control = (*bci);
int channel_index = control->get_channel_index();
nassertv(channel_index >= 0 && channel_index < (int)_channels.size());
nassertr(channel_index >= 0 && channel_index < (int)_channels.size(), false);
AnimChannelBase *channel = _channels[channel_index];
nassertv(channel != (AnimChannelBase*)0L);
nassertr(channel != (AnimChannelBase*)0L, false);
needs_update = control->channel_has_changed(channel);
}
@ -115,15 +123,19 @@ do_update(PartBundle *root, PartGroup *parent,
}
if (parent_changed || needs_update) {
update_internals(parent, needs_update, parent_changed);
any_changed = update_internals(parent, needs_update, parent_changed);
}
// Now recurse.
Children::iterator ci;
for (ci = _children.begin(); ci != _children.end(); ++ci) {
(*ci)->do_update(root, this, parent_changed || needs_update,
anim_changed);
if ((*ci)->do_update(root, this, parent_changed || needs_update,
anim_changed)) {
any_changed = true;
}
}
return any_changed;
}
@ -134,9 +146,13 @@ do_update(PartBundle *root, PartGroup *parent,
// some ancestor has changed values. It is a hook for
// derived classes to update whatever cache they may
// have that depends on these.
//
// The return value is true if the part has changed as a
// result of the update, or false otherwise.
////////////////////////////////////////////////////////////////////
void MovingPartBase::
bool MovingPartBase::
update_internals(PartGroup *, bool, bool) {
return false;
}
////////////////////////////////////////////////////////////////////

View File

@ -48,11 +48,11 @@ public:
virtual void write_with_value(ostream &out, int indent_level) const;
virtual void output_value(ostream &out) const=0;
virtual void do_update(PartBundle *root, PartGroup *parent,
virtual bool do_update(PartBundle *root, PartGroup *parent,
bool parent_changed, bool anim_changed);
virtual void get_blend_value(const PartBundle *root)=0;
virtual void update_internals(PartGroup *parent, bool self_changed,
virtual bool update_internals(PartGroup *parent, bool self_changed,
bool parent_changed);
protected:

View File

@ -344,11 +344,16 @@ advance_time(double time) {
////////////////////////////////////////////////////////////////////
// Function: PartBundle::update
// Access: Public
// Description:
// Description: Updates all the parts in the bundle to reflect the
// data for the current frame (as set in each of the
// AnimControls).
//
// Returns true if any part has changed as a result of
// this, or false otherwise.
////////////////////////////////////////////////////////////////////
void PartBundle::
bool PartBundle::
update() {
do_update(this, NULL, false, _anim_changed);
bool any_changed = do_update(this, NULL, false, _anim_changed);
// Now update all the controls for next time.
ChannelBlend::const_iterator cbi;
@ -357,6 +362,8 @@ update() {
control->mark_channels();
}
_anim_changed = false;
return any_changed;
}

View File

@ -122,7 +122,7 @@ public:
// bunch of friends.
void advance_time(double time);
void update();
bool update();
virtual void control_activated(AnimControl *control);
protected:

View File

@ -350,15 +350,28 @@ write_with_value(ostream &out, int indent_level) const {
////////////////////////////////////////////////////////////////////
// Function: PartGroup::do_update
// Access: Public, Virtual
// Description:
// Description: Recursively update this particular part and all of
// its descendents for the current frame. This is not
// really public and is not intended to be called
// directly; it is called from the top of the tree by
// PartBundle::update().
//
// The return value is true if any part has changed,
// false otherwise.
////////////////////////////////////////////////////////////////////
void PartGroup::
bool PartGroup::
do_update(PartBundle *root, PartGroup *,
bool parent_changed, bool anim_changed) {
bool any_changed = false;
Children::iterator ci;
for (ci = _children.begin(); ci != _children.end(); ++ci) {
(*ci)->do_update(root, this, parent_changed, anim_changed);
if ((*ci)->do_update(root, this, parent_changed, anim_changed)) {
any_changed = true;
}
}
return any_changed;
}

View File

@ -82,7 +82,7 @@ public:
const PartGroup *parent,
int hierarchy_match_flags = 0) const;
virtual void do_update(PartBundle *root, PartGroup *parent,
virtual bool do_update(PartBundle *root, PartGroup *parent,
bool parent_changed, bool anim_changed);
protected:

View File

@ -21,16 +21,16 @@
#include "computedVertices.h"
#include "config_char.h"
#include <geomNode.h>
#include <datagram.h>
#include <datagramIterator.h>
#include <bamReader.h>
#include <bamWriter.h>
#include <pStatTimer.h>
#include <geomNode.h>
#include <animControl.h>
#include <clockObject.h>
#include <pStatTimer.h>
#include "geomNode.h"
#include "datagram.h"
#include "datagramIterator.h"
#include "bamReader.h"
#include "bamWriter.h"
#include "pStatTimer.h"
#include "geomNode.h"
#include "animControl.h"
#include "clockObject.h"
#include "pStatTimer.h"
TypeHandle Character::_type_handle;
@ -140,11 +140,14 @@ update() {
PStatTimer timer(_char_pcollector);
// First, update all the joints and sliders.
get_bundle()->update();
bool any_changed = get_bundle()->update();
// Now update the vertices.
if (_computed_vertices != (ComputedVertices *)NULL) {
_computed_vertices->update(this);
// Now update the vertices, if we need to. This is likely to be a
// slow operation.
if (any_changed || even_animation) {
if (_computed_vertices != (ComputedVertices *)NULL) {
_computed_vertices->update(this);
}
}
}
@ -299,7 +302,7 @@ copy_geom(Geom *source, const Character *from) {
PT(Geom) dest = source;
source->get_coords(coords, index);
if ((coords != NULL) && (coords == (from->_cv._coords))) {
if ((coords != (void *)NULL) && (coords == (from->_cv._coords))) {
if (dest == source) {
dest = source->make_copy();
}

View File

@ -19,16 +19,16 @@
#ifndef CHARACTER_H
#define CHARACTER_H
#include <pandabase.h>
#include "pandabase.h"
#include "computedVertices.h"
#include <partBundleNode.h>
#include <namedNode.h>
#include <vector_PartGroupStar.h>
#include <pointerTo.h>
#include <geom.h>
#include <pStatCollector.h>
#include "partBundleNode.h"
#include "namedNode.h"
#include "vector_PartGroupStar.h"
#include "pointerTo.h"
#include "geom.h"
#include "pStatCollector.h"
class CharacterJointBundle;
class ComputedVertices;

View File

@ -84,22 +84,40 @@ make_copy() const {
////////////////////////////////////////////////////////////////////
// Function: CharacterJoint::update_internals
// Access: Public, Virtual
// Description:
// Description: This is called by do_update() whenever the part or
// some ancestor has changed values. It is a hook for
// derived classes to update whatever cache they may
// have that depends on these.
//
// The return value is true if the part has changed as a
// result of the update, or false otherwise.
//
// In the case of a CharacterJoint, of course, it means
// to recompute the joint angles and associated
// transforms for this particular joint.
////////////////////////////////////////////////////////////////////
void CharacterJoint::
update_internals(PartGroup *parent, bool self_changed, bool) {
nassertv(parent != NULL);
bool CharacterJoint::
update_internals(PartGroup *parent, bool self_changed, bool parent_changed) {
nassertr(parent != (PartGroup *)NULL, false);
bool net_changed = false;
if (parent->is_of_type(CharacterJoint::get_class_type())) {
CharacterJoint *parent_joint = DCAST(CharacterJoint, parent);
// The joint is not a toplevel joint; its parent therefore affects
// its net transform.
if (parent_changed || self_changed) {
CharacterJoint *parent_joint = DCAST(CharacterJoint, parent);
_net_transform = _value * parent_joint->_net_transform;
net_changed = true;
}
_net_transform = _value * parent_joint->_net_transform;
net_changed = true;
} else if (self_changed) {
_net_transform = _value;
net_changed = true;
} else {
// The joint *is* a toplevel joint, and the only thing that
// affects its net transform is the joint itself.
if (self_changed) {
_net_transform = _value;
net_changed = true;
}
}
if (net_changed && !_net_transform_arcs.empty()) {
@ -141,6 +159,8 @@ update_internals(PartGroup *parent, bool self_changed, bool) {
}
}
}
return self_changed || net_changed;
}
////////////////////////////////////////////////////////////////////

View File

@ -43,7 +43,7 @@ public:
virtual PartGroup *make_copy() const;
virtual void update_internals(PartGroup *parent, bool self_changed,
virtual bool update_internals(PartGroup *parent, bool self_changed,
bool parent_changed);
PUBLISHED:

View File

@ -31,6 +31,41 @@ Configure(config_char);
NotifyCategoryDef(char, "");
ConfigureFn(config_char) {
init_libchar();
}
// The animation system, by default, only recomputes the characters'
// vertices on frames for which there is some change in the animation
// cycle. Since this doesn't happen every frame, and since the
// recomputing of vertices can take significant time, this might
// result in irregular patterns of slow frames and fast frames,
// resulting in an unsteady frame rate. Sometimes it is preferable to
// achieve a more even frame rate, even if the average frame rate is
// slower overall.
// Set even-animation to true to achieve this. When this is true,
// characters' vertices will be recomputed every frame, whether they
// need it or not. This will tend to balance out the frame rate so
// that it is more uniformly slow.
const bool even_animation = config_char.GetBool("even-animation", false);
////////////////////////////////////////////////////////////////////
// Function: init_libchar
// Description: Initializes the library. This must be called at
// least once before any of the functions or classes in
// this library can be used. Normally it will be
// called by the static initializers and need not be
// called explicitly, but special cases exist.
////////////////////////////////////////////////////////////////////
void
init_libchar() {
static bool initialized = false;
if (initialized) {
return;
}
initialized = true;
Character::init_type();
CharacterJoint::init_type();
CharacterJointBundle::init_type();

View File

@ -27,4 +27,9 @@
NotifyCategoryDecl(char, EXPCL_PANDA, EXPTP_PANDA);
#endif
// Configure variables for char package.
extern const bool EXPCL_PANDA even_animation;
extern EXPCL_PANDA void init_libchar();
#endif