1 //
2 // Copyright (c) 2008-2017 the Urho3D project.
3 //
4 // Permission is hereby granted, free of charge, to any person obtaining a copy
5 // of this software and associated documentation files (the "Software"), to deal
6 // in the Software without restriction, including without limitation the rights
7 // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8 // copies of the Software, and to permit persons to whom the Software is
9 // furnished to do so, subject to the following conditions:
10 //
11 // The above copyright notice and this permission notice shall be included in
12 // all copies or substantial portions of the Software.
13 //
14 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
20 // THE SOFTWARE.
21 //
22
23 #include "../Precompiled.h"
24
25 #include "../Core/Context.h"
26 #include "../Core/Profiler.h"
27 #include "../Graphics/AnimatedModel.h"
28 #include "../Graphics/Animation.h"
29 #include "../Graphics/AnimationState.h"
30 #include "../Graphics/Batch.h"
31 #include "../Graphics/Camera.h"
32 #include "../Graphics/DebugRenderer.h"
33 #include "../Graphics/DrawableEvents.h"
34 #include "../Graphics/Geometry.h"
35 #include "../Graphics/Graphics.h"
36 #include "../Graphics/IndexBuffer.h"
37 #include "../Graphics/Material.h"
38 #include "../Graphics/Octree.h"
39 #include "../Graphics/VertexBuffer.h"
40 #include "../IO/Log.h"
41 #include "../Resource/ResourceCache.h"
42 #include "../Resource/ResourceEvents.h"
43 #include "../Scene/Scene.h"
44
45 #include "../DebugNew.h"
46
47 namespace Urho3D
48 {
49
50 extern const char* GEOMETRY_CATEGORY;
51
52 const char* animationStatesStructureElementNames[] =
53 {
54 "Anim State Count",
55 " Animation",
56 " Start Bone",
57 " Is Looped",
58 " Weight",
59 " Time",
60 " Layer",
61 0
62 };
63
CompareAnimationOrder(const SharedPtr<AnimationState> & lhs,const SharedPtr<AnimationState> & rhs)64 static bool CompareAnimationOrder(const SharedPtr<AnimationState>& lhs, const SharedPtr<AnimationState>& rhs)
65 {
66 return lhs->GetLayer() < rhs->GetLayer();
67 }
68
69 static const unsigned MAX_ANIMATION_STATES = 256;
70
AnimatedModel(Context * context)71 AnimatedModel::AnimatedModel(Context* context) :
72 StaticModel(context),
73 animationLodFrameNumber_(0),
74 morphElementMask_(0),
75 animationLodBias_(1.0f),
76 animationLodTimer_(-1.0f),
77 animationLodDistance_(0.0f),
78 updateInvisible_(false),
79 animationDirty_(false),
80 animationOrderDirty_(false),
81 morphsDirty_(false),
82 skinningDirty_(true),
83 boneBoundingBoxDirty_(true),
84 isMaster_(true),
85 loading_(false),
86 assignBonesPending_(false),
87 forceAnimationUpdate_(false)
88 {
89 }
90
~AnimatedModel()91 AnimatedModel::~AnimatedModel()
92 {
93 // When being destroyed, remove the bone hierarchy if appropriate (last AnimatedModel in the node)
94 Bone* rootBone = skeleton_.GetRootBone();
95 if (rootBone && rootBone->node_)
96 {
97 Node* parent = rootBone->node_->GetParent();
98 if (parent && !parent->GetComponent<AnimatedModel>())
99 RemoveRootBone();
100 }
101 }
102
RegisterObject(Context * context)103 void AnimatedModel::RegisterObject(Context* context)
104 {
105 context->RegisterFactory<AnimatedModel>(GEOMETRY_CATEGORY);
106
107 URHO3D_ACCESSOR_ATTRIBUTE("Is Enabled", IsEnabled, SetEnabled, bool, true, AM_DEFAULT);
108 URHO3D_MIXED_ACCESSOR_ATTRIBUTE("Model", GetModelAttr, SetModelAttr, ResourceRef, ResourceRef(Model::GetTypeStatic()), AM_DEFAULT);
109 URHO3D_ACCESSOR_ATTRIBUTE("Material", GetMaterialsAttr, SetMaterialsAttr, ResourceRefList, ResourceRefList(Material::GetTypeStatic()),
110 AM_DEFAULT);
111 URHO3D_ATTRIBUTE("Is Occluder", bool, occluder_, false, AM_DEFAULT);
112 URHO3D_ACCESSOR_ATTRIBUTE("Can Be Occluded", IsOccludee, SetOccludee, bool, true, AM_DEFAULT);
113 URHO3D_ATTRIBUTE("Cast Shadows", bool, castShadows_, false, AM_DEFAULT);
114 URHO3D_ACCESSOR_ATTRIBUTE("Update When Invisible", GetUpdateInvisible, SetUpdateInvisible, bool, false, AM_DEFAULT);
115 URHO3D_ACCESSOR_ATTRIBUTE("Draw Distance", GetDrawDistance, SetDrawDistance, float, 0.0f, AM_DEFAULT);
116 URHO3D_ACCESSOR_ATTRIBUTE("Shadow Distance", GetShadowDistance, SetShadowDistance, float, 0.0f, AM_DEFAULT);
117 URHO3D_ACCESSOR_ATTRIBUTE("LOD Bias", GetLodBias, SetLodBias, float, 1.0f, AM_DEFAULT);
118 URHO3D_ACCESSOR_ATTRIBUTE("Animation LOD Bias", GetAnimationLodBias, SetAnimationLodBias, float, 1.0f, AM_DEFAULT);
119 URHO3D_COPY_BASE_ATTRIBUTES(Drawable);
120 URHO3D_MIXED_ACCESSOR_ATTRIBUTE("Bone Animation Enabled", GetBonesEnabledAttr, SetBonesEnabledAttr, VariantVector,
121 Variant::emptyVariantVector, AM_FILE | AM_NOEDIT);
122 URHO3D_MIXED_ACCESSOR_VARIANT_VECTOR_STRUCTURE_ATTRIBUTE("Animation States", GetAnimationStatesAttr, SetAnimationStatesAttr,
123 VariantVector, Variant::emptyVariantVector,
124 animationStatesStructureElementNames, AM_FILE);
125 URHO3D_ACCESSOR_ATTRIBUTE("Morphs", GetMorphsAttr, SetMorphsAttr, PODVector<unsigned char>, Variant::emptyBuffer,
126 AM_DEFAULT | AM_NOEDIT);
127 }
128
Load(Deserializer & source,bool setInstanceDefault)129 bool AnimatedModel::Load(Deserializer& source, bool setInstanceDefault)
130 {
131 loading_ = true;
132 bool success = Component::Load(source, setInstanceDefault);
133 loading_ = false;
134
135 return success;
136 }
137
LoadXML(const XMLElement & source,bool setInstanceDefault)138 bool AnimatedModel::LoadXML(const XMLElement& source, bool setInstanceDefault)
139 {
140 loading_ = true;
141 bool success = Component::LoadXML(source, setInstanceDefault);
142 loading_ = false;
143
144 return success;
145 }
146
LoadJSON(const JSONValue & source,bool setInstanceDefault)147 bool AnimatedModel::LoadJSON(const JSONValue& source, bool setInstanceDefault)
148 {
149 loading_ = true;
150 bool success = Component::LoadJSON(source, setInstanceDefault);
151 loading_ = false;
152
153 return success;
154 }
155
ApplyAttributes()156 void AnimatedModel::ApplyAttributes()
157 {
158 if (assignBonesPending_)
159 AssignBoneNodes();
160 }
161
ProcessRayQuery(const RayOctreeQuery & query,PODVector<RayQueryResult> & results)162 void AnimatedModel::ProcessRayQuery(const RayOctreeQuery& query, PODVector<RayQueryResult>& results)
163 {
164 // If no bones or no bone-level testing, use the StaticModel test
165 RayQueryLevel level = query.level_;
166 if (level < RAY_TRIANGLE || !skeleton_.GetNumBones())
167 {
168 StaticModel::ProcessRayQuery(query, results);
169 return;
170 }
171
172 // Check ray hit distance to AABB before proceeding with bone-level tests
173 if (query.ray_.HitDistance(GetWorldBoundingBox()) >= query.maxDistance_)
174 return;
175
176 const Vector<Bone>& bones = skeleton_.GetBones();
177 Sphere boneSphere;
178
179 for (unsigned i = 0; i < bones.Size(); ++i)
180 {
181 const Bone& bone = bones[i];
182 if (!bone.node_)
183 continue;
184
185 float distance;
186
187 // Use hitbox if available
188 if (bone.collisionMask_ & BONECOLLISION_BOX)
189 {
190 // Do an initial crude test using the bone's AABB
191 const BoundingBox& box = bone.boundingBox_;
192 const Matrix3x4& transform = bone.node_->GetWorldTransform();
193 distance = query.ray_.HitDistance(box.Transformed(transform));
194 if (distance >= query.maxDistance_)
195 continue;
196 if (level != RAY_AABB)
197 {
198 // Follow with an OBB test if required
199 Matrix3x4 inverse = transform.Inverse();
200 Ray localRay = query.ray_.Transformed(inverse);
201 distance = localRay.HitDistance(box);
202 if (distance >= query.maxDistance_)
203 continue;
204 }
205 }
206 else if (bone.collisionMask_ & BONECOLLISION_SPHERE)
207 {
208 boneSphere.center_ = bone.node_->GetWorldPosition();
209 boneSphere.radius_ = bone.radius_;
210 distance = query.ray_.HitDistance(boneSphere);
211 if (distance >= query.maxDistance_)
212 continue;
213 }
214 else
215 continue;
216
217 // If the code reaches here then we have a hit
218 RayQueryResult result;
219 result.position_ = query.ray_.origin_ + distance * query.ray_.direction_;
220 result.normal_ = -query.ray_.direction_;
221 result.distance_ = distance;
222 result.drawable_ = this;
223 result.node_ = node_;
224 result.subObject_ = i;
225 results.Push(result);
226 }
227 }
228
Update(const FrameInfo & frame)229 void AnimatedModel::Update(const FrameInfo& frame)
230 {
231 // If node was invisible last frame, need to decide animation LOD distance here
232 // If headless, retain the current animation distance (should be 0)
233 if (frame.camera_ && abs((int)frame.frameNumber_ - (int)viewFrameNumber_) > 1)
234 {
235 // First check for no update at all when invisible. In that case reset LOD timer to ensure update
236 // next time the model is in view
237 if (!updateInvisible_)
238 {
239 if (animationDirty_)
240 {
241 animationLodTimer_ = -1.0f;
242 forceAnimationUpdate_ = true;
243 }
244 return;
245 }
246 float distance = frame.camera_->GetDistance(node_->GetWorldPosition());
247 // If distance is greater than draw distance, no need to update at all
248 if (drawDistance_ > 0.0f && distance > drawDistance_)
249 return;
250 float scale = GetWorldBoundingBox().Size().DotProduct(DOT_SCALE);
251 animationLodDistance_ = frame.camera_->GetLodDistance(distance, scale, lodBias_);
252 }
253
254 if (animationDirty_ || animationOrderDirty_)
255 UpdateAnimation(frame);
256 else if (boneBoundingBoxDirty_)
257 UpdateBoneBoundingBox();
258 }
259
UpdateBatches(const FrameInfo & frame)260 void AnimatedModel::UpdateBatches(const FrameInfo& frame)
261 {
262 const Matrix3x4& worldTransform = node_->GetWorldTransform();
263 const BoundingBox& worldBoundingBox = GetWorldBoundingBox();
264 distance_ = frame.camera_->GetDistance(worldBoundingBox.Center());
265
266 // Note: per-geometry distances do not take skinning into account. Especially in case of a ragdoll they may be
267 // much off base if the node's own transform is not updated
268 if (batches_.Size() == 1)
269 batches_[0].distance_ = distance_;
270 else
271 {
272 for (unsigned i = 0; i < batches_.Size(); ++i)
273 batches_[i].distance_ = frame.camera_->GetDistance(worldTransform * geometryData_[i].center_);
274 }
275
276 // Use a transformed version of the model's bounding box instead of world bounding box for LOD scale
277 // determination so that animation does not change the scale
278 BoundingBox transformedBoundingBox = boundingBox_.Transformed(worldTransform);
279 float scale = transformedBoundingBox.Size().DotProduct(DOT_SCALE);
280 float newLodDistance = frame.camera_->GetLodDistance(distance_, scale, lodBias_);
281
282 // If model is rendered from several views, use the minimum LOD distance for animation LOD
283 if (frame.frameNumber_ != animationLodFrameNumber_)
284 {
285 animationLodDistance_ = newLodDistance;
286 animationLodFrameNumber_ = frame.frameNumber_;
287 }
288 else
289 animationLodDistance_ = Min(animationLodDistance_, newLodDistance);
290
291 if (newLodDistance != lodDistance_)
292 {
293 lodDistance_ = newLodDistance;
294 CalculateLodLevels();
295 }
296 }
297
UpdateGeometry(const FrameInfo & frame)298 void AnimatedModel::UpdateGeometry(const FrameInfo& frame)
299 {
300 // Late update in case the model came into view and animation was dirtied in the meanwhile
301 if (forceAnimationUpdate_)
302 {
303 UpdateAnimation(frame);
304 forceAnimationUpdate_ = false;
305 }
306
307 if (morphsDirty_)
308 UpdateMorphs();
309
310 if (skinningDirty_)
311 UpdateSkinning();
312 }
313
GetUpdateGeometryType()314 UpdateGeometryType AnimatedModel::GetUpdateGeometryType()
315 {
316 if (morphsDirty_ || forceAnimationUpdate_)
317 return UPDATE_MAIN_THREAD;
318 else if (skinningDirty_)
319 return UPDATE_WORKER_THREAD;
320 else
321 return UPDATE_NONE;
322 }
323
DrawDebugGeometry(DebugRenderer * debug,bool depthTest)324 void AnimatedModel::DrawDebugGeometry(DebugRenderer* debug, bool depthTest)
325 {
326 if (debug && IsEnabledEffective())
327 {
328 debug->AddBoundingBox(GetWorldBoundingBox(), Color::GREEN, depthTest);
329 debug->AddSkeleton(skeleton_, Color(0.75f, 0.75f, 0.75f), depthTest);
330 }
331 }
332
SetModel(Model * model,bool createBones)333 void AnimatedModel::SetModel(Model* model, bool createBones)
334 {
335 if (model == model_)
336 return;
337
338 if (!node_)
339 {
340 URHO3D_LOGERROR("Can not set model while model component is not attached to a scene node");
341 return;
342 }
343
344 // Unsubscribe from the reload event of previous model (if any), then subscribe to the new
345 if (model_)
346 UnsubscribeFromEvent(model_, E_RELOADFINISHED);
347
348 model_ = model;
349
350 if (model)
351 {
352 SubscribeToEvent(model, E_RELOADFINISHED, URHO3D_HANDLER(AnimatedModel, HandleModelReloadFinished));
353
354 // Copy the subgeometry & LOD level structure
355 SetNumGeometries(model->GetNumGeometries());
356 const Vector<Vector<SharedPtr<Geometry> > >& geometries = model->GetGeometries();
357 const PODVector<Vector3>& geometryCenters = model->GetGeometryCenters();
358 for (unsigned i = 0; i < geometries.Size(); ++i)
359 {
360 geometries_[i] = geometries[i];
361 geometryData_[i].center_ = geometryCenters[i];
362 }
363
364 // Copy geometry bone mappings
365 const Vector<PODVector<unsigned> >& geometryBoneMappings = model->GetGeometryBoneMappings();
366 geometryBoneMappings_.Clear();
367 geometryBoneMappings_.Reserve(geometryBoneMappings.Size());
368 for (unsigned i = 0; i < geometryBoneMappings.Size(); ++i)
369 geometryBoneMappings_.Push(geometryBoneMappings[i]);
370
371 // Copy morphs. Note: morph vertex buffers will be created later on-demand
372 morphVertexBuffers_.Clear();
373 morphs_.Clear();
374 const Vector<ModelMorph>& morphs = model->GetMorphs();
375 morphs_.Reserve(morphs.Size());
376 morphElementMask_ = 0;
377 for (unsigned i = 0; i < morphs.Size(); ++i)
378 {
379 ModelMorph newMorph;
380 newMorph.name_ = morphs[i].name_;
381 newMorph.nameHash_ = morphs[i].nameHash_;
382 newMorph.weight_ = 0.0f;
383 newMorph.buffers_ = morphs[i].buffers_;
384 for (HashMap<unsigned, VertexBufferMorph>::ConstIterator j = morphs[i].buffers_.Begin();
385 j != morphs[i].buffers_.End(); ++j)
386 morphElementMask_ |= j->second_.elementMask_;
387 morphs_.Push(newMorph);
388 }
389
390 // Copy bounding box & skeleton
391 SetBoundingBox(model->GetBoundingBox());
392 // Initial bone bounding box is just the one stored in the model
393 boneBoundingBox_ = boundingBox_;
394 boneBoundingBoxDirty_ = true;
395 SetSkeleton(model->GetSkeleton(), createBones);
396 ResetLodLevels();
397
398 // Reserve space for skinning matrices
399 skinMatrices_.Resize(skeleton_.GetNumBones());
400 SetGeometryBoneMappings();
401
402 // Enable skinning in batches
403 for (unsigned i = 0; i < batches_.Size(); ++i)
404 {
405 if (skinMatrices_.Size())
406 {
407 batches_[i].geometryType_ = GEOM_SKINNED;
408 // Check if model has per-geometry bone mappings
409 if (geometrySkinMatrices_.Size() && geometrySkinMatrices_[i].Size())
410 {
411 batches_[i].worldTransform_ = &geometrySkinMatrices_[i][0];
412 batches_[i].numWorldTransforms_ = geometrySkinMatrices_[i].Size();
413 }
414 // If not, use the global skin matrices
415 else
416 {
417 batches_[i].worldTransform_ = &skinMatrices_[0];
418 batches_[i].numWorldTransforms_ = skinMatrices_.Size();
419 }
420 }
421 else
422 {
423 batches_[i].geometryType_ = GEOM_STATIC;
424 batches_[i].worldTransform_ = &node_->GetWorldTransform();
425 batches_[i].numWorldTransforms_ = 1;
426 }
427 }
428 }
429 else
430 {
431 RemoveRootBone(); // Remove existing root bone if any
432 SetNumGeometries(0);
433 geometryBoneMappings_.Clear();
434 morphVertexBuffers_.Clear();
435 morphs_.Clear();
436 morphElementMask_ = 0;
437 SetBoundingBox(BoundingBox());
438 SetSkeleton(Skeleton(), false);
439 }
440
441 MarkNetworkUpdate();
442 }
443
AddAnimationState(Animation * animation)444 AnimationState* AnimatedModel::AddAnimationState(Animation* animation)
445 {
446 if (!isMaster_)
447 {
448 URHO3D_LOGERROR("Can not add animation state to non-master model");
449 return 0;
450 }
451
452 if (!animation || !skeleton_.GetNumBones())
453 return 0;
454
455 // Check for not adding twice
456 AnimationState* existing = GetAnimationState(animation);
457 if (existing)
458 return existing;
459
460 SharedPtr<AnimationState> newState(new AnimationState(this, animation));
461 animationStates_.Push(newState);
462 MarkAnimationOrderDirty();
463 return newState;
464 }
465
RemoveAnimationState(Animation * animation)466 void AnimatedModel::RemoveAnimationState(Animation* animation)
467 {
468 if (animation)
469 RemoveAnimationState(animation->GetNameHash());
470 else
471 {
472 for (Vector<SharedPtr<AnimationState> >::Iterator i = animationStates_.Begin(); i != animationStates_.End(); ++i)
473 {
474 AnimationState* state = *i;
475 if (!state->GetAnimation())
476 {
477 animationStates_.Erase(i);
478 MarkAnimationDirty();
479 return;
480 }
481 }
482 }
483 }
484
RemoveAnimationState(const String & animationName)485 void AnimatedModel::RemoveAnimationState(const String& animationName)
486 {
487 RemoveAnimationState(StringHash(animationName));
488 }
489
RemoveAnimationState(StringHash animationNameHash)490 void AnimatedModel::RemoveAnimationState(StringHash animationNameHash)
491 {
492 for (Vector<SharedPtr<AnimationState> >::Iterator i = animationStates_.Begin(); i != animationStates_.End(); ++i)
493 {
494 AnimationState* state = *i;
495 Animation* animation = state->GetAnimation();
496 if (animation)
497 {
498 // Check both the animation and the resource name
499 if (animation->GetNameHash() == animationNameHash || animation->GetAnimationNameHash() == animationNameHash)
500 {
501 animationStates_.Erase(i);
502 MarkAnimationDirty();
503 return;
504 }
505 }
506 }
507 }
508
RemoveAnimationState(AnimationState * state)509 void AnimatedModel::RemoveAnimationState(AnimationState* state)
510 {
511 for (Vector<SharedPtr<AnimationState> >::Iterator i = animationStates_.Begin(); i != animationStates_.End(); ++i)
512 {
513 if (*i == state)
514 {
515 animationStates_.Erase(i);
516 MarkAnimationDirty();
517 return;
518 }
519 }
520 }
521
RemoveAnimationState(unsigned index)522 void AnimatedModel::RemoveAnimationState(unsigned index)
523 {
524 if (index < animationStates_.Size())
525 {
526 animationStates_.Erase(index);
527 MarkAnimationDirty();
528 }
529 }
530
RemoveAllAnimationStates()531 void AnimatedModel::RemoveAllAnimationStates()
532 {
533 if (animationStates_.Size())
534 {
535 animationStates_.Clear();
536 MarkAnimationDirty();
537 }
538 }
539
SetAnimationLodBias(float bias)540 void AnimatedModel::SetAnimationLodBias(float bias)
541 {
542 animationLodBias_ = Max(bias, 0.0f);
543 MarkNetworkUpdate();
544 }
545
SetUpdateInvisible(bool enable)546 void AnimatedModel::SetUpdateInvisible(bool enable)
547 {
548 updateInvisible_ = enable;
549 MarkNetworkUpdate();
550 }
551
552
SetMorphWeight(unsigned index,float weight)553 void AnimatedModel::SetMorphWeight(unsigned index, float weight)
554 {
555 if (index >= morphs_.Size())
556 return;
557
558 // If morph vertex buffers have not been created yet, create now
559 if (weight != 0.0f && morphVertexBuffers_.Empty())
560 CloneGeometries();
561
562 if (weight != morphs_[index].weight_)
563 {
564 morphs_[index].weight_ = weight;
565
566 // For a master model, set the same morph weight on non-master models
567 if (isMaster_)
568 {
569 PODVector<AnimatedModel*> models;
570 GetComponents<AnimatedModel>(models);
571
572 // Indexing might not be the same, so use the name hash instead
573 for (unsigned i = 1; i < models.Size(); ++i)
574 {
575 if (!models[i]->isMaster_)
576 models[i]->SetMorphWeight(morphs_[index].nameHash_, weight);
577 }
578 }
579
580 MarkMorphsDirty();
581 MarkNetworkUpdate();
582 }
583 }
584
SetMorphWeight(const String & name,float weight)585 void AnimatedModel::SetMorphWeight(const String& name, float weight)
586 {
587 for (unsigned i = 0; i < morphs_.Size(); ++i)
588 {
589 if (morphs_[i].name_ == name)
590 {
591 SetMorphWeight(i, weight);
592 return;
593 }
594 }
595 }
596
SetMorphWeight(StringHash nameHash,float weight)597 void AnimatedModel::SetMorphWeight(StringHash nameHash, float weight)
598 {
599 for (unsigned i = 0; i < morphs_.Size(); ++i)
600 {
601 if (morphs_[i].nameHash_ == nameHash)
602 {
603 SetMorphWeight(i, weight);
604 return;
605 }
606 }
607 }
608
ResetMorphWeights()609 void AnimatedModel::ResetMorphWeights()
610 {
611 for (Vector<ModelMorph>::Iterator i = morphs_.Begin(); i != morphs_.End(); ++i)
612 i->weight_ = 0.0f;
613
614 // For a master model, reset weights on non-master models
615 if (isMaster_)
616 {
617 PODVector<AnimatedModel*> models;
618 GetComponents<AnimatedModel>(models);
619
620 for (unsigned i = 1; i < models.Size(); ++i)
621 {
622 if (!models[i]->isMaster_)
623 models[i]->ResetMorphWeights();
624 }
625 }
626
627 MarkMorphsDirty();
628 MarkNetworkUpdate();
629 }
630
GetMorphWeight(unsigned index) const631 float AnimatedModel::GetMorphWeight(unsigned index) const
632 {
633 return index < morphs_.Size() ? morphs_[index].weight_ : 0.0f;
634 }
635
GetMorphWeight(const String & name) const636 float AnimatedModel::GetMorphWeight(const String& name) const
637 {
638 for (Vector<ModelMorph>::ConstIterator i = morphs_.Begin(); i != morphs_.End(); ++i)
639 {
640 if (i->name_ == name)
641 return i->weight_;
642 }
643
644 return 0.0f;
645 }
646
GetMorphWeight(StringHash nameHash) const647 float AnimatedModel::GetMorphWeight(StringHash nameHash) const
648 {
649 for (Vector<ModelMorph>::ConstIterator i = morphs_.Begin(); i != morphs_.End(); ++i)
650 {
651 if (i->nameHash_ == nameHash)
652 return i->weight_;
653 }
654
655 return 0.0f;
656 }
657
GetAnimationState(Animation * animation) const658 AnimationState* AnimatedModel::GetAnimationState(Animation* animation) const
659 {
660 for (Vector<SharedPtr<AnimationState> >::ConstIterator i = animationStates_.Begin(); i != animationStates_.End(); ++i)
661 {
662 if ((*i)->GetAnimation() == animation)
663 return *i;
664 }
665
666 return 0;
667 }
668
GetAnimationState(const String & animationName) const669 AnimationState* AnimatedModel::GetAnimationState(const String& animationName) const
670 {
671 return GetAnimationState(StringHash(animationName));
672 }
673
GetAnimationState(StringHash animationNameHash) const674 AnimationState* AnimatedModel::GetAnimationState(StringHash animationNameHash) const
675 {
676 for (Vector<SharedPtr<AnimationState> >::ConstIterator i = animationStates_.Begin(); i != animationStates_.End(); ++i)
677 {
678 Animation* animation = (*i)->GetAnimation();
679 if (animation)
680 {
681 // Check both the animation and the resource name
682 if (animation->GetNameHash() == animationNameHash || animation->GetAnimationNameHash() == animationNameHash)
683 return *i;
684 }
685 }
686
687 return 0;
688 }
689
GetAnimationState(unsigned index) const690 AnimationState* AnimatedModel::GetAnimationState(unsigned index) const
691 {
692 return index < animationStates_.Size() ? animationStates_[index].Get() : 0;
693 }
694
SetSkeleton(const Skeleton & skeleton,bool createBones)695 void AnimatedModel::SetSkeleton(const Skeleton& skeleton, bool createBones)
696 {
697 if (!node_ && createBones)
698 {
699 URHO3D_LOGERROR("AnimatedModel not attached to a scene node, can not create bone nodes");
700 return;
701 }
702
703 if (isMaster_)
704 {
705 // Check if bone structure has stayed compatible (reloading the model.) In that case retain the old bones and animations
706 if (skeleton_.GetNumBones() == skeleton.GetNumBones())
707 {
708 Vector<Bone>& destBones = skeleton_.GetModifiableBones();
709 const Vector<Bone>& srcBones = skeleton.GetBones();
710 bool compatible = true;
711
712 for (unsigned i = 0; i < destBones.Size(); ++i)
713 {
714 if (destBones[i].node_ && destBones[i].name_ == srcBones[i].name_ && destBones[i].parentIndex_ ==
715 srcBones[i].parentIndex_)
716 {
717 // If compatible, just copy the values and retain the old node and animated status
718 Node* boneNode = destBones[i].node_;
719 bool animated = destBones[i].animated_;
720 destBones[i] = srcBones[i];
721 destBones[i].node_ = boneNode;
722 destBones[i].animated_ = animated;
723 }
724 else
725 {
726 compatible = false;
727 break;
728 }
729 }
730 if (compatible)
731 return;
732 }
733
734 RemoveAllAnimationStates();
735
736 // Detach the rootbone of the previous model if any
737 if (createBones)
738 RemoveRootBone();
739
740 skeleton_.Define(skeleton);
741
742 // Merge bounding boxes from non-master models
743 FinalizeBoneBoundingBoxes();
744
745 Vector<Bone>& bones = skeleton_.GetModifiableBones();
746 // Create scene nodes for the bones
747 if (createBones)
748 {
749 for (Vector<Bone>::Iterator i = bones.Begin(); i != bones.End(); ++i)
750 {
751 // Create bones as local, as they are never to be directly synchronized over the network
752 Node* boneNode = node_->CreateChild(i->name_, LOCAL);
753 boneNode->AddListener(this);
754 boneNode->SetTransform(i->initialPosition_, i->initialRotation_, i->initialScale_);
755 // Copy the model component's temporary status
756 boneNode->SetTemporary(IsTemporary());
757 i->node_ = boneNode;
758 }
759
760 for (unsigned i = 0; i < bones.Size(); ++i)
761 {
762 unsigned parentIndex = bones[i].parentIndex_;
763 if (parentIndex != i && parentIndex < bones.Size())
764 bones[parentIndex].node_->AddChild(bones[i].node_);
765 }
766 }
767
768 using namespace BoneHierarchyCreated;
769
770 VariantMap& eventData = GetEventDataMap();
771 eventData[P_NODE] = node_;
772 node_->SendEvent(E_BONEHIERARCHYCREATED, eventData);
773 }
774 else
775 {
776 // For non-master models: use the bone nodes of the master model
777 skeleton_.Define(skeleton);
778
779 // Instruct the master model to refresh (merge) its bone bounding boxes
780 AnimatedModel* master = node_->GetComponent<AnimatedModel>();
781 if (master && master != this)
782 master->FinalizeBoneBoundingBoxes();
783
784 if (createBones)
785 {
786 Vector<Bone>& bones = skeleton_.GetModifiableBones();
787 for (Vector<Bone>::Iterator i = bones.Begin(); i != bones.End(); ++i)
788 {
789 Node* boneNode = node_->GetChild(i->name_, true);
790 if (boneNode)
791 boneNode->AddListener(this);
792 i->node_ = boneNode;
793 }
794 }
795 }
796
797 assignBonesPending_ = !createBones;
798 }
799
SetModelAttr(const ResourceRef & value)800 void AnimatedModel::SetModelAttr(const ResourceRef& value)
801 {
802 ResourceCache* cache = GetSubsystem<ResourceCache>();
803 // When loading a scene, set model without creating the bone nodes (will be assigned later during post-load)
804 SetModel(cache->GetResource<Model>(value.name_), !loading_);
805 }
806
SetBonesEnabledAttr(const VariantVector & value)807 void AnimatedModel::SetBonesEnabledAttr(const VariantVector& value)
808 {
809 Vector<Bone>& bones = skeleton_.GetModifiableBones();
810 for (unsigned i = 0; i < bones.Size() && i < value.Size(); ++i)
811 bones[i].animated_ = value[i].GetBool();
812 }
813
SetAnimationStatesAttr(const VariantVector & value)814 void AnimatedModel::SetAnimationStatesAttr(const VariantVector& value)
815 {
816 ResourceCache* cache = GetSubsystem<ResourceCache>();
817 RemoveAllAnimationStates();
818 unsigned index = 0;
819 unsigned numStates = index < value.Size() ? value[index++].GetUInt() : 0;
820 // Prevent negative or overly large value being assigned from the editor
821 if (numStates > M_MAX_INT)
822 numStates = 0;
823 if (numStates > MAX_ANIMATION_STATES)
824 numStates = MAX_ANIMATION_STATES;
825
826 animationStates_.Reserve(numStates);
827 while (numStates--)
828 {
829 if (index + 5 < value.Size())
830 {
831 // Note: null animation is allowed here for editing
832 const ResourceRef& animRef = value[index++].GetResourceRef();
833 SharedPtr<AnimationState> newState(new AnimationState(this, cache->GetResource<Animation>(animRef.name_)));
834 animationStates_.Push(newState);
835
836 newState->SetStartBone(skeleton_.GetBone(value[index++].GetString()));
837 newState->SetLooped(value[index++].GetBool());
838 newState->SetWeight(value[index++].GetFloat());
839 newState->SetTime(value[index++].GetFloat());
840 newState->SetLayer((unsigned char)value[index++].GetInt());
841 }
842 else
843 {
844 // If not enough data, just add an empty animation state
845 SharedPtr<AnimationState> newState(new AnimationState(this, 0));
846 animationStates_.Push(newState);
847 }
848 }
849
850 if (animationStates_.Size())
851 {
852 MarkAnimationDirty();
853 MarkAnimationOrderDirty();
854 }
855 }
856
SetMorphsAttr(const PODVector<unsigned char> & value)857 void AnimatedModel::SetMorphsAttr(const PODVector<unsigned char>& value)
858 {
859 for (unsigned index = 0; index < value.Size(); ++index)
860 SetMorphWeight(index, (float)value[index] / 255.0f);
861 }
862
GetModelAttr() const863 ResourceRef AnimatedModel::GetModelAttr() const
864 {
865 return GetResourceRef(model_, Model::GetTypeStatic());
866 }
867
GetBonesEnabledAttr() const868 VariantVector AnimatedModel::GetBonesEnabledAttr() const
869 {
870 VariantVector ret;
871 const Vector<Bone>& bones = skeleton_.GetBones();
872 ret.Reserve(bones.Size());
873 for (Vector<Bone>::ConstIterator i = bones.Begin(); i != bones.End(); ++i)
874 ret.Push(i->animated_);
875 return ret;
876 }
877
GetAnimationStatesAttr() const878 VariantVector AnimatedModel::GetAnimationStatesAttr() const
879 {
880 VariantVector ret;
881 ret.Reserve(animationStates_.Size() * 6 + 1);
882 ret.Push(animationStates_.Size());
883 for (Vector<SharedPtr<AnimationState> >::ConstIterator i = animationStates_.Begin(); i != animationStates_.End(); ++i)
884 {
885 AnimationState* state = *i;
886 Animation* animation = state->GetAnimation();
887 Bone* startBone = state->GetStartBone();
888 ret.Push(GetResourceRef(animation, Animation::GetTypeStatic()));
889 ret.Push(startBone ? startBone->name_ : String::EMPTY);
890 ret.Push(state->IsLooped());
891 ret.Push(state->GetWeight());
892 ret.Push(state->GetTime());
893 ret.Push((int)state->GetLayer());
894 }
895 return ret;
896 }
897
GetMorphsAttr() const898 const PODVector<unsigned char>& AnimatedModel::GetMorphsAttr() const
899 {
900 attrBuffer_.Clear();
901 for (Vector<ModelMorph>::ConstIterator i = morphs_.Begin(); i != morphs_.End(); ++i)
902 attrBuffer_.WriteUByte((unsigned char)(i->weight_ * 255.0f));
903
904 return attrBuffer_.GetBuffer();
905 }
906
UpdateBoneBoundingBox()907 void AnimatedModel::UpdateBoneBoundingBox()
908 {
909 if (skeleton_.GetNumBones())
910 {
911 // The bone bounding box is in local space, so need the node's inverse transform
912 boneBoundingBox_.Clear();
913 Matrix3x4 inverseNodeTransform = node_->GetWorldTransform().Inverse();
914
915 const Vector<Bone>& bones = skeleton_.GetBones();
916 for (Vector<Bone>::ConstIterator i = bones.Begin(); i != bones.End(); ++i)
917 {
918 Node* boneNode = i->node_;
919 if (!boneNode)
920 continue;
921
922 // Use hitbox if available. If not, use only half of the sphere radius
923 /// \todo The sphere radius should be multiplied with bone scale
924 if (i->collisionMask_ & BONECOLLISION_BOX)
925 boneBoundingBox_.Merge(i->boundingBox_.Transformed(inverseNodeTransform * boneNode->GetWorldTransform()));
926 else if (i->collisionMask_ & BONECOLLISION_SPHERE)
927 boneBoundingBox_.Merge(Sphere(inverseNodeTransform * boneNode->GetWorldPosition(), i->radius_ * 0.5f));
928 }
929 }
930
931 boneBoundingBoxDirty_ = false;
932 worldBoundingBoxDirty_ = true;
933 }
934
OnNodeSet(Node * node)935 void AnimatedModel::OnNodeSet(Node* node)
936 {
937 Drawable::OnNodeSet(node);
938
939 if (node)
940 {
941 // If this AnimatedModel is the first in the node, it is the master which controls animation & morphs
942 isMaster_ = GetComponent<AnimatedModel>() == this;
943 }
944 }
945
OnMarkedDirty(Node * node)946 void AnimatedModel::OnMarkedDirty(Node* node)
947 {
948 Drawable::OnMarkedDirty(node);
949
950 // If the scene node or any of the bone nodes move, mark skinning dirty
951 if (skeleton_.GetNumBones())
952 {
953 skinningDirty_ = true;
954 // Bone bounding box doesn't need to be marked dirty when only the base scene node moves
955 if (node != node_)
956 boneBoundingBoxDirty_ = true;
957 }
958 }
959
OnWorldBoundingBoxUpdate()960 void AnimatedModel::OnWorldBoundingBoxUpdate()
961 {
962 if (isMaster_)
963 {
964 // Note: do not update bone bounding box here, instead do it in either of the threaded updates
965 worldBoundingBox_ = boneBoundingBox_.Transformed(node_->GetWorldTransform());
966 }
967 else
968 {
969 // Non-master animated models get the bounding box from the master
970 /// \todo If it's a skinned attachment that does not cover the whole body, it will have unnecessarily large bounds
971 AnimatedModel* master = node_->GetComponent<AnimatedModel>();
972 // Check if we've become the new master model in case the original was deleted
973 if (master == this)
974 isMaster_ = true;
975 if (master)
976 worldBoundingBox_ = master->GetWorldBoundingBox();
977 }
978 }
979
AssignBoneNodes()980 void AnimatedModel::AssignBoneNodes()
981 {
982 assignBonesPending_ = false;
983
984 if (!node_)
985 return;
986
987 // Find the bone nodes from the node hierarchy and add listeners
988 Vector<Bone>& bones = skeleton_.GetModifiableBones();
989 bool boneFound = false;
990 for (Vector<Bone>::Iterator i = bones.Begin(); i != bones.End(); ++i)
991 {
992 Node* boneNode = node_->GetChild(i->name_, true);
993 if (boneNode)
994 {
995 boneFound = true;
996 boneNode->AddListener(this);
997 }
998 i->node_ = boneNode;
999 }
1000
1001 // If no bones found, this may be a prefab where the bone information was left out.
1002 // In that case reassign the skeleton now if possible
1003 if (!boneFound && model_)
1004 SetSkeleton(model_->GetSkeleton(), true);
1005
1006 // Re-assign the same start bone to animations to get the proper bone node this time
1007 for (Vector<SharedPtr<AnimationState> >::Iterator i = animationStates_.Begin(); i != animationStates_.End(); ++i)
1008 {
1009 AnimationState* state = *i;
1010 state->SetStartBone(state->GetStartBone());
1011 }
1012 }
1013
FinalizeBoneBoundingBoxes()1014 void AnimatedModel::FinalizeBoneBoundingBoxes()
1015 {
1016 Vector<Bone>& bones = skeleton_.GetModifiableBones();
1017 PODVector<AnimatedModel*> models;
1018 GetComponents<AnimatedModel>(models);
1019
1020 if (models.Size() > 1)
1021 {
1022 // Reset first to the model resource's original bone bounding information if available (should be)
1023 if (model_)
1024 {
1025 const Vector<Bone>& modelBones = model_->GetSkeleton().GetBones();
1026 for (unsigned i = 0; i < bones.Size() && i < modelBones.Size(); ++i)
1027 {
1028 bones[i].collisionMask_ = modelBones[i].collisionMask_;
1029 bones[i].radius_ = modelBones[i].radius_;
1030 bones[i].boundingBox_ = modelBones[i].boundingBox_;
1031 }
1032 }
1033
1034 // Get matching bones from all non-master models and merge their bone bounding information
1035 // to prevent culling errors (master model may not have geometry in all bones, or the bounds are smaller)
1036 for (PODVector<AnimatedModel*>::Iterator i = models.Begin(); i != models.End(); ++i)
1037 {
1038 if ((*i) == this)
1039 continue;
1040
1041 Skeleton& otherSkeleton = (*i)->GetSkeleton();
1042 for (Vector<Bone>::Iterator j = bones.Begin(); j != bones.End(); ++j)
1043 {
1044 Bone* otherBone = otherSkeleton.GetBone(j->nameHash_);
1045 if (otherBone)
1046 {
1047 if (otherBone->collisionMask_ & BONECOLLISION_SPHERE)
1048 {
1049 j->collisionMask_ |= BONECOLLISION_SPHERE;
1050 j->radius_ = Max(j->radius_, otherBone->radius_);
1051 }
1052 if (otherBone->collisionMask_ & BONECOLLISION_BOX)
1053 {
1054 j->collisionMask_ |= BONECOLLISION_BOX;
1055 if (j->boundingBox_.Defined())
1056 j->boundingBox_.Merge(otherBone->boundingBox_);
1057 else
1058 j->boundingBox_.Define(otherBone->boundingBox_);
1059 }
1060 }
1061 }
1062 }
1063 }
1064
1065 // Remove collision information from dummy bones that do not affect skinning, to prevent them from being merged
1066 // to the bounding box and making it artificially large
1067 for (Vector<Bone>::Iterator i = bones.Begin(); i != bones.End(); ++i)
1068 {
1069 if (i->collisionMask_ & BONECOLLISION_BOX && i->boundingBox_.Size().Length() < M_EPSILON)
1070 i->collisionMask_ &= ~BONECOLLISION_BOX;
1071 if (i->collisionMask_ & BONECOLLISION_SPHERE && i->radius_ < M_EPSILON)
1072 i->collisionMask_ &= ~BONECOLLISION_SPHERE;
1073 }
1074 }
1075
RemoveRootBone()1076 void AnimatedModel::RemoveRootBone()
1077 {
1078 Bone* rootBone = skeleton_.GetRootBone();
1079 if (rootBone && rootBone->node_)
1080 rootBone->node_->Remove();
1081 }
1082
MarkAnimationDirty()1083 void AnimatedModel::MarkAnimationDirty()
1084 {
1085 if (isMaster_)
1086 {
1087 animationDirty_ = true;
1088 MarkForUpdate();
1089 }
1090 }
1091
MarkAnimationOrderDirty()1092 void AnimatedModel::MarkAnimationOrderDirty()
1093 {
1094 if (isMaster_)
1095 {
1096 animationOrderDirty_ = true;
1097 MarkForUpdate();
1098 }
1099 }
1100
MarkMorphsDirty()1101 void AnimatedModel::MarkMorphsDirty()
1102 {
1103 morphsDirty_ = true;
1104 }
1105
CloneGeometries()1106 void AnimatedModel::CloneGeometries()
1107 {
1108 const Vector<SharedPtr<VertexBuffer> >& originalVertexBuffers = model_->GetVertexBuffers();
1109 HashMap<VertexBuffer*, SharedPtr<VertexBuffer> > clonedVertexBuffers;
1110 morphVertexBuffers_.Resize(originalVertexBuffers.Size());
1111
1112 for (unsigned i = 0; i < originalVertexBuffers.Size(); ++i)
1113 {
1114 VertexBuffer* original = originalVertexBuffers[i];
1115 if (model_->GetMorphRangeCount(i))
1116 {
1117 SharedPtr<VertexBuffer> clone(new VertexBuffer(context_));
1118 clone->SetShadowed(true);
1119 clone->SetSize(original->GetVertexCount(), morphElementMask_ & original->GetElementMask(), true);
1120 void* dest = clone->Lock(0, original->GetVertexCount());
1121 if (dest)
1122 {
1123 CopyMorphVertices(dest, original->GetShadowData(), original->GetVertexCount(), clone, original);
1124 clone->Unlock();
1125 }
1126 clonedVertexBuffers[original] = clone;
1127 morphVertexBuffers_[i] = clone;
1128 }
1129 else
1130 morphVertexBuffers_[i].Reset();
1131 }
1132
1133 // Geometries will always be cloned fully. They contain only references to buffer, so they are relatively light
1134 for (unsigned i = 0; i < geometries_.Size(); ++i)
1135 {
1136 for (unsigned j = 0; j < geometries_[i].Size(); ++j)
1137 {
1138 SharedPtr<Geometry> original = geometries_[i][j];
1139 SharedPtr<Geometry> clone(new Geometry(context_));
1140
1141 // Add an additional vertex stream into the clone, which supplies only the morphable vertex data, while the static
1142 // data comes from the original vertex buffer(s)
1143 const Vector<SharedPtr<VertexBuffer> >& originalBuffers = original->GetVertexBuffers();
1144 unsigned totalBuf = originalBuffers.Size();
1145 for (unsigned k = 0; k < originalBuffers.Size(); ++k)
1146 {
1147 VertexBuffer* originalBuffer = originalBuffers[k];
1148 if (clonedVertexBuffers.Contains(originalBuffer))
1149 ++totalBuf;
1150 }
1151 clone->SetNumVertexBuffers(totalBuf);
1152
1153 unsigned l = 0;
1154 for (unsigned k = 0; k < originalBuffers.Size(); ++k)
1155 {
1156 VertexBuffer* originalBuffer = originalBuffers[k];
1157
1158 if (clonedVertexBuffers.Contains(originalBuffer))
1159 {
1160 VertexBuffer* clonedBuffer = clonedVertexBuffers[originalBuffer];
1161 clone->SetVertexBuffer(l++, originalBuffer);
1162 // Specify the morph buffer at a greater index to override the model's original positions/normals/tangents
1163 clone->SetVertexBuffer(l++, clonedBuffer);
1164 }
1165 else
1166 clone->SetVertexBuffer(l++, originalBuffer);
1167 }
1168
1169 clone->SetIndexBuffer(original->GetIndexBuffer());
1170 clone->SetDrawRange(original->GetPrimitiveType(), original->GetIndexStart(), original->GetIndexCount());
1171 clone->SetLodDistance(original->GetLodDistance());
1172
1173 geometries_[i][j] = clone;
1174 }
1175 }
1176
1177 // Make sure the rendering batches use the new cloned geometries
1178 ResetLodLevels();
1179 MarkMorphsDirty();
1180 }
1181
CopyMorphVertices(void * destVertexData,void * srcVertexData,unsigned vertexCount,VertexBuffer * destBuffer,VertexBuffer * srcBuffer)1182 void AnimatedModel::CopyMorphVertices(void* destVertexData, void* srcVertexData, unsigned vertexCount, VertexBuffer* destBuffer,
1183 VertexBuffer* srcBuffer)
1184 {
1185 unsigned mask = destBuffer->GetElementMask() & srcBuffer->GetElementMask();
1186 unsigned normalOffset = srcBuffer->GetElementOffset(SEM_NORMAL);
1187 unsigned tangentOffset = srcBuffer->GetElementOffset(SEM_TANGENT);
1188 unsigned vertexSize = srcBuffer->GetVertexSize();
1189 float* dest = (float*)destVertexData;
1190 unsigned char* src = (unsigned char*)srcVertexData;
1191
1192 while (vertexCount--)
1193 {
1194 if (mask & MASK_POSITION)
1195 {
1196 float* posSrc = (float*)src;
1197 dest[0] = posSrc[0];
1198 dest[1] = posSrc[1];
1199 dest[2] = posSrc[2];
1200 dest += 3;
1201 }
1202 if (mask & MASK_NORMAL)
1203 {
1204 float* normalSrc = (float*)(src + normalOffset);
1205 dest[0] = normalSrc[0];
1206 dest[1] = normalSrc[1];
1207 dest[2] = normalSrc[2];
1208 dest += 3;
1209 }
1210 if (mask & MASK_TANGENT)
1211 {
1212 float* tangentSrc = (float*)(src + tangentOffset);
1213 dest[0] = tangentSrc[0];
1214 dest[1] = tangentSrc[1];
1215 dest[2] = tangentSrc[2];
1216 dest[3] = tangentSrc[3];
1217 dest += 4;
1218 }
1219
1220 src += vertexSize;
1221 }
1222 }
1223
SetGeometryBoneMappings()1224 void AnimatedModel::SetGeometryBoneMappings()
1225 {
1226 geometrySkinMatrices_.Clear();
1227 geometrySkinMatrixPtrs_.Clear();
1228
1229 if (!geometryBoneMappings_.Size())
1230 return;
1231
1232 // Check if all mappings are empty, then we do not need to use mapped skinning
1233 bool allEmpty = true;
1234 for (unsigned i = 0; i < geometryBoneMappings_.Size(); ++i)
1235 if (geometryBoneMappings_[i].Size())
1236 allEmpty = false;
1237
1238 if (allEmpty)
1239 return;
1240
1241 // Reserve space for per-geometry skinning matrices
1242 geometrySkinMatrices_.Resize(geometryBoneMappings_.Size());
1243 for (unsigned i = 0; i < geometryBoneMappings_.Size(); ++i)
1244 geometrySkinMatrices_[i].Resize(geometryBoneMappings_[i].Size());
1245
1246 // Build original-to-skinindex matrix pointer mapping for fast copying
1247 // Note: at this point layout of geometrySkinMatrices_ cannot be modified or pointers become invalid
1248 geometrySkinMatrixPtrs_.Resize(skeleton_.GetNumBones());
1249 for (unsigned i = 0; i < geometryBoneMappings_.Size(); ++i)
1250 {
1251 for (unsigned j = 0; j < geometryBoneMappings_[i].Size(); ++j)
1252 geometrySkinMatrixPtrs_[geometryBoneMappings_[i][j]].Push(&geometrySkinMatrices_[i][j]);
1253 }
1254 }
1255
UpdateAnimation(const FrameInfo & frame)1256 void AnimatedModel::UpdateAnimation(const FrameInfo& frame)
1257 {
1258 // If using animation LOD, accumulate time and see if it is time to update
1259 if (animationLodBias_ > 0.0f && animationLodDistance_ > 0.0f)
1260 {
1261 // Perform the first update always regardless of LOD timer
1262 if (animationLodTimer_ >= 0.0f)
1263 {
1264 animationLodTimer_ += animationLodBias_ * frame.timeStep_ * ANIMATION_LOD_BASESCALE;
1265 if (animationLodTimer_ >= animationLodDistance_)
1266 animationLodTimer_ = fmodf(animationLodTimer_, animationLodDistance_);
1267 else
1268 return;
1269 }
1270 else
1271 animationLodTimer_ = 0.0f;
1272 }
1273
1274 ApplyAnimation();
1275 }
1276
ApplyAnimation()1277 void AnimatedModel::ApplyAnimation()
1278 {
1279 // Make sure animations are in ascending priority order
1280 if (animationOrderDirty_)
1281 {
1282 Sort(animationStates_.Begin(), animationStates_.End(), CompareAnimationOrder);
1283 animationOrderDirty_ = false;
1284 }
1285
1286 // Reset skeleton, apply all animations, calculate bones' bounding box. Make sure this is only done for the master model
1287 // (first AnimatedModel in a node)
1288 if (isMaster_)
1289 {
1290 skeleton_.ResetSilent();
1291 for (Vector<SharedPtr<AnimationState> >::Iterator i = animationStates_.Begin(); i != animationStates_.End(); ++i)
1292 (*i)->Apply();
1293
1294 // Skeleton reset and animations apply the node transforms "silently" to avoid repeated marking dirty. Mark dirty now
1295 node_->MarkDirty();
1296
1297 // Calculate new bone bounding box
1298 UpdateBoneBoundingBox();
1299 }
1300
1301 animationDirty_ = false;
1302 }
1303
UpdateSkinning()1304 void AnimatedModel::UpdateSkinning()
1305 {
1306 // Note: the model's world transform will be baked in the skin matrices
1307 const Vector<Bone>& bones = skeleton_.GetBones();
1308 // Use model's world transform in case a bone is missing
1309 const Matrix3x4& worldTransform = node_->GetWorldTransform();
1310
1311 // Skinning with global matrices only
1312 if (!geometrySkinMatrices_.Size())
1313 {
1314 for (unsigned i = 0; i < bones.Size(); ++i)
1315 {
1316 const Bone& bone = bones[i];
1317 if (bone.node_)
1318 skinMatrices_[i] = bone.node_->GetWorldTransform() * bone.offsetMatrix_;
1319 else
1320 skinMatrices_[i] = worldTransform;
1321 }
1322 }
1323 // Skinning with per-geometry matrices
1324 else
1325 {
1326 for (unsigned i = 0; i < bones.Size(); ++i)
1327 {
1328 const Bone& bone = bones[i];
1329 if (bone.node_)
1330 skinMatrices_[i] = bone.node_->GetWorldTransform() * bone.offsetMatrix_;
1331 else
1332 skinMatrices_[i] = worldTransform;
1333
1334 // Copy the skin matrix to per-geometry matrices as needed
1335 for (unsigned j = 0; j < geometrySkinMatrixPtrs_[i].Size(); ++j)
1336 *geometrySkinMatrixPtrs_[i][j] = skinMatrices_[i];
1337 }
1338 }
1339
1340 skinningDirty_ = false;
1341 }
1342
UpdateMorphs()1343 void AnimatedModel::UpdateMorphs()
1344 {
1345 Graphics* graphics = GetSubsystem<Graphics>();
1346 if (!graphics)
1347 return;
1348
1349 if (morphs_.Size())
1350 {
1351 // Reset the morph data range from all morphable vertex buffers, then apply morphs
1352 for (unsigned i = 0; i < morphVertexBuffers_.Size(); ++i)
1353 {
1354 VertexBuffer* buffer = morphVertexBuffers_[i];
1355 if (buffer)
1356 {
1357 VertexBuffer* originalBuffer = model_->GetVertexBuffers()[i];
1358 unsigned morphStart = model_->GetMorphRangeStart(i);
1359 unsigned morphCount = model_->GetMorphRangeCount(i);
1360
1361 void* dest = buffer->Lock(morphStart, morphCount);
1362 if (dest)
1363 {
1364 // Reset morph range by copying data from the original vertex buffer
1365 CopyMorphVertices(dest, originalBuffer->GetShadowData() + morphStart * originalBuffer->GetVertexSize(),
1366 morphCount, buffer, originalBuffer);
1367
1368 for (unsigned j = 0; j < morphs_.Size(); ++j)
1369 {
1370 if (morphs_[j].weight_ != 0.0f)
1371 {
1372 HashMap<unsigned, VertexBufferMorph>::Iterator k = morphs_[j].buffers_.Find(i);
1373 if (k != morphs_[j].buffers_.End())
1374 ApplyMorph(buffer, dest, morphStart, k->second_, morphs_[j].weight_);
1375 }
1376 }
1377
1378 buffer->Unlock();
1379 }
1380 }
1381 }
1382 }
1383
1384 morphsDirty_ = false;
1385 }
1386
ApplyMorph(VertexBuffer * buffer,void * destVertexData,unsigned morphRangeStart,const VertexBufferMorph & morph,float weight)1387 void AnimatedModel::ApplyMorph(VertexBuffer* buffer, void* destVertexData, unsigned morphRangeStart, const VertexBufferMorph& morph,
1388 float weight)
1389 {
1390 unsigned elementMask = morph.elementMask_ & buffer->GetElementMask();
1391 unsigned vertexCount = morph.vertexCount_;
1392 unsigned normalOffset = buffer->GetElementOffset(SEM_NORMAL);
1393 unsigned tangentOffset = buffer->GetElementOffset(SEM_TANGENT);
1394 unsigned vertexSize = buffer->GetVertexSize();
1395
1396 unsigned char* srcData = morph.morphData_;
1397 unsigned char* destData = (unsigned char*)destVertexData;
1398
1399 while (vertexCount--)
1400 {
1401 unsigned vertexIndex = *((unsigned*)srcData) - morphRangeStart;
1402 srcData += sizeof(unsigned);
1403
1404 if (elementMask & MASK_POSITION)
1405 {
1406 float* dest = (float*)(destData + vertexIndex * vertexSize);
1407 float* src = (float*)srcData;
1408 dest[0] += src[0] * weight;
1409 dest[1] += src[1] * weight;
1410 dest[2] += src[2] * weight;
1411 srcData += 3 * sizeof(float);
1412 }
1413 if (elementMask & MASK_NORMAL)
1414 {
1415 float* dest = (float*)(destData + vertexIndex * vertexSize + normalOffset);
1416 float* src = (float*)srcData;
1417 dest[0] += src[0] * weight;
1418 dest[1] += src[1] * weight;
1419 dest[2] += src[2] * weight;
1420 srcData += 3 * sizeof(float);
1421 }
1422 if (elementMask & MASK_TANGENT)
1423 {
1424 float* dest = (float*)(destData + vertexIndex * vertexSize + tangentOffset);
1425 float* src = (float*)srcData;
1426 dest[0] += src[0] * weight;
1427 dest[1] += src[1] * weight;
1428 dest[2] += src[2] * weight;
1429 srcData += 3 * sizeof(float);
1430 }
1431 }
1432 }
1433
HandleModelReloadFinished(StringHash eventType,VariantMap & eventData)1434 void AnimatedModel::HandleModelReloadFinished(StringHash eventType, VariantMap& eventData)
1435 {
1436 Model* currentModel = model_;
1437 model_.Reset(); // Set null to allow to be re-set
1438 SetModel(currentModel);
1439 }
1440
1441 }
1442