mirror of
https://github.com/panda3d/panda3d.git
synced 2025-10-02 18:03:56 -04:00
don't recompute character vertices if animation is unchanged
This commit is contained in:
parent
54c440e9e1
commit
2fc11e2a9f
@ -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;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
|
@ -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:
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
||||
|
@ -122,7 +122,7 @@ public:
|
||||
// bunch of friends.
|
||||
|
||||
void advance_time(double time);
|
||||
void update();
|
||||
bool update();
|
||||
virtual void control_activated(AnimControl *control);
|
||||
|
||||
protected:
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
||||
|
@ -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:
|
||||
|
@ -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();
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
|
@ -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:
|
||||
|
@ -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();
|
||||
|
@ -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
|
||||
|
Loading…
x
Reference in New Issue
Block a user