From 53eb3936617aa2701342cf5b1c535eb36fe4fb0b Mon Sep 17 00:00:00 2001 From: David Rose Date: Sat, 7 May 2005 00:10:20 +0000 Subject: [PATCH] egg-retarget-anim --- .../eggcharbase/eggCharacterCollection.cxx | 18 ++ .../src/eggcharbase/eggCharacterCollection.h | 2 + .../src/eggcharbase/eggCharacterData.cxx | 20 ++ pandatool/src/eggcharbase/eggCharacterData.h | 2 + pandatool/src/eggprogs/Sources.pp | 9 + pandatool/src/eggprogs/eggRetargetAnim.cxx | 184 ++++++++++++++++++ pandatool/src/eggprogs/eggRetargetAnim.h | 52 +++++ 7 files changed, 287 insertions(+) create mode 100644 pandatool/src/eggprogs/eggRetargetAnim.cxx create mode 100644 pandatool/src/eggprogs/eggRetargetAnim.h diff --git a/pandatool/src/eggcharbase/eggCharacterCollection.cxx b/pandatool/src/eggcharbase/eggCharacterCollection.cxx index 2bbe9f4418..9cd4c15788 100644 --- a/pandatool/src/eggcharbase/eggCharacterCollection.cxx +++ b/pandatool/src/eggcharbase/eggCharacterCollection.cxx @@ -666,6 +666,24 @@ found_egg_match(EggCharacterData *char_data, EggJointData *joint_data, } } +//////////////////////////////////////////////////////////////////// +// Function: EggCharacterCollection::rename_char +// Access: Public +// Description: Renames the ith character to the indicated name. +// This name must not already be used by another +// character in the collection. +//////////////////////////////////////////////////////////////////// +void EggCharacterCollection:: +rename_char(int i, const string &name) { + nassertv(i >= 0 && i < (int)_characters.size()); + + EggCharacterData *char_data = _characters[i]; + if (char_data->get_name() != name) { + nassertv(get_character_by_name(name) == (EggCharacterData *)NULL); + char_data->rename_char(name); + } +} + //////////////////////////////////////////////////////////////////// // Function: EggCharacterCollection::write // Access: Public, Virtual diff --git a/pandatool/src/eggcharbase/eggCharacterCollection.h b/pandatool/src/eggcharbase/eggCharacterCollection.h index 7b8357215e..7e9f4f8d74 100644 --- a/pandatool/src/eggcharbase/eggCharacterCollection.h +++ b/pandatool/src/eggcharbase/eggCharacterCollection.h @@ -54,6 +54,8 @@ public: INLINE EggCharacterData *get_character_by_model_index(int model_index) const; + void rename_char(int i, const string &name); + virtual void write(ostream &out, int indent_level = 0) const; void check_errors(ostream &out, bool force_initial_rest_frame); diff --git a/pandatool/src/eggcharbase/eggCharacterData.cxx b/pandatool/src/eggcharbase/eggCharacterData.cxx index aebd82f1d3..c4ad6599ad 100644 --- a/pandatool/src/eggcharbase/eggCharacterData.cxx +++ b/pandatool/src/eggcharbase/eggCharacterData.cxx @@ -64,6 +64,26 @@ EggCharacterData:: } } +//////////////////////////////////////////////////////////////////// +// Function: EggCharacterData::rename_char +// Access: Public +// Description: Renames all of the models in the character data to +// the indicated name. This is the name that is used to +// identify unique skeleton hierarchies; if you set two +// different models to the same name, they will be +// loaded together as if they are expected to have the +// same skeleton hierarchy. +//////////////////////////////////////////////////////////////////// +void EggCharacterData:: +rename_char(const string &name) { + Models::iterator mi; + for (mi = _models.begin(); mi != _models.end(); ++mi) { + (*mi)._model_root->set_name(name); + } + + set_name(name); +} + //////////////////////////////////////////////////////////////////// // Function: EggCharacterData::add_model // Access: Public diff --git a/pandatool/src/eggcharbase/eggCharacterData.h b/pandatool/src/eggcharbase/eggCharacterData.h index c38ff3df80..f3f89d9cac 100644 --- a/pandatool/src/eggcharbase/eggCharacterData.h +++ b/pandatool/src/eggcharbase/eggCharacterData.h @@ -66,6 +66,8 @@ public: EggCharacterData(EggCharacterCollection *collection); virtual ~EggCharacterData(); + void rename_char(const string &name); + void add_model(int model_index, EggNode *model_root, EggData *egg_data); INLINE int get_num_models() const; INLINE int get_model_index(int n) const; diff --git a/pandatool/src/eggprogs/Sources.pp b/pandatool/src/eggprogs/Sources.pp index 7c24e4b36d..e2192794f3 100644 --- a/pandatool/src/eggprogs/Sources.pp +++ b/pandatool/src/eggprogs/Sources.pp @@ -56,6 +56,15 @@ #end bin_target +#begin bin_target + #define LOCAL_LIBS eggcharbase $[LOCAL_LIBS] + #define TARGET egg-retarget-anim + + #define SOURCES \ + eggRetargetAnim.cxx eggRetargetAnim.h + +#end bin_target + #begin bin_target #define TARGET egg2c diff --git a/pandatool/src/eggprogs/eggRetargetAnim.cxx b/pandatool/src/eggprogs/eggRetargetAnim.cxx new file mode 100644 index 0000000000..99c207f819 --- /dev/null +++ b/pandatool/src/eggprogs/eggRetargetAnim.cxx @@ -0,0 +1,184 @@ +// Filename: eggRetargetAnim.cxx +// Created by: drose (05May05) +// +//////////////////////////////////////////////////////////////////// +// +// PANDA 3D SOFTWARE +// Copyright (c) 2001 - 2004, Disney Enterprises, Inc. All rights reserved +// +// All use of this software is subject to the terms of the Panda 3d +// Software license. You should have received a copy of this license +// along with this source code; you will also find a current copy of +// the license at http://etc.cmu.edu/panda3d/docs/license/ . +// +// To contact the maintainers of this program write to +// panda3d-general@lists.sourceforge.net . +// +//////////////////////////////////////////////////////////////////// + +#include "eggRetargetAnim.h" + +#include "dcast.h" +#include "eggJointData.h" +#include "eggCharacterCollection.h" +#include "eggCharacterData.h" +#include "eggJointPointer.h" +#include "eggTable.h" +#include "compose_matrix.h" + +//////////////////////////////////////////////////////////////////// +// Function: EggRetargetAnim::Constructor +// Access: Public +// Description: +//////////////////////////////////////////////////////////////////// +EggRetargetAnim:: +EggRetargetAnim() { + add_path_replace_options(); + add_path_store_options(); + + set_program_description + ("egg-retarget-anim reads a character model and its associated animation " + "files, and removes the translations and scales from the animation " + "files, replacing them with the translations and scales from the " + "rest position of the character model.\n\n" + + "This allows an animation that was generated for a model with one " + "skeleton to be played successfully on a model with a different " + "skeleton, provided that both skeletons have the same hierarchy and " + "differ only in scales and/or translations of the various joints, " + "and that scales and translations are not part of the per-frame " + "animations."); + + add_option + ("r", "file.egg", 0, + "Read the reference model from the indicated egg file. All of the " + "animations will be retargeted to match the indicated file.", + &EggRetargetAnim::dispatch_filename, NULL, &_reference_filename); +} + +//////////////////////////////////////////////////////////////////// +// Function: EggRetargetAnim::run +// Access: Public +// Description: +//////////////////////////////////////////////////////////////////// +void EggRetargetAnim:: +run() { + nassertv(_collection != (EggCharacterCollection *)NULL); + nassertv(_collection->get_num_eggs() > 0); + + if (_reference_filename.empty()) { + nout << "No reference filename specified.\n"; + exit(1); + } + + int num_characters = _collection->get_num_characters(); + if (num_characters != 1) { + nout << "All animations must have the same character name.\n"; + exit(1); + } + + // Read in the extra egg file that we use for extracting the + // references out. + PT(EggData) reference_egg = read_egg(_reference_filename); + if (reference_egg == (EggData *)NULL) { + nout << "Cannot read " << _reference_filename << "\n"; + exit(1); + } + + // First, we add it to a separate EggCharacterCollection, so we can + // figure out its name. + EggCharacterCollection col; + if (col.add_egg(reference_egg) < 0) { + nout << _reference_filename + << " does not contain a character model or animation reference.\n"; + exit(1); + } + + if (col.get_num_characters() != 1) { + nout << "Reference model must contain only one character.\n"; + exit(1); + } + + string ref_name = col.get_character(0)->get_name(); + + // Now rename all of the animations to the same name as the + // reference model, and add the reference animation in to the same + // collection to match it up joint-for-joint. + _collection->rename_char(0, ref_name); + int reference_egg_index = _collection->add_egg(reference_egg); + nassertv(reference_egg_index > 0); + nassertv(_collection->get_num_characters() == 1); + + int reference_model = _collection->get_first_model_index(reference_egg_index); + EggCharacterData *char_data = _collection->get_character(0); + nout << "Processing " << char_data->get_name() << "\n"; + + EggJointData *root_joint = char_data->get_root_joint(); + retarget_anim(char_data, root_joint, reference_model); + root_joint->do_rebuild(); + + write_eggs(); +} + +//////////////////////////////////////////////////////////////////// +// Function: EggRetargetAnim::retarget_anim +// Access: Public +// Description: Recursively replaces the scale and translate +// information on all of the joints in the char_data +// hierarchy wiht this from reference_char. +//////////////////////////////////////////////////////////////////// +void EggRetargetAnim:: +retarget_anim(EggCharacterData *char_data, EggJointData *joint_data, + int reference_model) { + int num_models = joint_data->get_num_models(); + for (int i = 0; i < num_models; i++) { + if (joint_data->has_model(i)) { + int num_frames = char_data->get_num_frames(i); + + EggBackPointer *back = joint_data->get_model(i); + nassertv(back != (EggBackPointer *)NULL); + EggJointPointer *joint; + DCAST_INTO_V(joint, back); + + LMatrix4d ref = joint_data->get_frame(reference_model, 0); + LVecBase3d ref_scale, ref_shear, ref_hpr, ref_translate; + if (!decompose_matrix(ref, ref_scale, ref_shear, ref_hpr, ref_translate)) { + nout << "Could not decompose rest frame for " + << joint_data->get_name() << "\n"; + } else { + int f; + for (f = 0; f < num_frames; f++) { + LMatrix4d mat = joint_data->get_frame(i, f); + + LVecBase3d scale, shear, hpr, translate; + if (decompose_matrix(mat, scale, shear, hpr, translate)) { + compose_matrix(mat, ref_scale, ref_shear, hpr, ref_translate); + } else { + nout << "Could not decompose matrix for " << joint_data->get_name() + << "\n"; + } + + if (!joint->add_rebuild_frame(mat)) { + nout << "Unable to combine animations.\n"; + exit(1); + } + } + } + } + } + + + int num_children = joint_data->get_num_children(); + for (int i = 0; i < num_children; i++) { + EggJointData *next_joint_data = joint_data->get_child(i); + retarget_anim(char_data, next_joint_data, reference_model); + } +} + + +int main(int argc, char *argv[]) { + EggRetargetAnim prog; + prog.parse_command_line(argc, argv); + prog.run(); + return 0; +} diff --git a/pandatool/src/eggprogs/eggRetargetAnim.h b/pandatool/src/eggprogs/eggRetargetAnim.h new file mode 100644 index 0000000000..d91242307b --- /dev/null +++ b/pandatool/src/eggprogs/eggRetargetAnim.h @@ -0,0 +1,52 @@ +// Filename: eggRetargetAnim.h +// Created by: drose (05May05) +// +//////////////////////////////////////////////////////////////////// +// +// PANDA 3D SOFTWARE +// Copyright (c) 2001 - 2004, Disney Enterprises, Inc. All rights reserved +// +// All use of this software is subject to the terms of the Panda 3d +// Software license. You should have received a copy of this license +// along with this source code; you will also find a current copy of +// the license at http://etc.cmu.edu/panda3d/docs/license/ . +// +// To contact the maintainers of this program write to +// panda3d-general@lists.sourceforge.net . +// +//////////////////////////////////////////////////////////////////// + +#ifndef EGGRETARGETANIM_H +#define EGGRETARGETANIM_H + +#include "pandatoolbase.h" + +#include "eggCharacterFilter.h" +#include "luse.h" + +#include "pvector.h" + +class EggCharacterData; +class EggJointData; + +//////////////////////////////////////////////////////////////////// +// Class : EggRetargetAnim +// Description : Retargets one or more animation files from one +// particular skeleton to a similar, but differently +// scaled skeleton by preserving the rotation +// information but discarding translation and/or scale. +//////////////////////////////////////////////////////////////////// +class EggRetargetAnim : public EggCharacterFilter { +public: + EggRetargetAnim(); + + void run(); + + void retarget_anim(EggCharacterData *char_data, EggJointData *joint_data, + int reference_model); + + Filename _reference_filename; +}; + +#endif +