void AnimatedModel::AssignBoneNodes() { assignBonesPending_ = false; if (!node_) return; // Find the bone nodes from the node hierarchy and add listeners Vector<Bone>& bones = skeleton_.GetModifiableBones(); bool boneFound = false; for (Vector<Bone>::Iterator i = bones.Begin(); i != bones.End(); ++i) { Node* boneNode = node_->GetChild(i->name_, true); if (boneNode) { boneFound = true; boneNode->AddListener(this); } i->node_ = boneNode; } // If no bones found, this may be a prefab where the bone information was left out. // In that case reassign the skeleton now if possible if (!boneFound && model_) SetSkeleton(model_->GetSkeleton(), true); // Re-assign the same start bone to animations to get the proper bone node this time for (Vector<SharedPtr<AnimationState> >::Iterator i = animationStates_.Begin(); i != animationStates_.End(); ++i) { AnimationState* state = *i; state->SetStartBone(state->GetStartBone()); } }
void DecalSet::AssignBoneNodes() { assignBonesPending_ = false; if (!node_) return; // Find the bone nodes from the node hierarchy and add listeners for (Vector<Bone>::Iterator i = bones_.Begin(); i != bones_.End(); ++i) { Node* boneNode = node_->GetChild(i->name_, true); if (boneNode) boneNode->AddListener(this); i->node_ = boneNode; } }
void SplinePath::ApplyAttributes() { if (!dirty_) return; // Remove all old instance nodes before searching for new. Can not call RemoveAllInstances() as that would modify // the ID list on its own for (unsigned i = 0; i < controlPoints_.Size(); ++i) { Node* node = controlPoints_[i]; if (node) node->RemoveListener(this); } controlPoints_.Clear(); spline_.Clear(); Scene* scene = GetScene(); if (scene) { // The first index stores the number of IDs redundantly. This is for editing for (unsigned i = 1; i < controlPointIdsAttr_.Size(); ++i) { Node* node = scene->GetNode(controlPointIdsAttr_[i].GetUInt()); if (node) { WeakPtr<Node> controlPoint(node); node->AddListener(this); controlPoints_.Push(controlPoint); spline_.AddKnot(node->GetWorldPosition()); } } Node* node = scene->GetNode(controlledIdAttr_); if (node) { WeakPtr<Node> controlled(node); controlledNode_ = controlled; } } CalculateLength(); dirty_ = false; }
void StaticModelGroup::ApplyAttributes() { if (!nodeIDsDirty_) return; // Remove all old instance nodes before searching for new. Can not call RemoveAllInstances() as that would modify // the ID list on its own for (unsigned i = 0; i < instanceNodes_.Size(); ++i) { Node* node = instanceNodes_[i]; if (node) node->RemoveListener(this); } instanceNodes_.Clear(); Scene* scene = GetScene(); if (scene) { // The first index stores the number of IDs redundantly. This is for editing for (unsigned i = 1; i < nodeIDsAttr_.Size(); ++i) { Node* node = scene->GetNode(nodeIDsAttr_[i].GetUInt()); if (node) { WeakPtr<Node> instanceWeak(node); node->AddListener(this); instanceNodes_.Push(instanceWeak); } } } worldTransforms_.Resize(instanceNodes_.Size()); nodeIDsDirty_ = false; OnMarkedDirty(GetNode()); }
void StaticModelGroup::ApplyAttributes() { if (!nodesDirty_) return; // Remove all old instance nodes before searching for new for (unsigned i = 0; i < instanceNodes_.Size(); ++i) { Node* node = instanceNodes_[i]; if (node) node->RemoveListener(this); } instanceNodes_.Clear(); Scene* scene = GetScene(); if (scene) { // The first index stores the number of IDs redundantly. This is for editing for (unsigned i = 1; i < nodeIDsAttr_.Size(); ++i) { Node* node = scene->GetNode(nodeIDsAttr_[i].GetUInt()); if (node) { WeakPtr<Node> instanceWeak(node); node->AddListener(this); instanceNodes_.Push(instanceWeak); } } } worldTransforms_.Resize(instanceNodes_.Size()); numWorldTransforms_ = 0; // Correct amount will be found during world bounding box update nodesDirty_ = false; OnMarkedDirty(GetNode()); }
void AnimatedModel::SetSkeleton(const Skeleton& skeleton, bool createBones) { if (!node_ && createBones) { URHO3D_LOGERROR("AnimatedModel not attached to a scene node, can not create bone nodes"); return; } if (isMaster_) { // Check if bone structure has stayed compatible (reloading the model.) In that case retain the old bones and animations if (skeleton_.GetNumBones() == skeleton.GetNumBones()) { Vector<Bone>& destBones = skeleton_.GetModifiableBones(); const Vector<Bone>& srcBones = skeleton.GetBones(); bool compatible = true; for (unsigned i = 0; i < destBones.Size(); ++i) { if (destBones[i].node_ && destBones[i].name_ == srcBones[i].name_ && destBones[i].parentIndex_ == srcBones[i].parentIndex_) { // If compatible, just copy the values and retain the old node and animated status Node* boneNode = destBones[i].node_; bool animated = destBones[i].animated_; destBones[i] = srcBones[i]; destBones[i].node_ = boneNode; destBones[i].animated_ = animated; } else { compatible = false; break; } } if (compatible) return; } RemoveAllAnimationStates(); // Detach the rootbone of the previous model if any if (createBones) RemoveRootBone(); skeleton_.Define(skeleton); // Merge bounding boxes from non-master models FinalizeBoneBoundingBoxes(); Vector<Bone>& bones = skeleton_.GetModifiableBones(); // Create scene nodes for the bones if (createBones) { for (Vector<Bone>::Iterator i = bones.Begin(); i != bones.End(); ++i) { // Create bones as local, as they are never to be directly synchronized over the network Node* boneNode = node_->CreateChild(i->name_, LOCAL); boneNode->AddListener(this); boneNode->SetTransform(i->initialPosition_, i->initialRotation_, i->initialScale_); // Copy the model component's temporary status boneNode->SetTemporary(IsTemporary()); i->node_ = boneNode; } for (unsigned i = 0; i < bones.Size(); ++i) { unsigned parentIndex = bones[i].parentIndex_; if (parentIndex != i && parentIndex < bones.Size()) bones[parentIndex].node_->AddChild(bones[i].node_); } } using namespace BoneHierarchyCreated; VariantMap& eventData = GetEventDataMap(); eventData[P_NODE] = node_; node_->SendEvent(E_BONEHIERARCHYCREATED, eventData); } else { // For non-master models: use the bone nodes of the master model skeleton_.Define(skeleton); // Instruct the master model to refresh (merge) its bone bounding boxes auto* master = node_->GetComponent<AnimatedModel>(); if (master && master != this) master->FinalizeBoneBoundingBoxes(); if (createBones) { Vector<Bone>& bones = skeleton_.GetModifiableBones(); for (Vector<Bone>::Iterator i = bones.Begin(); i != bones.End(); ++i) { Node* boneNode = node_->GetChild(i->name_, true); if (boneNode) boneNode->AddListener(this); i->node_ = boneNode; } } } assignBonesPending_ = !createBones; }
void AnimatedModel::SetSkeleton(const Skeleton& skeleton, bool createBones) { if (!node_ && createBones) { LOGERROR("AnimatedModel not attached to a scene node, can not create bone nodes"); return; } if (isMaster_) { // Check if bone structure has stayed compatible (reloading the model.) In that case retain the old bones and animations if (skeleton_.GetNumBones() == skeleton.GetNumBones()) { Vector<Bone>& destBones = skeleton_.GetModifiableBones(); const Vector<Bone>& srcBones = skeleton.GetBones(); bool compatible = true; for (unsigned i = 0; i < destBones.Size(); ++i) { if (destBones[i].node_ && destBones[i].name_ == srcBones[i].name_ && destBones[i].parentIndex_ == srcBones[i].parentIndex_) { // If compatible, just copy the values and retain the old node and animated status Node* boneNode = destBones[i].node_; bool animated = destBones[i].animated_; destBones[i] = srcBones[i]; destBones[i].node_ = boneNode; destBones[i].animated_ = animated; } else { compatible = false; break; } } if (compatible) return; } RemoveAllAnimationStates(); // Detach the rootbone of the previous model if any if (createBones) RemoveRootBone(); skeleton_.Define(skeleton); // Remove collision information from dummy bones that do not affect skinning, to prevent them from being merged // to the bounding box Vector<Bone>& bones = skeleton_.GetModifiableBones(); for (Vector<Bone>::Iterator i = bones.Begin(); i != bones.End(); ++i) { if (i->collisionMask_ & BONECOLLISION_BOX && i->boundingBox_.Size().Length() < M_EPSILON) i->collisionMask_ &= ~BONECOLLISION_BOX; if (i->collisionMask_ & BONECOLLISION_SPHERE && i->radius_ < M_EPSILON) i->collisionMask_ &= ~BONECOLLISION_SPHERE; } // Create scene nodes for the bones if (createBones) { for (Vector<Bone>::Iterator i = bones.Begin(); i != bones.End(); ++i) { // Create bones as local, as they are never to be directly synchronized over the network Node* boneNode = node_->CreateChild(i->name_, LOCAL); boneNode->AddListener(this); boneNode->SetTransform(i->initialPosition_, i->initialRotation_, i->initialScale_); i->node_ = boneNode; } for (unsigned i = 0; i < bones.Size(); ++i) { unsigned parentIndex = bones[i].parentIndex_; if (parentIndex != i && parentIndex < bones.Size()) bones[parentIndex].node_->AddChild(bones[i].node_); } } MarkAnimationDirty(); using namespace BoneHierarchyCreated; VariantMap& eventData = GetEventDataMap(); eventData[P_NODE] = (void*)node_; node_->SendEvent(E_BONEHIERARCHYCREATED, eventData); } else { // For non-master models: use the bone nodes of the master model skeleton_.Define(skeleton); if (createBones) { Vector<Bone>& bones = skeleton_.GetModifiableBones(); for (Vector<Bone>::Iterator i = bones.Begin(); i != bones.End(); ++i) { Node* boneNode = node_->GetChild(i->name_, true); if (boneNode) boneNode->AddListener(this); i->node_ = boneNode; } } } // Reserve space for skinning matrices skinMatrices_.Resize(skeleton_.GetNumBones()); SetGeometryBoneMappings(); assignBonesPending_ = !createBones; }