Panda3D
Loading...
Searching...
No Matches
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
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
35TypeHandle DaeCharacter::_type_handle;
36
37/**
38 *
39 */
40DaeCharacter::
41DaeCharacter(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 */
70bind_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 */
123adjust_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 */
174influence_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 */
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 */
213r_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 */
245build_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}
void bind_joints(JointMap &joint_map)
Binds the joints to the character.
void influence_vertex(int index, EggVertex *vertex)
Adds the influences for the given vertex.
void build_table(EggTable *parent, FCDSceneNode *node, const pset< float > &keys)
Processes a joint node and its transforms.
void collect_keys(pset< float > &keys)
Collects all animation keys of animations applied to this character.
void r_collect_keys(FCDSceneNode *node, pset< float > &keys)
Collects all animation keys found for the given node tree.
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.
EggNode * add_child(EggNode *node)
Adds the indicated child to the group and returns it.
The main glue of the egg hierarchy, this corresponds to the <Group>, <Instance>, and <Joint> type nod...
Definition eggGroup.h:34
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 corresponds to a.
Definition eggTable.h:27
Any one-, two-, three-, or four-component vertex, possibly with attributes such as a normal.
Definition eggVertex.h:39
This corresponds to an <Xfm$Anim_S$> entry, which is a collection of up to nine entries that specify...
Definition eggXfmSAnim.h:28
TypeHandle is the identifier used to differentiate C++ class types.
Definition typeHandle.h:81
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.