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