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  */
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  */
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  */
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  */
196 collect_keys(pset<float> &keys) {
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  */
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  */
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 }
DaeCharacter::bind_joints
void bind_joints(JointMap &joint_map)
Binds the joints to the character.
Definition: daeCharacter.cxx:70
pt_EggVertex.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
DaeCharacter::build_table
void build_table(EggTable *parent, FCDSceneNode *node, const pset< float > &keys)
Processes a joint node and its transforms.
Definition: daeCharacter.cxx:245
eggXfmSAnim.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
DaeCharacter::collect_keys
void collect_keys(pset< float > &keys)
Collects all animation keys of animations applied to this character.
Definition: daeCharacter.cxx:196
pmap< std::string, Joint >
EggTable
This corresponds to a.
Definition: eggTable.h:27
DaeCharacter::r_collect_keys
void r_collect_keys(FCDSceneNode *node, pset< float > &keys)
Collects all animation keys found for the given node tree.
Definition: daeCharacter.cxx:213
daeCharacter.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
fcollada_utils.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
TypeHandle
TypeHandle is the identifier used to differentiate C++ class types.
Definition: typeHandle.h:81
EggXfmSAnim
This corresponds to an <Xfm$Anim_S$> entry, which is a collection of up to nine <S$Anim> entries that...
Definition: eggXfmSAnim.h:28
EggVertex
Any one-, two-, three-, or four-component vertex, possibly with attributes such as a normal.
Definition: eggVertex.h:39
config_daeegg.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
DaeCharacter::Joint
Definition: daeCharacter.h:39
EggGroup::ref_vertex
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
daeMaterials.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
DaeCharacter::adjust_joints
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.
Definition: daeCharacter.cxx:123
daeToEggConverter.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
EggGroup
The main glue of the egg hierarchy, this corresponds to the <Group>, <Instance>, and <Joint> type nod...
Definition: eggGroup.h:34
EggGroupNode::add_child
EggNode * add_child(EggNode *node)
Adds the indicated child to the group and returns it.
Definition: eggGroupNode.cxx:243
eggExternalReference.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
DaeCharacter::influence_vertex
void influence_vertex(int index, EggVertex *vertex)
Adds the influences for the given vertex.
Definition: daeCharacter.cxx:174
pset
This is our own Panda specialization on the default STL set.
Definition: pset.h:49