Panda3D
eggRetargetAnim.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 eggRetargetAnim.cxx
10  * @author drose
11  * @date 2005-05-05
12  */
13 
14 #include "eggRetargetAnim.h"
15 
16 #include "dcast.h"
17 #include "eggJointData.h"
18 #include "eggCharacterCollection.h"
19 #include "eggCharacterData.h"
20 #include "eggCharacterDb.h"
21 #include "eggJointPointer.h"
22 #include "eggTable.h"
23 #include "compose_matrix.h"
24 
25 /**
26  *
27  */
28 EggRetargetAnim::
29 EggRetargetAnim() {
30  add_path_replace_options();
31  add_path_store_options();
32 
33  set_program_brief("remove transformations from animation data in .egg files");
34  set_program_description
35  ("egg-retarget-anim reads a character model and its associated animation "
36  "files, and removes the translations and scales from the animation "
37  "files, replacing them with the translations and scales from the "
38  "rest position of the character model.\n\n"
39 
40  "This allows an animation that was generated for a model with one "
41  "skeleton to be played successfully on a model with a different "
42  "skeleton, provided that both skeletons have the same hierarchy and "
43  "differ only in scales and/or translations of the various joints, "
44  "and that scales and translations are not part of the per-frame "
45  "animations.");
46 
47  add_option
48  ("r", "file.egg", 0,
49  "Read the reference model from the indicated egg file. All of the "
50  "animations will be retargeted to match the indicated file.",
51  &EggRetargetAnim::dispatch_filename, nullptr, &_reference_filename);
52 
53  add_option
54  ("keep", "joint[,joint...]", 0,
55  "Preserve the full animation on the named joint(s). This is especially "
56  "appropriate for the root joint.",
57  &EggRetargetAnim::dispatch_vector_string_comma, nullptr, &_keep_joints);
58 }
59 
60 /**
61  *
62  */
63 void EggRetargetAnim::
64 run() {
65  nassertv(_collection != nullptr);
66  nassertv(_collection->get_num_eggs() > 0);
67 
68  if (_reference_filename.empty()) {
69  nout << "No reference filename specified.\n";
70  exit(1);
71  }
72 
73  int num_characters = _collection->get_num_characters();
74  if (num_characters != 1) {
75  nout << "All animations must have the same character name.\n";
76  exit(1);
77  }
78 
79  // Read in the extra egg file that we use for extracting the references out.
80  PT(EggData) reference_egg = read_egg(_reference_filename);
81  if (reference_egg == nullptr) {
82  nout << "Cannot read " << _reference_filename << "\n";
83  exit(1);
84  }
85 
86  // First, we add it to a separate EggCharacterCollection, so we can figure
87  // out its name.
89  if (col.add_egg(reference_egg) < 0) {
90  nout << _reference_filename
91  << " does not contain a character model or animation reference.\n";
92  exit(1);
93  }
94 
95  if (col.get_num_characters() != 1) {
96  nout << "Reference model must contain only one character.\n";
97  exit(1);
98  }
99 
100  std::string ref_name = col.get_character(0)->get_name();
101 
102  // Now rename all of the animations to the same name as the reference model,
103  // and add the reference animation in to the same collection to match it up
104  // joint-for-joint.
105  _collection->rename_char(0, ref_name);
106  int reference_egg_index = _collection->add_egg(reference_egg);
107  nassertv(reference_egg_index > 0);
108  nassertv(_collection->get_num_characters() == 1);
109 
110  int reference_model = _collection->get_first_model_index(reference_egg_index);
111  EggCharacterData *char_data = _collection->get_character(0);
112  nout << "Processing " << char_data->get_name() << "\n";
113 
114  typedef pset<std::string> Names;
115  Names keep_names;
116 
117  vector_string::const_iterator si;
118  for (si = _keep_joints.begin(); si != _keep_joints.end(); ++si) {
119  keep_names.insert(*si);
120  }
121 
122  EggCharacterDb db;
123  EggJointData *root_joint = char_data->get_root_joint();
124  retarget_anim(char_data, root_joint, reference_model, keep_names, db);
125  root_joint->do_rebuild_all(db);
126 
127  write_eggs();
128 }
129 
130 /**
131  * Recursively replaces the scale and translate information on all of the
132  * joints in the char_data hierarchy wiht this from reference_char.
133  */
136  int reference_model, const pset<std::string> &keep_names,
137  EggCharacterDb &db) {
138  if (keep_names.find(joint_data->get_name()) != keep_names.end()) {
139  // Don't retarget this joint; keep the translation and scale and whatever.
140 
141  } else {
142  // Retarget this joint.
143  int num_models = joint_data->get_num_models();
144  for (int i = 0; i < num_models; i++) {
145  if (joint_data->has_model(i)) {
146  int num_frames = char_data->get_num_frames(i);
147 
148  EggBackPointer *back = joint_data->get_model(i);
149  nassertv(back != nullptr);
150  EggJointPointer *joint;
151  DCAST_INTO_V(joint, back);
152 
153  LMatrix4d ref = joint_data->get_frame(reference_model, 0);
154  LVecBase3d ref_scale, ref_shear, ref_hpr, ref_translate;
155  if (!decompose_matrix(ref, ref_scale, ref_shear, ref_hpr, ref_translate)) {
156  nout << "Could not decompose rest frame for "
157  << joint_data->get_name() << "\n";
158  } else {
159  int f;
160  for (f = 0; f < num_frames; f++) {
161  LMatrix4d mat = joint_data->get_frame(i, f);
162 
163  LVecBase3d scale, shear, hpr, translate;
164  if (decompose_matrix(mat, scale, shear, hpr, translate)) {
165  compose_matrix(mat, ref_scale, ref_shear, hpr, ref_translate);
166  } else {
167  nout << "Could not decompose matrix for " << joint_data->get_name()
168  << "\n";
169  }
170 
171  db.set_matrix(joint, EggCharacterDb::TT_rebuild_frame,
172  f, mat);
173  }
174  }
175  }
176  }
177  }
178 
179  int num_children = joint_data->get_num_children();
180  for (int i = 0; i < num_children; i++) {
181  EggJointData *next_joint_data = joint_data->get_child(i);
182  retarget_anim(char_data, next_joint_data, reference_model, keep_names, db);
183  }
184 }
185 
186 
187 int main(int argc, char *argv[]) {
188  EggRetargetAnim prog;
189  prog.parse_command_line(argc, argv);
190  prog.run();
191  return 0;
192 }
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
EggJointData * get_root_joint() const
Returns the root joint of the character hierarchy.
int get_num_frames(int model_index) const
Returns the number of frames of animation of the indicated model.
virtual void parse_command_line(int argc, char **argv)
Dispatches on each of the options on the command line, and passes the remaining parameters to handle_...
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
int get_num_models() const
Returns the maximum number of back pointers this component may have.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
int add_egg(EggData *egg)
Adds a new egg file to the list of models and animation files for this particular character.
EggBackPointer * get_model(int model_index) const
Returns the back pointer to an egg file for the indicated model if it exists, or NULL if it does not.
This is the primary interface into all the egg data, and the root of the egg file structure.
Definition: eggData.h:37
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
int get_num_characters() const
Returns the number of separate Characters that have been discovered in the various egg files added to...
This class is used during joint optimization or restructuring to store the table of interim joint com...
Retargets one or more animation files from one particular skeleton to a similar, but differently scal...
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
void set_matrix(const EggJointPointer *joint, TableType type, int frame, const LMatrix4d &mat)
Stores the matrix for the indicated joint, type, and frame in the database.
This is a base class for EggJointNodePointer and EggMatrixTablePointer.
EggCharacterData * get_character(int i) const
Returns the ith character in the collection.
Represents a set of characters, as read and collected from possibly several model and/or animation eg...
bool has_model(int model_index) const
Returns true if the component has a back pointer to an egg file somewhere for the indicated model,...
void retarget_anim(EggCharacterData *char_data, EggJointData *joint_data, int reference_model, const pset< std::string > &keep_names, EggCharacterDb &db)
Recursively replaces the scale and translate information on all of the joints in the char_data hierar...
Represents a single character, as read and collected from several models and animation files.
This is one node of a hierarchy of EggJointData nodes, each of which represents a single joint of the...
Definition: eggJointData.h:31
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
LMatrix4d get_frame(int model_index, int n) const
Returns the local transform matrix corresponding to this joint position in the nth frame in the indic...
bool do_rebuild_all(EggCharacterDb &db)
Calls do_rebuild() on all models, and recursively on all joints at this node and below.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
This stores a pointer from an EggJointData or EggSliderData object back to the referencing data in an...