Panda3D
Loading...
Searching...
No Matches
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"
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 */
28EggRetargetAnim::
29EggRetargetAnim() {
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 */
63void EggRetargetAnim::
64run() {
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
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 */
135retarget_anim(EggCharacterData *char_data, EggJointData *joint_data,
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
187int main(int argc, char *argv[]) {
188 EggRetargetAnim prog;
189 prog.parse_command_line(argc, argv);
190 prog.run();
191 return 0;
192}
This stores a pointer from an EggJointData or EggSliderData object back to the referencing data in an...
Represents a set of characters, as read and collected from possibly several model and/or animation eg...
int get_num_characters() const
Returns the number of separate Characters that have been discovered in the various egg files added to...
int add_egg(EggData *egg)
Adds a new egg file to the list of models and animation files for this particular character.
EggCharacterData * get_character(int i) const
Returns the ith character in the collection.
Represents a single character, as read and collected from several models and animation files.
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.
This class is used during joint optimization or restructuring to store the table of interim joint com...
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.
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.
int get_num_models() const
Returns the maximum number of back pointers this component may have.
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,...
This is the primary interface into all the egg data, and the root of the egg file structure.
Definition eggData.h:37
This is one node of a hierarchy of EggJointData nodes, each of which represents a single joint of the...
bool do_rebuild_all(EggCharacterDb &db)
Calls do_rebuild() on all models, and recursively on all joints at this node and below.
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...
This is a base class for EggJointNodePointer and EggMatrixTablePointer.
Retargets one or more animation files from one particular skeleton to a similar, but differently scal...
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...
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_...
This is our own Panda specialization on the default STL set.
Definition pset.h:49
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.