eggRetargetAnim.cxx 6.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192
  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. #include "eggRetargetAnim.h"
  14. #include "dcast.h"
  15. #include "eggJointData.h"
  16. #include "eggCharacterCollection.h"
  17. #include "eggCharacterData.h"
  18. #include "eggCharacterDb.h"
  19. #include "eggJointPointer.h"
  20. #include "eggTable.h"
  21. #include "compose_matrix.h"
  22. /**
  23. *
  24. */
  25. EggRetargetAnim::
  26. EggRetargetAnim() {
  27. add_path_replace_options();
  28. add_path_store_options();
  29. set_program_brief("remove transformations from animation data in .egg files");
  30. set_program_description
  31. ("egg-retarget-anim reads a character model and its associated animation "
  32. "files, and removes the translations and scales from the animation "
  33. "files, replacing them with the translations and scales from the "
  34. "rest position of the character model.\n\n"
  35. "This allows an animation that was generated for a model with one "
  36. "skeleton to be played successfully on a model with a different "
  37. "skeleton, provided that both skeletons have the same hierarchy and "
  38. "differ only in scales and/or translations of the various joints, "
  39. "and that scales and translations are not part of the per-frame "
  40. "animations.");
  41. add_option
  42. ("r", "file.egg", 0,
  43. "Read the reference model from the indicated egg file. All of the "
  44. "animations will be retargeted to match the indicated file.",
  45. &EggRetargetAnim::dispatch_filename, nullptr, &_reference_filename);
  46. add_option
  47. ("keep", "joint[,joint...]", 0,
  48. "Preserve the full animation on the named joint(s). This is especially "
  49. "appropriate for the root joint.",
  50. &EggRetargetAnim::dispatch_vector_string_comma, nullptr, &_keep_joints);
  51. }
  52. /**
  53. *
  54. */
  55. void EggRetargetAnim::
  56. run() {
  57. nassertv(_collection != nullptr);
  58. nassertv(_collection->get_num_eggs() > 0);
  59. if (_reference_filename.empty()) {
  60. nout << "No reference filename specified.\n";
  61. exit(1);
  62. }
  63. int num_characters = _collection->get_num_characters();
  64. if (num_characters != 1) {
  65. nout << "All animations must have the same character name.\n";
  66. exit(1);
  67. }
  68. // Read in the extra egg file that we use for extracting the references out.
  69. PT(EggData) reference_egg = read_egg(_reference_filename);
  70. if (reference_egg == nullptr) {
  71. nout << "Cannot read " << _reference_filename << "\n";
  72. exit(1);
  73. }
  74. // First, we add it to a separate EggCharacterCollection, so we can figure
  75. // out its name.
  76. EggCharacterCollection col;
  77. if (col.add_egg(reference_egg) < 0) {
  78. nout << _reference_filename
  79. << " does not contain a character model or animation reference.\n";
  80. exit(1);
  81. }
  82. if (col.get_num_characters() != 1) {
  83. nout << "Reference model must contain only one character.\n";
  84. exit(1);
  85. }
  86. std::string ref_name = col.get_character(0)->get_name();
  87. // Now rename all of the animations to the same name as the reference model,
  88. // and add the reference animation in to the same collection to match it up
  89. // joint-for-joint.
  90. _collection->rename_char(0, ref_name);
  91. int reference_egg_index = _collection->add_egg(reference_egg);
  92. nassertv(reference_egg_index > 0);
  93. nassertv(_collection->get_num_characters() == 1);
  94. int reference_model = _collection->get_first_model_index(reference_egg_index);
  95. EggCharacterData *char_data = _collection->get_character(0);
  96. nout << "Processing " << char_data->get_name() << "\n";
  97. typedef pset<std::string> Names;
  98. Names keep_names;
  99. vector_string::const_iterator si;
  100. for (si = _keep_joints.begin(); si != _keep_joints.end(); ++si) {
  101. keep_names.insert(*si);
  102. }
  103. EggCharacterDb db;
  104. EggJointData *root_joint = char_data->get_root_joint();
  105. retarget_anim(char_data, root_joint, reference_model, keep_names, db);
  106. root_joint->do_rebuild_all(db);
  107. write_eggs();
  108. }
  109. /**
  110. * Recursively replaces the scale and translate information on all of the
  111. * joints in the char_data hierarchy wiht this from reference_char.
  112. */
  113. void EggRetargetAnim::
  114. retarget_anim(EggCharacterData *char_data, EggJointData *joint_data,
  115. int reference_model, const pset<std::string> &keep_names,
  116. EggCharacterDb &db) {
  117. if (keep_names.find(joint_data->get_name()) != keep_names.end()) {
  118. // Don't retarget this joint; keep the translation and scale and whatever.
  119. } else {
  120. // Retarget this joint.
  121. int num_models = joint_data->get_num_models();
  122. for (int i = 0; i < num_models; i++) {
  123. if (joint_data->has_model(i)) {
  124. int num_frames = char_data->get_num_frames(i);
  125. EggBackPointer *back = joint_data->get_model(i);
  126. nassertv(back != nullptr);
  127. EggJointPointer *joint;
  128. DCAST_INTO_V(joint, back);
  129. LMatrix4d ref = joint_data->get_frame(reference_model, 0);
  130. LVecBase3d ref_scale, ref_shear, ref_hpr, ref_translate;
  131. if (!decompose_matrix(ref, ref_scale, ref_shear, ref_hpr, ref_translate)) {
  132. nout << "Could not decompose rest frame for "
  133. << joint_data->get_name() << "\n";
  134. } else {
  135. int f;
  136. for (f = 0; f < num_frames; f++) {
  137. LMatrix4d mat = joint_data->get_frame(i, f);
  138. LVecBase3d scale, shear, hpr, translate;
  139. if (decompose_matrix(mat, scale, shear, hpr, translate)) {
  140. compose_matrix(mat, ref_scale, ref_shear, hpr, ref_translate);
  141. } else {
  142. nout << "Could not decompose matrix for " << joint_data->get_name()
  143. << "\n";
  144. }
  145. db.set_matrix(joint, EggCharacterDb::TT_rebuild_frame,
  146. f, mat);
  147. }
  148. }
  149. }
  150. }
  151. }
  152. int num_children = joint_data->get_num_children();
  153. for (int i = 0; i < num_children; i++) {
  154. EggJointData *next_joint_data = joint_data->get_child(i);
  155. retarget_anim(char_data, next_joint_data, reference_model, keep_names, db);
  156. }
  157. }
  158. int main(int argc, char *argv[]) {
  159. EggRetargetAnim prog;
  160. prog.parse_command_line(argc, argv);
  161. prog.run();
  162. return 0;
  163. }