Panda3D
daeCharacter.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 daeCharacter.cxx
10  * @author rdb
11  * @date 2008-11-24
12  */
13 
14 #include "daeCharacter.h"
15 #include "config_daeegg.h"
16 #include "fcollada_utils.h"
17 #include "pt_EggVertex.h"
18 #include "eggXfmSAnim.h"
19 #include "daeToEggConverter.h"
20 #include "daeMaterials.h"
21 
22 #include "eggExternalReference.h"
23 
24 #include <FCDocument/FCDocument.h>
25 #include <FCDocument/FCDController.h>
26 #include <FCDocument/FCDGeometry.h>
27 #include <FCDocument/FCDSceneNodeTools.h>
28 
29 #include <FCDocument/FCDSceneNode.h>
30 #include <FCDocument/FCDTransform.h>
31 #include <FCDocument/FCDAnimated.h>
32 #include <FCDocument/FCDAnimationCurve.h>
33 #include <FCDocument/FCDAnimationKey.h>
34 
35 TypeHandle DaeCharacter::_type_handle;
36 
37 /**
38  *
39  */
40 DaeCharacter::
41 DaeCharacter(EggGroup *node_group, const FCDControllerInstance *instance) :
42  _node_group(node_group),
43  _name(node_group->get_name()),
44  _instance(instance),
45  _skin_controller(nullptr),
46  _skin_mesh(nullptr) {
47 
48  _bind_shape_mat = LMatrix4d::ident_mat();
49 
50  // If it's a skin controller, add the controller joints.
51  const FCDController *controller = (const FCDController *)instance->GetEntity();
52  if (controller == nullptr) {
53  return;
54  }
55  _skin_mesh = controller->GetBaseGeometry()->GetMesh();
56 
57  if (controller->IsSkin()) {
58  _skin_controller = controller->GetSkinController();
59  _bind_shape_mat = DAEToEggConverter::convert_matrix(_skin_controller->GetBindShapeTransform());
60  }
61 }
62 
63 /**
64  * Binds the joints to the character. This means changing them to the bind
65  * pose. It is necessary to call this before process_skin_geometry.
66  *
67  * Returns the root group.
68  */
69 void DaeCharacter::
70 bind_joints(JointMap &joint_map) {
71  _joints.clear();
72 
73  size_t num_joints = _skin_controller->GetJointCount();
74  _joints.reserve(num_joints);
75 
76  // Record the bind pose for each joint.
77  for (size_t j = 0; j < num_joints; ++j) {
78  const FCDSkinControllerJoint *skin_joint = _skin_controller->GetJoint(j);
79  std::string sid = FROM_FSTRING(skin_joint->GetId());
80  LMatrix4d bind_pose;
81  bind_pose.invert_from(DAEToEggConverter::convert_matrix(
82  skin_joint->GetBindPoseInverse()));
83 
84  // Check that we already encountered this joint during traversal.
85  JointMap::iterator ji = joint_map.find(sid);
86  if (ji != joint_map.end()) {
87  Joint &joint = ji->second;
88 
89  if (joint._character != nullptr) {
90  // In some cases, though, multiple controllers share the same joints.
91  // We can't support this without duplicating the joint structure, so
92  // we check if the bind poses are the same.
93  if (!joint._bind_pose.almost_equal(bind_pose, 0.0001)) {
94  // Ugh. What else could we do?
95  daeegg_cat.error()
96  << "Multiple controllers share joint with sid " << sid
97  << ", with different bind poses.\n";
98  }
99  } else {
100  // Mark the joint as being controlled by this character.
101  joint._bind_pose = bind_pose;
102  joint._character = this;
103  }
104 
105  _joints.push_back(joint);
106  } else {
107  daeegg_cat.warning()
108  << "Unknown joint sid being referenced: '" << sid << "'\n";
109 
110  // We still have to add a dummy joint or the index will be off.
111  _joints.push_back(Joint(nullptr, nullptr));
112  }
113  }
114 }
115 
116 /**
117  * Traverses through the character hierarchy in order to bind the mesh to the
118  * character. This involves reorienting the joints to match the bind pose.
119  *
120  * It is important that this is called only once.
121  */
122 void DaeCharacter::
123 adjust_joints(FCDSceneNode *node, const JointMap &joint_map,
124  const LMatrix4d &transform) {
125 
126  LMatrix4d this_transform = transform;
127 
128  if (node->IsJoint()) {
129  std::string sid = FROM_FSTRING(node->GetSubId());
130 
131  JointMap::const_iterator ji = joint_map.find(sid);
132  if (ji != joint_map.end()) {
133  const Joint &joint = ji->second;
134 
135  // Panda needs the joints to be in bind pose. Not fun! We copy the
136  // joint transform to the default pose, though, so that Panda will
137  // restore the joint transformation after binding.
138 
139  if (joint._character == this) {
140  LMatrix4d bind_pose = joint._bind_pose * _bind_shape_mat *
141  invert(transform);
142  // LMatrix4d bind_pose = joint._bind_pose * _bind_shape_mat *
143  // joint._group->get_parent()->get_node_frame_inv();
144 
145  this_transform = bind_pose * this_transform;
146  joint._group->set_default_pose(*joint._group);
147  joint._group->set_transform3d(bind_pose);
148 
149  /*
150  PT(EggGroup) sphere = new EggGroup;
151  sphere->add_uniform_scale(0.1);
152  sphere->set_group_type(EggGroup::GT_instance);
153  sphere->add_child(new EggExternalReference("", "jack.egg"));
154  joint._group->add_child(sphere);
155  */
156  }
157  }
158  } else {
159  // this_transform = DAEToEggConverter::convert_matrix(node->ToMatrix());
160  }
161 
162  // Loop through the children joints
163  for (size_t ch = 0; ch < node->GetChildrenCount(); ++ch) {
164  // if (node->GetChild(ch)->IsJoint()) {
165  adjust_joints(node->GetChild(ch), joint_map, this_transform);
166  // }
167  }
168 }
169 
170 /**
171  * Adds the influences for the given vertex.
172  */
173 void DaeCharacter::
174 influence_vertex(int index, EggVertex *vertex) {
175  const FCDSkinControllerVertex *influence = _skin_controller->GetVertexInfluence(index);
176 
177  for (size_t pa = 0; pa < influence->GetPairCount(); ++pa) {
178  const FCDJointWeightPair* jwpair = influence->GetPair(pa);
179 
180  if (jwpair->jointIndex >= 0 && jwpair->jointIndex < (int)_joints.size()) {
181  EggGroup *joint = _joints[jwpair->jointIndex]._group.p();
182  if (joint != nullptr) {
183  joint->ref_vertex(vertex, jwpair->weight);
184  }
185  } else {
186  daeegg_cat.error()
187  << "Invalid joint index: " << jwpair->jointIndex << "\n";
188  }
189  }
190 }
191 
192 /**
193  * Collects all animation keys of animations applied to this character.
194  */
195 void DaeCharacter::
197 #if FCOLLADA_VERSION < 0x00030005
198  FCDSceneNodeList roots = _instance->FindSkeletonNodes();
199 #else
200  FCDSceneNodeList roots;
201  _instance->FindSkeletonNodes(roots);
202 #endif
203 
204  for (FCDSceneNodeList::iterator it = roots.begin(); it != roots.end(); ++it) {
205  r_collect_keys(*it, keys);
206  }
207 }
208 
209 /**
210  * Collects all animation keys found for the given node tree.
211  */
212 void DaeCharacter::
213 r_collect_keys(FCDSceneNode* node, pset<float> &keys) {
214  FCDAnimatedList animateds;
215 
216  // Collect all the animation curves
217  for (size_t t = 0; t < node->GetTransformCount(); ++t) {
218  FCDTransform *transform = node->GetTransform(t);
219  FCDAnimated *animated = transform->GetAnimated();
220 
221  if (animated != nullptr) {
222  const FCDAnimationCurveListList &all_curves = animated->GetCurves();
223 
224  for (size_t ci = 0; ci < all_curves.size(); ++ci) {
225  const FCDAnimationCurveTrackList &curves = all_curves[ci];
226  if (curves.empty()) {
227  continue;
228  }
229 
230  size_t num_keys = curves.front()->GetKeyCount();
231  const FCDAnimationKey **curve_keys = curves.front()->GetKeys();
232 
233  for (size_t c = 0; c < num_keys; ++c) {
234  keys.insert(curve_keys[c]->input);
235  }
236  }
237  }
238  }
239 }
240 
241 /**
242  * Processes a joint node and its transforms.
243  */
244 void DaeCharacter::
245 build_table(EggTable *parent, FCDSceneNode* node, const pset<float> &keys) {
246  nassertv(node != nullptr);
247 
248  if (!node->IsJoint()) {
249  for (size_t ch = 0; ch < node->GetChildrenCount(); ++ch) {
250  build_table(parent, node->GetChild(ch), keys);
251  }
252  return;
253  }
254 
255  std::string node_id = FROM_FSTRING(node->GetDaeId());
256  PT(EggTable) table = new EggTable(node_id);
257  table->set_table_type(EggTable::TT_table);
258  parent->add_child(table);
259 
260  PT(EggXfmSAnim) xform = new EggXfmSAnim("xform");
261  table->add_child(xform);
262 
263  // Generate the sampled animation and loop through the matrices
264  FCDAnimatedList animateds;
265 
266  // Collect all the animation curves
267  for (size_t t = 0; t < node->GetTransformCount(); ++t) {
268  FCDTransform *transform = node->GetTransform(t);
269  FCDAnimated *animated = transform->GetAnimated();
270  if (animated != nullptr) {
271  if (animated->HasCurve()) {
272  animateds.push_back(animated);
273  }
274  }
275  }
276 
277  // Sample the scene node transform
278  float last_key;
279  float timing_total = 0;
281  for (ki = keys.begin(); ki != keys.end(); ++ki) {
282  for (FCDAnimatedList::iterator it = animateds.begin(); it != animateds.end(); ++it) {
283  // Sample each animated, which changes the transform values directly
284  (*it)->Evaluate(*ki);
285  }
286 
287  if (ki != keys.begin()) {
288  timing_total += (*ki - last_key);
289  }
290  last_key = *ki;
291 
292  // Retrieve the new transform matrix for the COLLADA scene node
293  FMMatrix44 fmat = node->ToMatrix();
294 
295  // Work around issue in buggy exporters (like ColladaMax)
296  if (IS_NEARLY_ZERO(fmat[3][3])) {
297  fmat[3][3] = 1;
298  }
299 
300  xform->add_data(DAEToEggConverter::convert_matrix(fmat));
301  }
302 
303  // Quantize the FPS, otherwise Panda complains about FPS mismatches.
304  float fps = cfloor(((keys.size() - 1) / timing_total) * 100 + 0.5f) * 0.01f;
305  xform->set_fps(fps);
306 
307  // Loop through the children joints
308  for (size_t ch = 0; ch < node->GetChildrenCount(); ++ch) {
309  // if (node->GetChild(ch)->IsJoint()) {
310  build_table(table, node->GetChild(ch), keys);
311  // }
312  }
313 }
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
void r_collect_keys(FCDSceneNode *node, pset< float > &keys)
Collects all animation keys found for the given node tree.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
The main glue of the egg hierarchy, this corresponds to the <Group>, <Instance>, and <Joint> type nod...
Definition: eggGroup.h:34
void influence_vertex(int index, EggVertex *vertex)
Adds the influences for the given vertex.
Any one-, two-, three-, or four-component vertex, possibly with attributes such as a normal.
Definition: eggVertex.h:39
void bind_joints(JointMap &joint_map)
Binds the joints to the character.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
This corresponds to an <Xfm$Anim_S$> entry, which is a collection of up to nine <S$Anim> entries that...
Definition: eggXfmSAnim.h:28
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
This corresponds to a.
Definition: eggTable.h:27
EggNode * add_child(EggNode *node)
Adds the indicated child to the group and returns it.
void ref_vertex(EggVertex *vert, double membership=1.0)
Adds the vertex to the set of those referenced by the group, at the indicated membership level.
Definition: eggGroup.cxx:608
This is our own Panda specialization on the default STL set.
Definition: pset.h:49
void build_table(EggTable *parent, FCDSceneNode *node, const pset< float > &keys)
Processes a joint node and its transforms.
TypeHandle is the identifier used to differentiate C++ class types.
Definition: typeHandle.h:81
void collect_keys(pset< float > &keys)
Collects all animation keys of animations applied to this character.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
void adjust_joints(FCDSceneNode *node, const JointMap &joint_map, const LMatrix4d &transform=LMatrix4d::ident_mat())
Traverses through the character hierarchy in order to bind the mesh to the character.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.