void RagDoll::Activate() { //turn the whole thing on //pawn_->GetNode()->RemoveComponent<RigidBody>(); //pawn_->GetNode()->RemoveComponent<CollisionShape>(); //pawn_->GetNode()->RemoveComponent(pawn_->GetBody());//remove the main components //pawn_->GetNode()->RemoveComponent(pawn_->GetShape());//remove the main components //if(node_->HasComponent<RigidBody>()) //{ //GetSubsystem<DebugHud>()->SetAppStats("state:", name_ ); node_->RemoveComponent<RigidBody>(); node_->RemoveComponent<CollisionShape>(); //} AnimatedModel* model = node_->GetComponent<AnimatedModel>(); Skeleton& skeleton = model->GetSkeleton(); for (unsigned i = 0; i < skeleton.GetNumBones(); ++i) skeleton.GetBone(i)->animated_ = false; for (unsigned i = 0; i < boneNode_.Size(); ++i) { //URHO3D_LOGINFO(String(i)); RigidBody* rb = boneNode_[i]->GetComponent<RigidBody>(); rb->SetTrigger(false); rb->SetMass(1.0f); } }
const PODVector<unsigned char>& AnimationController::GetNetAnimationsAttr() const { attrBuffer_.Clear(); AnimatedModel* model = GetComponent<AnimatedModel>(); unsigned validAnimations = 0; for (Vector<AnimationControl>::ConstIterator i = animations_.Begin(); i != animations_.End(); ++i) { if (GetAnimationState(i->hash_)) ++validAnimations; } attrBuffer_.WriteVLE(validAnimations); for (Vector<AnimationControl>::ConstIterator i = animations_.Begin(); i != animations_.End(); ++i) { AnimationState* state = GetAnimationState(i->hash_); if (!state) continue; unsigned char ctrl = 0; Bone* startBone = state->GetStartBone(); if (state->IsLooped()) ctrl |= CTRL_LOOPED; if (startBone && model && startBone != model->GetSkeleton().GetRootBone()) ctrl |= CTRL_STARTBONE; if (i->autoFadeTime_ > 0.0f) ctrl |= CTRL_AUTOFADE; if (i->removeOnCompletion_) ctrl |= CTRL_REMOVEONCOMPLETION; if (i->setTimeTtl_ > 0.0f) ctrl |= CTRL_SETTIME; if (i->setWeightTtl_ > 0.0f) ctrl |= CTRL_SETWEIGHT; attrBuffer_.WriteString(i->name_); attrBuffer_.WriteUByte(ctrl); attrBuffer_.WriteUByte(state->GetLayer()); attrBuffer_.WriteShort((short)Clamp(i->speed_ * 2048.0f, -32767.0f, 32767.0f)); attrBuffer_.WriteUByte((unsigned char)(i->targetWeight_ * 255.0f)); attrBuffer_.WriteUByte((unsigned char)Clamp(i->fadeTime_ * 64.0f, 0.0f, 255.0f)); if (ctrl & CTRL_STARTBONE) attrBuffer_.WriteStringHash(startBone->nameHash_); if (ctrl & CTRL_AUTOFADE) attrBuffer_.WriteUByte((unsigned char)Clamp(i->autoFadeTime_ * 64.0f, 0.0f, 255.0f)); if (ctrl & CTRL_SETTIME) { attrBuffer_.WriteUByte(i->setTimeRev_); attrBuffer_.WriteUShort(i->setTime_); } if (ctrl & CTRL_SETWEIGHT) { attrBuffer_.WriteUByte(i->setWeightRev_); attrBuffer_.WriteUByte(i->setWeight_); } } return attrBuffer_.GetBuffer(); }
bool AnimationController::SetStartBone(const String& name, const String& startBoneName) { AnimationState* state = FindAnimationState(name); if (!state) return false; AnimatedModel* model = GetComponent<AnimatedModel>(); Bone* bone = model->GetSkeleton().GetBone(startBoneName); state->SetStartBone(bone); MarkNetworkUpdate(); return true; }
void CharacterDemo::CreateCharacter() { ResourceCache* cache = GetSubsystem<ResourceCache>(); Node* objectNode = scene_->CreateChild("Jack"); objectNode->SetPosition(Vector3(0.0f, 1.0f, 0.0f)); // spin node Node* adjustNode = objectNode->CreateChild("AdjNode"); adjustNode->SetRotation( Quaternion(180, Vector3(0,1,0) ) ); // Create the rendering component + animation controller AnimatedModel* object = adjustNode->CreateComponent<AnimatedModel>(); object->SetModel(cache->GetResource<Model>("Models/Mutant/Mutant.mdl")); object->SetMaterial(cache->GetResource<Material>("Models/Mutant/Materials/mutant_M.xml")); object->SetCastShadows(true); adjustNode->CreateComponent<AnimationController>(); // Set the head bone for manual control object->GetSkeleton().GetBone("Mutant:Head")->animated_ = false; // Create rigidbody, and set non-zero mass so that the body becomes dynamic RigidBody* body = objectNode->CreateComponent<RigidBody>(); body->SetCollisionLayer(1); body->SetMass(1.0f); // Set zero angular factor so that physics doesn't turn the character on its own. // Instead we will control the character yaw manually body->SetAngularFactor(Vector3::ZERO); // Set the rigidbody to signal collision also when in rest, so that we get ground collisions properly body->SetCollisionEventMode(COLLISION_ALWAYS); // Set a capsule shape for collision CollisionShape* shape = objectNode->CreateComponent<CollisionShape>(); shape->SetCapsule(0.7f, 1.8f, Vector3(0.0f, 0.9f, 0.0f)); // Create the character logic component, which takes care of steering the rigidbody // Remember it so that we can set the controls. Use a WeakPtr because the scene hierarchy already owns it // and keeps it alive as long as it's not removed from the hierarchy character_ = objectNode->CreateComponent<Character>(); }
bool DecalSet::GetBones(Drawable* target, unsigned batchIndex, const float* blendWeights, const unsigned char* blendIndices, unsigned char* newBlendIndices) { AnimatedModel* animatedModel = dynamic_cast<AnimatedModel*>(target); if (!animatedModel) return false; // Check whether target is using global or per-geometry skinning const Vector<PODVector<Matrix3x4> >& geometrySkinMatrices = animatedModel->GetGeometrySkinMatrices(); const Vector<PODVector<unsigned> >& geometryBoneMappings = animatedModel->GetGeometryBoneMappings(); for (unsigned i = 0; i < 4; ++i) { if (blendWeights[i] > 0.0f) { Bone* bone = 0; if (geometrySkinMatrices.Empty()) bone = animatedModel->GetSkeleton().GetBone(blendIndices[i]); else if (blendIndices[i] < geometryBoneMappings[batchIndex].Size()) bone = animatedModel->GetSkeleton().GetBone(geometryBoneMappings[batchIndex][blendIndices[i]]); if (!bone) { URHO3D_LOGWARNING("Out of range bone index for skinned decal"); return false; } bool found = false; unsigned index; for (index = 0; index < bones_.Size(); ++index) { if (bones_[index].node_ == bone->node_) { // Check also that the offset matrix matches, in case we for example have a separate attachment AnimatedModel // with a different bind pose if (bones_[index].offsetMatrix_.Equals(bone->offsetMatrix_)) { found = true; break; } } } if (!found) { if (bones_.Size() >= Graphics::GetMaxBones()) { URHO3D_LOGWARNING("Maximum skinned decal bone count reached"); return false; } else { // Copy the bone from the model to the decal index = bones_.Size(); bones_.Resize(bones_.Size() + 1); bones_[index] = *bone; skinMatrices_.Resize(skinMatrices_.Size() + 1); skinningDirty_ = true; // Start listening to bone transform changes to update skinning bone->node_->AddListener(this); } } newBlendIndices[i] = (unsigned char)index; } else newBlendIndices[i] = 0; } // Update amount of shader data in the decal batch UpdateBatch(); return true; }
bool DecalSet::AddDecal(Drawable* target, const Vector3& worldPosition, const Quaternion& worldRotation, float size, float aspectRatio, float depth, const Vector2& topLeftUV, const Vector2& bottomRightUV, float timeToLive, float normalCutoff, unsigned subGeometry) { URHO3D_PROFILE(AddDecal); // Do not add decals in headless mode if (!node_ || !GetSubsystem<Graphics>()) return false; if (!target || !target->GetNode()) { URHO3D_LOGERROR("Null target drawable for decal"); return false; } // Check for animated target and switch into skinned/static mode if necessary AnimatedModel* animatedModel = dynamic_cast<AnimatedModel*>(target); if ((animatedModel && !skinned_) || (!animatedModel && skinned_)) { RemoveAllDecals(); skinned_ = animatedModel != 0; bufferDirty_ = true; } // Center the decal frustum on the world position Vector3 adjustedWorldPosition = worldPosition - 0.5f * depth * (worldRotation * Vector3::FORWARD); /// \todo target transform is not right if adding a decal to StaticModelGroup Matrix3x4 targetTransform = target->GetNode()->GetWorldTransform().Inverse(); // For an animated model, adjust the decal position back to the bind pose // To do this, need to find the bone the decal is colliding with if (animatedModel) { Skeleton& skeleton = animatedModel->GetSkeleton(); unsigned numBones = skeleton.GetNumBones(); Bone* bestBone = 0; float bestSize = 0.0f; for (unsigned i = 0; i < numBones; ++i) { Bone* bone = skeleton.GetBone(i); if (!bone->node_ || !bone->collisionMask_) continue; // Represent the decal as a sphere, try to find the biggest colliding bone Sphere decalSphere (bone->node_->GetWorldTransform().Inverse() * worldPosition, 0.5f * size / bone->node_->GetWorldScale().Length()); if (bone->collisionMask_ & BONECOLLISION_BOX) { float size = bone->boundingBox_.HalfSize().Length(); if (bone->boundingBox_.IsInside(decalSphere) && size > bestSize) { bestBone = bone; bestSize = size; } } else if (bone->collisionMask_ & BONECOLLISION_SPHERE) { Sphere boneSphere(Vector3::ZERO, bone->radius_); float size = bone->radius_; if (boneSphere.IsInside(decalSphere) && size > bestSize) { bestBone = bone; bestSize = size; } } } if (bestBone) targetTransform = (bestBone->node_->GetWorldTransform() * bestBone->offsetMatrix_).Inverse(); } // Build the decal frustum Frustum decalFrustum; Matrix3x4 frustumTransform = targetTransform * Matrix3x4(adjustedWorldPosition, worldRotation, 1.0f); decalFrustum.DefineOrtho(size, aspectRatio, 1.0, 0.0f, depth, frustumTransform); Vector3 decalNormal = (targetTransform * Vector4(worldRotation * Vector3::BACK, 0.0f)).Normalized(); decals_.Resize(decals_.Size() + 1); Decal& newDecal = decals_.Back(); newDecal.timeToLive_ = timeToLive; Vector<PODVector<DecalVertex> > faces; PODVector<DecalVertex> tempFace; unsigned numBatches = target->GetBatches().Size(); // Use either a specified subgeometry in the target, or all if (subGeometry < numBatches) GetFaces(faces, target, subGeometry, decalFrustum, decalNormal, normalCutoff); else { for (unsigned i = 0; i < numBatches; ++i) GetFaces(faces, target, i, decalFrustum, decalNormal, normalCutoff); } // Clip the acquired faces against all frustum planes for (unsigned i = 0; i < NUM_FRUSTUM_PLANES; ++i) { for (unsigned j = 0; j < faces.Size(); ++j) { PODVector<DecalVertex>& face = faces[j]; if (face.Empty()) continue; ClipPolygon(tempFace, face, decalFrustum.planes_[i], skinned_); face = tempFace; } } // Now triangulate the resulting faces into decal vertices for (unsigned i = 0; i < faces.Size(); ++i) { PODVector<DecalVertex>& face = faces[i]; if (face.Size() < 3) continue; for (unsigned j = 2; j < face.Size(); ++j) { newDecal.AddVertex(face[0]); newDecal.AddVertex(face[j - 1]); newDecal.AddVertex(face[j]); } } // Check if resulted in no triangles if (newDecal.vertices_.Empty()) { decals_.Pop(); return true; } if (newDecal.vertices_.Size() > maxVertices_) { URHO3D_LOGWARNING("Can not add decal, vertex count " + String(newDecal.vertices_.Size()) + " exceeds maximum " + String(maxVertices_)); decals_.Pop(); return false; } if (newDecal.indices_.Size() > maxIndices_) { URHO3D_LOGWARNING("Can not add decal, index count " + String(newDecal.indices_.Size()) + " exceeds maximum " + String(maxIndices_)); decals_.Pop(); return false; } // Calculate UVs Matrix4 projection(Matrix4::ZERO); projection.m11_ = (1.0f / (size * 0.5f)); projection.m00_ = projection.m11_ / aspectRatio; projection.m22_ = 1.0f / depth; projection.m33_ = 1.0f; CalculateUVs(newDecal, frustumTransform.Inverse(), projection, topLeftUV, bottomRightUV); // Transform vertices to this node's local space and generate tangents Matrix3x4 decalTransform = node_->GetWorldTransform().Inverse() * target->GetNode()->GetWorldTransform(); TransformVertices(newDecal, skinned_ ? Matrix3x4::IDENTITY : decalTransform); GenerateTangents(&newDecal.vertices_[0], sizeof(DecalVertex), &newDecal.indices_[0], sizeof(unsigned short), 0, newDecal.indices_.Size(), offsetof(DecalVertex, normal_), offsetof(DecalVertex, texCoord_), offsetof(DecalVertex, tangent_)); newDecal.CalculateBoundingBox(); numVertices_ += newDecal.vertices_.Size(); numIndices_ += newDecal.indices_.Size(); // Remove oldest decals if total vertices exceeded while (decals_.Size() && (numVertices_ > maxVertices_ || numIndices_ > maxIndices_)) RemoveDecals(1); URHO3D_LOGDEBUG("Added decal with " + String(newDecal.vertices_.Size()) + " vertices"); // If new decal is time limited, subscribe to scene post-update if (newDecal.timeToLive_ > 0.0f && !subscribed_) UpdateEventSubscription(false); MarkDecalsDirty(); return true; }
void CreateRagdoll::HandleNodeCollision(StringHash eventType, VariantMap& eventData) { using namespace NodeCollision; // Get the other colliding body, make sure it is moving (has nonzero mass) RigidBody* otherBody = static_cast<RigidBody*>(eventData[P_OTHERBODY].GetPtr()); if (otherBody->GetMass() > 0.0f) { // We do not need the physics components in the AnimatedModel's root scene node anymore node_->RemoveComponent<RigidBody>(); node_->RemoveComponent<CollisionShape>(); // Create RigidBody & CollisionShape components to bones CreateRagdollBone("Bip01_Pelvis", SHAPE_BOX, Vector3(0.3f, 0.2f, 0.25f), Vector3(0.0f, 0.0f, 0.0f), Quaternion(0.0f, 0.0f, 0.0f)); CreateRagdollBone("Bip01_Spine1", SHAPE_BOX, Vector3(0.35f, 0.2f, 0.3f), Vector3(0.15f, 0.0f, 0.0f), Quaternion(0.0f, 0.0f, 0.0f)); CreateRagdollBone("Bip01_L_Thigh", SHAPE_CAPSULE, Vector3(0.175f, 0.45f, 0.175f), Vector3(0.25f, 0.0f, 0.0f), Quaternion(0.0f, 0.0f, 90.0f)); CreateRagdollBone("Bip01_R_Thigh", SHAPE_CAPSULE, Vector3(0.175f, 0.45f, 0.175f), Vector3(0.25f, 0.0f, 0.0f), Quaternion(0.0f, 0.0f, 90.0f)); CreateRagdollBone("Bip01_L_Calf", SHAPE_CAPSULE, Vector3(0.15f, 0.55f, 0.15f), Vector3(0.25f, 0.0f, 0.0f), Quaternion(0.0f, 0.0f, 90.0f)); CreateRagdollBone("Bip01_R_Calf", SHAPE_CAPSULE, Vector3(0.15f, 0.55f, 0.15f), Vector3(0.25f, 0.0f, 0.0f), Quaternion(0.0f, 0.0f, 90.0f)); CreateRagdollBone("Bip01_Head", SHAPE_BOX, Vector3(0.2f, 0.2f, 0.2f), Vector3(0.1f, 0.0f, 0.0f), Quaternion(0.0f, 0.0f, 0.0f)); CreateRagdollBone("Bip01_L_UpperArm", SHAPE_CAPSULE, Vector3(0.15f, 0.35f, 0.15f), Vector3(0.1f, 0.0f, 0.0f), Quaternion(0.0f, 0.0f, 90.0f)); CreateRagdollBone("Bip01_R_UpperArm", SHAPE_CAPSULE, Vector3(0.15f, 0.35f, 0.15f), Vector3(0.1f, 0.0f, 0.0f), Quaternion(0.0f, 0.0f, 90.0f)); CreateRagdollBone("Bip01_L_Forearm", SHAPE_CAPSULE, Vector3(0.125f, 0.4f, 0.125f), Vector3(0.2f, 0.0f, 0.0f), Quaternion(0.0f, 0.0f, 90.0f)); CreateRagdollBone("Bip01_R_Forearm", SHAPE_CAPSULE, Vector3(0.125f, 0.4f, 0.125f), Vector3(0.2f, 0.0f, 0.0f), Quaternion(0.0f, 0.0f, 90.0f)); // Create Constraints between bones CreateRagdollConstraint("Bip01_L_Thigh", "Bip01_Pelvis", CONSTRAINT_CONETWIST, Vector3::BACK, Vector3::FORWARD, Vector2(45.0f, 45.0f), Vector2::ZERO); CreateRagdollConstraint("Bip01_R_Thigh", "Bip01_Pelvis", CONSTRAINT_CONETWIST, Vector3::BACK, Vector3::FORWARD, Vector2(45.0f, 45.0f), Vector2::ZERO); CreateRagdollConstraint("Bip01_L_Calf", "Bip01_L_Thigh", CONSTRAINT_HINGE, Vector3::BACK, Vector3::BACK, Vector2(90.0f, 0.0f), Vector2::ZERO); CreateRagdollConstraint("Bip01_R_Calf", "Bip01_R_Thigh", CONSTRAINT_HINGE, Vector3::BACK, Vector3::BACK, Vector2(90.0f, 0.0f), Vector2::ZERO); CreateRagdollConstraint("Bip01_Spine1", "Bip01_Pelvis", CONSTRAINT_HINGE, Vector3::FORWARD, Vector3::FORWARD, Vector2(45.0f, 0.0f), Vector2(-10.0f, 0.0f)); CreateRagdollConstraint("Bip01_Head", "Bip01_Spine1", CONSTRAINT_CONETWIST, Vector3::LEFT, Vector3::LEFT, Vector2(0.0f, 30.0f), Vector2::ZERO); CreateRagdollConstraint("Bip01_L_UpperArm", "Bip01_Spine1", CONSTRAINT_CONETWIST, Vector3::DOWN, Vector3::UP, Vector2(45.0f, 45.0f), Vector2::ZERO, false); CreateRagdollConstraint("Bip01_R_UpperArm", "Bip01_Spine1", CONSTRAINT_CONETWIST, Vector3::DOWN, Vector3::UP, Vector2(45.0f, 45.0f), Vector2::ZERO, false); CreateRagdollConstraint("Bip01_L_Forearm", "Bip01_L_UpperArm", CONSTRAINT_HINGE, Vector3::BACK, Vector3::BACK, Vector2(90.0f, 0.0f), Vector2::ZERO); CreateRagdollConstraint("Bip01_R_Forearm", "Bip01_R_UpperArm", CONSTRAINT_HINGE, Vector3::BACK, Vector3::BACK, Vector2(90.0f, 0.0f), Vector2::ZERO); // Disable keyframe animation from all bones so that they will not interfere with the ragdoll AnimatedModel* model = GetComponent<AnimatedModel>(); Skeleton& skeleton = model->GetSkeleton(); for (unsigned i = 0; i < skeleton.GetNumBones(); ++i) skeleton.GetBone(i)->animated_ = false; // Finally remove self from the scene node. Note that this must be the last operation performed in the function Remove(); } }
void AnimationController::SetNetAnimationsAttr(const PODVector<unsigned char>& value) { MemoryBuffer buf(value); AnimatedModel* model = GetComponent<AnimatedModel>(); // Check which animations we need to remove HashSet<StringHash> processedAnimations; unsigned numAnimations = buf.ReadVLE(); while (numAnimations--) { String animName = buf.ReadString(); StringHash animHash(animName); processedAnimations.Insert(animHash); // Check if the animation state exists. If not, add new AnimationState* state = GetAnimationState(animHash); if (!state) { Animation* newAnimation = GetSubsystem<ResourceCache>()->GetResource<Animation>(animName); state = AddAnimationState(newAnimation); if (!state) { LOGERROR("Animation update applying aborted due to unknown animation"); return; } } // Check if the internal control structure exists. If not, add new unsigned index; for (index = 0; index < animations_.Size(); ++index) { if (animations_[index].hash_ == animHash) break; } if (index == animations_.Size()) { AnimationControl newControl; newControl.name_ = animName; newControl.hash_ = animHash; animations_.Push(newControl); } unsigned char ctrl = buf.ReadUByte(); state->SetLayer(buf.ReadUByte()); state->SetLooped((ctrl & CTRL_LOOPED) != 0); animations_[index].speed_ = (float)buf.ReadShort() / 2048.0f; // 11 bits of decimal precision, max. 16x playback speed animations_[index].targetWeight_ = (float)buf.ReadUByte() / 255.0f; // 8 bits of decimal precision animations_[index].fadeTime_ = (float)buf.ReadUByte() / 64.0f; // 6 bits of decimal precision, max. 4 seconds fade if (ctrl & CTRL_STARTBONE) { StringHash boneHash = buf.ReadStringHash(); if (model) state->SetStartBone(model->GetSkeleton().GetBone(boneHash)); } else state->SetStartBone(0); if (ctrl & CTRL_AUTOFADE) animations_[index].autoFadeTime_ = (float)buf.ReadUByte() / 64.0f; // 6 bits of decimal precision, max. 4 seconds fade else animations_[index].autoFadeTime_ = 0.0f; animations_[index].removeOnCompletion_ = (ctrl & CTRL_REMOVEONCOMPLETION) != 0; if (ctrl & CTRL_SETTIME) { unsigned char setTimeRev = buf.ReadUByte(); unsigned short setTime = buf.ReadUShort(); // Apply set time command only if revision differs if (setTimeRev != animations_[index].setTimeRev_) { state->SetTime(((float)setTime / 65535.0f) * state->GetLength()); animations_[index].setTimeRev_ = setTimeRev; } } if (ctrl & CTRL_SETWEIGHT) { unsigned char setWeightRev = buf.ReadUByte(); unsigned char setWeight = buf.ReadUByte(); // Apply set weight command only if revision differs if (setWeightRev != animations_[index].setWeightRev_) { state->SetWeight((float)setWeight / 255.0f); animations_[index].setWeightRev_ = setWeightRev; } } } // Set any extra animations to fade out for (Vector<AnimationControl>::Iterator i = animations_.Begin(); i != animations_.End(); ++i) { if (!processedAnimations.Contains(i->hash_)) { i->targetWeight_ = 0.0f; i->fadeTime_ = EXTRA_ANIM_FADEOUT_TIME; } } }