コード例 #1
0
Node* GameApplication::add_object(Node* pParentNode, const String& nodeName,enObjectType type,float x,float y,float z,const char* modelUrl,const char* material)
{
	ResourceCache* cache = GetSubsystem<ResourceCache>();

	Node* pNode = pParentNode->CreateChild(nodeName);
	pNode->SetPosition(Vector3(x, y, z));

	if(type == enObjectType_StaticModel)
	{
		StaticModel* pModel = pNode->CreateComponent<StaticModel>();
		pModel->SetModel(cache->GetResource<Model>(modelUrl));
		if(material != NULL)
			pModel->SetMaterial(0,cache->GetResource<Material>(material));

		pModel->SetCastShadows(true);
	}
	else
	{
		AnimatedModel* pAniModel = pNode->CreateComponent<AnimatedModel>();
		pAniModel->SetModel(cache->GetResource<Model>(modelUrl));
		if(material != NULL)
			pAniModel->SetMaterial(0,cache->GetResource<Material>(material));

		pAniModel->SetCastShadows(true);
	}

	return pNode;
}
コード例 #2
0
bool AnimationController::FadeOthers(const String& name, float targetWeight, float fadeTime)
{
    unsigned index;
    AnimationState* state;
    FindAnimation(name, index, state);
    if (index == M_MAX_UNSIGNED || !state)
        return false;
    
    AnimatedModel* model = GetComponent<AnimatedModel>();
    unsigned char layer = state->GetLayer();
    
    bool needUpdate = false;
    for (unsigned i = 0; i < animations_.Size(); ++i)
    {
        if (i != index)
        {
            AnimationControl& control = animations_[i];
            AnimationState* otherState = model->GetAnimationState(control.hash_);
            if (otherState && otherState->GetLayer() == layer)
            {
                control.targetWeight_ = Clamp(targetWeight, 0.0f, 1.0f);
                control.fadeTime_ = fadeTime;
                needUpdate = true;
            }
        }
    }
    
    if (needUpdate)
        MarkNetworkUpdate();
    return true;
}
コード例 #3
0
ファイル: RagDoll.cpp プロジェクト: ghidra/urho_framework
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);
   	}
}
コード例 #4
0
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();
}
コード例 #5
0
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;
}
コード例 #6
0
void StaticModel::SetModel(Model* model)
{
    if (model == model_)
        return;

    // If script erroneously calls StaticModel::SetModel on an AnimatedModel, warn and redirect
    if (GetType() == AnimatedModel::GetTypeStatic())
    {
        ATOMIC_LOGWARNING("StaticModel::SetModel() called on AnimatedModel. Redirecting to AnimatedModel::SetModel()");
        AnimatedModel* animatedModel = static_cast<AnimatedModel*>(this);
        animatedModel->SetModel(model);
        return;
    }

    // Unsubscribe from the reload event of previous model (if any), then subscribe to the new
    if (model_)
        UnsubscribeFromEvent(model_, E_RELOADFINISHED);

    model_ = model;

    if (model)
    {
        SubscribeToEvent(model, E_RELOADFINISHED, ATOMIC_HANDLER(StaticModel, HandleModelReloadFinished));

        // Copy the subgeometry & LOD level structure
        SetNumGeometries(model->GetNumGeometries());
        const Vector<Vector<SharedPtr<Geometry> > >& geometries = model->GetGeometries();
        const PODVector<Vector3>& geometryCenters = model->GetGeometryCenters();
        const Matrix3x4* worldTransform = node_ ? &node_->GetWorldTransform() : (const Matrix3x4*)0;
        for (unsigned i = 0; i < geometries.Size(); ++i)
        {
            batches_[i].worldTransform_ = worldTransform;
            geometries_[i] = geometries[i];
            geometryData_[i].center_ = geometryCenters[i];

            // ATOMIC BEGIN
            geometryData_[i].enabled_ = true;
            geometryData_[i].batchGeometry_ = 0;
            // ATOMIC END

        }

        SetBoundingBox(model->GetBoundingBox());
        ResetLodLevels();
    }
    else
    {
        SetNumGeometries(0);
        SetBoundingBox(BoundingBox());
    }

    MarkNetworkUpdate();
}
コード例 #7
0
bool ModelImporter::ImportAnimation(const String& filename, const String& name, float startTime, float endTime)
{
    SharedPtr<OpenAssetImporter> importer(new OpenAssetImporter(context_));

    //importer->SetVerboseLog(true);

    importer->SetScale(scale_);
    importer->SetExportAnimations(true);
    importer->SetStartTime(startTime);
    importer->SetEndTime(endTime);

    if (importer->Load(filename))
    {
        importer->ExportModel(asset_->GetCachePath(), name, true);

        const Vector<OpenAssetImporter::AnimationInfo>& infos = importer->GetAnimationInfos();

        for (unsigned i = 0; i < infos.Size(); i++)
        {
            const OpenAssetImporter::AnimationInfo& info = infos.At(i);

            String pathName, fileName, extension;

            SplitPath(info.cacheFilename_, pathName, fileName, extension);

            ResourceCache* cache = GetSubsystem<ResourceCache>();

            AnimatedModel* animatedModel = importNode_->GetComponent<AnimatedModel>();

            if (animatedModel)
            {
                Model* model = animatedModel->GetModel();

                if (model)
                {
                    SharedPtr<Animation> animation = cache->GetTempResource<Animation>(fileName + extension);
                    if (animation)
                        model->AddAnimationResource(animation);
                }

            }

            LOGINFOF("Import Info: %s : %s", info.name_.CString(), fileName.CString());
        }

        return true;
    }

    return false;

}
コード例 #8
0
AnimationState* AnimationController::AddAnimationState(Animation* animation)
{
    if (!animation)
        return 0;

    // Model mode
    AnimatedModel* model = GetComponent<AnimatedModel>();
    if (model)
        return model->AddAnimationState(animation);

    // Node hierarchy mode
    SharedPtr<AnimationState> newState(new AnimationState(node_, animation));
    nodeAnimationStates_.Push(newState);
    return newState;
}
コード例 #9
0
AnimationState* AnimationController::GetAnimationState(StringHash nameHash) const
{
    // Model mode
    AnimatedModel* model = GetComponent<AnimatedModel>();
    if (model)
        return model->GetAnimationState(nameHash);

    // Node hierarchy mode
    for (Vector<SharedPtr<AnimationState> >::ConstIterator i = nodeAnimationStates_.Begin(); i != nodeAnimationStates_.End(); ++i)
    {
        Animation* animation = (*i)->GetAnimation();
        if (animation->GetNameHash() == nameHash || animation->GetAnimationNameHash() == nameHash)
            return *i;
    }

    return 0;
}
コード例 #10
0
ファイル: Mover.cpp プロジェクト: LumaDigital/AtomicExamples
void Mover::Update(float timeStep)
{
    node_->Translate(Vector3::FORWARD * moveSpeed_ * timeStep);

    // If in risk of going outside the plane, rotate the model right
    Vector3 pos = node_->GetPosition();
    if (pos.x_ < bounds_.min_.x_ || pos.x_ > bounds_.max_.x_ || pos.z_ < bounds_.min_.z_ || pos.z_ > bounds_.max_.z_)
        node_->Yaw(rotationSpeed_ * timeStep);

    // Get the model's first (only) animation state and advance its time. Note the convenience accessor to other components
    // in the same scene node
    AnimatedModel* model = GetComponent<AnimatedModel>();
    if (model->GetNumAnimationStates())
    {
        AnimationState* state = model->GetAnimationStates()[0];
        state->AddTime(timeStep);
    }
}
コード例 #11
0
ファイル: CharacterDemo.cpp プロジェクト: evolarium/Urho3D
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>();
}
コード例 #12
0
void AnimationController::StopLayer(unsigned char layer, float fadeOutTime)
{
    AnimatedModel* model = GetComponent<AnimatedModel>();
    if (!model)
        return;
    
    bool needUpdate = false;
    for (Vector<AnimationControl>::Iterator i = animations_.Begin(); i != animations_.End(); ++i)
    {
        AnimationState* state = model->GetAnimationState(i->hash_);
        if (state && state->GetLayer() == layer)
        {
            i->targetWeight_ = 0.0f;
            i->fadeTime_ = fadeOutTime;
            needUpdate = true;
        }
    }
    
    if (needUpdate)
        MarkNetworkUpdate();
}
コード例 #13
0
ファイル: Mover.cpp プロジェクト: PeteX/Urho3D
void Mover::HandleSceneUpdate(StringHash eventType, VariantMap& eventData)
{
    // Get the timestep from the update event
    using namespace SceneUpdate;
    float timeStep = eventData[P_TIMESTEP].GetFloat();
    
    node_->TranslateRelative(Vector3::FORWARD * moveSpeed_ * timeStep);
    
    // If in risk of going outside the plane, rotate the model right
    Vector3 pos = node_->GetPosition();
    if (pos.x_ < bounds_.min_.x_ || pos.x_ > bounds_.max_.x_ || pos.z_ < bounds_.min_.z_ || pos.z_ > bounds_.max_.z_)
        node_->Yaw(rotationSpeed_ * timeStep);
    
    // Get the model's first (only) animation state and advance its time. Note the convenience accessor to other components
    // in the same scene node
    AnimatedModel* model = GetComponent<AnimatedModel>();
    if (model->GetNumAnimationStates())
    {
        AnimationState* state = model->GetAnimationStates()[0];
        state->AddTime(timeStep);
    }
}
コード例 #14
0
void AnimationController::RemoveAnimationState(AnimationState* state)
{
    if (!state)
        return;

    // Model mode
    AnimatedModel* model = GetComponent<AnimatedModel>();
    if (model)
    {
        model->RemoveAnimationState(state);
        return;
    }

    // Node hierarchy mode
    for (Vector<SharedPtr<AnimationState> >::Iterator i = nodeAnimationStates_.Begin(); i != nodeAnimationStates_.End(); ++i)
    {
        if ((*i) == state)
        {
            nodeAnimationStates_.Erase(i);
            return;
        }
    }
}
コード例 #15
0
void AnimationController::FindAnimation(const String& name, unsigned& index, AnimationState*& state) const
{
    AnimatedModel* model = GetComponent<AnimatedModel>();
    StringHash nameHash(name);
    
    // Find the AnimationState
    state = model ? model->GetAnimationState(nameHash) : 0;
    if (state)
    {
        // Either a resource name or animation name may be specified. We store resource names, so correct the hash if necessary
        nameHash = state->GetAnimation()->GetNameHash();
    }
    
    // Find the internal control structure
    index = M_MAX_UNSIGNED;
    for (unsigned i = 0; i < animations_.Size(); ++i)
    {
        if (animations_[i].hash_ == nameHash)
        {
            index = i;
            break;
        }
    }
}
コード例 #16
0
bool AnimationController::Play(const String& name, unsigned char layer, bool looped, float fadeInTime)
{
    AnimatedModel* model = GetComponent<AnimatedModel>();
    if (!model)
        return false;
    
    // Check if already exists
    unsigned index;
    AnimationState* state;
    FindAnimation(name, index, state);
    
    if (!state)
    {
        Animation* newAnimation = GetSubsystem<ResourceCache>()->GetResource<Animation>(name);
        state = model->AddAnimationState(newAnimation);
        if (!state)
            return false;
    }
    
    if (index == M_MAX_UNSIGNED)
    {
        AnimationControl newControl;
        Animation* animation = state->GetAnimation();
        newControl.hash_ = animation->GetNameHash();
        animations_.Push(newControl);
        index = animations_.Size() - 1;
    }
    
    state->SetLayer(layer);
    state->SetLooped(looped);
    animations_[index].targetWeight_ = 1.0f;
    animations_[index].fadeTime_ = fadeInTime;
    
    MarkNetworkUpdate();
    return true;
}
コード例 #17
0
bool ModelImporter::Import()
{

    String ext = asset_->GetExtension();
    String modelAssetFilename = asset_->GetPath();

    importNode_ = new Node(context_);

    if (ext == ".mdl")
    {
        FileSystem* fs = GetSubsystem<FileSystem>();
        ResourceCache* cache = GetSubsystem<ResourceCache>();

        // mdl files are native file format that doesn't need to be converted
        // doesn't allow scale, animations legacy primarily for ToonTown

        if (!fs->Copy(asset_->GetPath(), asset_->GetCachePath() + ".mdl"))
        {
            importNode_= 0;
            return false;
        }

        Model* mdl = cache->GetResource<Model>( asset_->GetCachePath() + ".mdl");

        if (!mdl)
        {
            importNode_= 0;
            return false;
        }

        // Force a reload, though file watchers will catch this delayed and load again
        cache->ReloadResource(mdl);

        importNode_->CreateComponent<StaticModel>()->SetModel(mdl);
    }
    else
    {
        // skip external animations, they will be brought in when importing their
        // corresponding model

        if (!modelAssetFilename.Contains("@"))
        {
            ImportModel();

            if (importAnimations_)
            {
                ImportAnimations();
            }

            AnimatedModel* animatedModel = importNode_->GetComponent<AnimatedModel>();
            if (animatedModel)
            {
                Model* model = animatedModel->GetModel();
                if (model && model->GetAnimationCount())
                {
                    // resave with animation info

                    File mdlFile(context_);
                    if (!mdlFile.Open(asset_->GetCachePath() + ".mdl", FILE_WRITE))
                    {
                        ErrorExit("Could not open output file " + asset_->GetCachePath() + ".mdl");
                        return false;
                    }

                    model->Save(mdlFile);
                }
            }
        }
    }


    File outFile(context_);

    if (!outFile.Open(asset_->GetCachePath(), FILE_WRITE))
        ErrorExit("Could not open output file " + asset_->GetCachePath());

    importNode_->SaveXML(outFile);

    importNode_ = 0;

    return true;
}
コード例 #18
0
ファイル: DecalSet.cpp プロジェクト: TheComet93/Urho3D
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;
}
コード例 #19
0
ファイル: DecalSet.cpp プロジェクト: TheComet93/Urho3D
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;
}
コード例 #20
0
void Urho3DTemplate::CreateScene()
{
    ResourceCache* cache = GetSubsystem<ResourceCache>();

    scene_ = new Scene(context_);

    //Create octree, use default volume (-1000, -1000, -1000) to (1000,1000,1000)
    //Also create a DebugRenderer component so that we can draw debug geometry
    scene_->CreateComponent<Octree>();
    scene_->CreateComponent<DebugRenderer>();

    //Create scene node & StaticModel component for showing a static plane
    Node* planeNode = scene_->CreateChild("Plane");
    planeNode->SetScale(Vector3(100.0f, 1.0f, 100.0f));
    StaticModel* planeObject = planeNode->CreateComponent<StaticModel>();
    planeObject->SetModel(cache->GetResource<Model>("Models/Plane.mdl"));
    planeObject->SetMaterial(cache->GetResource<Material>("Materials/StoneTiled.xml"));

    //Create a Zone component for ambient lighting & fog control
    Node* zoneNode = scene_->CreateChild("Zone");
    Zone* zone = zoneNode->CreateComponent<Zone>();
    zone->SetBoundingBox(BoundingBox(-1000.0f, 1000.0f));
    zone->SetAmbientColor(Color(0.15f, 0.15f, 0.15f));
    zone->SetFogColor(Color(0.5f, 0.5f, 0.7f));
    zone->SetFogStart(100.0f);
    zone->SetFogEnd(300.0f);

    //Create a directional light to the world. Enable cascaded shadows on it
    Node* lightNode = scene_->CreateChild("DirectionalLight");
    lightNode->SetDirection(Vector3(0.6f, -1.0f, 0.8f));
    Light* light = lightNode->CreateComponent<Light>();
    light->SetLightType(LIGHT_DIRECTIONAL);
    light->SetCastShadows(true);
    light->SetShadowBias(BiasParameters(0.00025f, 0.5f));

    //Set cascade splits at 10, 50, 200 world unitys, fade shadows at 80% of maximum shadow distance
    light->SetShadowCascade(CascadeParameters(10.0f, 50.0f, 200.0f, 0.0f, 0.8f));

    //Create some mushrooms
    const unsigned NUM_MUSHROOMS = 100;
    for (unsigned i = 0; i < NUM_MUSHROOMS; ++i)
        CreateMushroom(Vector3(Random(90.0f) - 45.0f, 0.0f, Random(90.0f) - 45.0f));

    //Create randomly sized boxes. If boxes are big enough make them occluders
    const unsigned NUM_BOXES = 20;
    for (unsigned i = 0; i <NUM_BOXES; ++i)
    {
        Node* boxNode = scene_->CreateChild("Box");
        float size = 1.0f + Random(10.0f);
        boxNode->SetPosition(Vector3(Random(80.0f) - 40.0f, size * 0.5f, Random(80.0f) - 40.0f));
        boxNode->SetScale(size);
        StaticModel* boxObject = boxNode->CreateComponent<StaticModel>();
        boxObject->SetModel(cache->GetResource<Model>("Models/Box.mdl"));
        boxObject->SetMaterial(cache->GetResource<Material>("Materials/Stone.xml"));
        boxObject->SetCastShadows(true);
        if (size >= 3.0f)
            boxObject->SetOccluder(true);
    }

    //Create Jack node that will follow the path
    jackNode_ = scene_->CreateChild("Jack");
    jackNode_->SetPosition(Vector3(-5.0f, 0.0f, 20.0f));
    AnimatedModel* modelObject = jackNode_->CreateComponent<AnimatedModel>();
    modelObject->SetModel(cache->GetResource<Model>("Model/Jack.mdl"));
    modelObject->SetMaterial(cache->GetResource<Material>("Materials/Jack.xml"));
    modelObject->SetCastShadows(true);

    //Create the camera. Limit far clip distance to match the fog
    cameraNode_ = scene_->CreateChild("Camera");
    Camera* camera = cameraNode_->CreateComponent<Camera>();
    camera->SetFarClip(300.0f);

    //Set an initial position for the camera scene node above the plane
    cameraNode_->SetPosition(Vector3(0.0f, 5.0f, 0.0f));
}
コード例 #21
0
ファイル: Ragdolls.cpp プロジェクト: nemerle/lutefisk3d
void Ragdolls::CreateScene()
{
    ResourceCache* cache = GetContext()->m_ResourceCache.get();

    scene_ = new Scene(GetContext());

    // Create octree, use default volume (-1000, -1000, -1000) to (1000, 1000, 1000)
    // Create a physics simulation world with default parameters, which will update at 60fps. Like the Octree must
    // exist before creating drawable components, the PhysicsWorld must exist before creating physics components.
    // Finally, create a DebugRenderer component so that we can draw physics debug geometry
    scene_->CreateComponent<Octree>();
    scene_->CreateComponent<PhysicsWorld>();
    scene_->CreateComponent<DebugRenderer>();

    // Create a Zone component for ambient lighting & fog control
    Node* zoneNode = scene_->CreateChild("Zone");
    Zone* zone = zoneNode->CreateComponent<Zone>();
    zone->SetBoundingBox(BoundingBox(-1000.0f, 1000.0f));
    zone->SetAmbientColor(Color(0.15f, 0.15f, 0.15f));
    zone->SetFogColor(Color(0.5f, 0.5f, 0.7f));
    zone->SetFogStart(100.0f);
    zone->SetFogEnd(300.0f);

    // Create a directional light to the world. Enable cascaded shadows on it
    Node* lightNode = scene_->CreateChild("DirectionalLight");
    lightNode->SetDirection(Vector3(0.6f, -1.0f, 0.8f));
    Light* light = lightNode->CreateComponent<Light>();
    light->SetLightType(LIGHT_DIRECTIONAL);
    light->SetCastShadows(true);
    light->SetShadowBias(BiasParameters(0.00025f, 0.5f));
    // Set cascade splits at 10, 50 and 200 world units, fade shadows out at 80% of maximum shadow distance
    light->SetShadowCascade(CascadeParameters(10.0f, 50.0f, 200.0f, 0.0f, 0.8f));

    {
        // Create a floor object, 500 x 500 world units. Adjust position so that the ground is at zero Y
        Node* floorNode = scene_->CreateChild("Floor");
        floorNode->SetPosition(Vector3(0.0f, -0.5f, 0.0f));
        floorNode->SetScale(Vector3(500.0f, 1.0f, 500.0f));
        StaticModel* floorObject = floorNode->CreateComponent<StaticModel>();
        floorObject->SetModel(cache->GetResource<Model>("Models/Box.mdl"));
        floorObject->SetMaterial(cache->GetResource<Material>("Materials/StoneTiled.xml"));

        // Make the floor physical by adding RigidBody and CollisionShape components
        RigidBody* body = floorNode->CreateComponent<RigidBody>();
        // We will be spawning spherical objects in this sample. The ground also needs non-zero rolling friction so that
        // the spheres will eventually come to rest
        body->SetRollingFriction(0.15f);
        CollisionShape* shape = floorNode->CreateComponent<CollisionShape>();
        // Set a box shape of size 1 x 1 x 1 for collision. The shape will be scaled with the scene node scale, so the
        // rendering and physics representation sizes should match (the box model is also 1 x 1 x 1.)
        shape->SetBox(Vector3::ONE);
    }

    // Create animated models
    for (int z = -1; z <= 1; ++z)
    {
        for (int x = -4; x <= 4; ++x)
        {
            Node* modelNode = scene_->CreateChild("Jack");
            modelNode->SetPosition(Vector3(x * 5.0f, 0.0f, z * 5.0f));
            modelNode->SetRotation(Quaternion(0.0f, 180.0f, 0.0f));
            AnimatedModel* modelObject = modelNode->CreateComponent<AnimatedModel>();
            modelObject->SetModel(cache->GetResource<Model>("Models/Jack.mdl"));
            modelObject->SetMaterial(cache->GetResource<Material>("Materials/Jack.xml"));
            modelObject->SetCastShadows(true);
            // Set the model to also update when invisible to avoid staying invisible when the model should come into
            // view, but does not as the bounding box is not updated
            modelObject->SetUpdateInvisible(true);

            // Create a rigid body and a collision shape. These will act as a trigger for transforming the
            // model into a ragdoll when hit by a moving object
            RigidBody* body = modelNode->CreateComponent<RigidBody>();
            // The Trigger mode makes the rigid body only detect collisions, but impart no forces on the
            // colliding objects
            body->SetTrigger(true);
            CollisionShape* shape = modelNode->CreateComponent<CollisionShape>();
            // Create the capsule shape with an offset so that it is correctly aligned with the model, which
            // has its origin at the feet
            shape->SetCapsule(0.7f, 2.0f, Vector3(0.0f, 1.0f, 0.0f));

            // Create a custom component that reacts to collisions and creates the ragdoll
            modelNode->CreateComponent<CreateRagdoll>();
        }
    }

    // Create the camera. Limit far clip distance to match the fog. Note: now we actually create the camera node outside
    // the scene, because we want it to be unaffected by scene load / save
    cameraNode_ = new Node(GetContext());
    Camera* camera = cameraNode_->CreateComponent<Camera>();
    camera->setFarClipDistance(300.0f);

    // Set an initial position for the camera scene node above the floor
    cameraNode_->SetPosition(Vector3(0.0f, 3.0f, -20.0f));
}
コード例 #22
0
ファイル: CreateRagdoll.cpp プロジェクト: ClockTeam/Clockwork
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();
    }
}
コード例 #23
0
void SkeletalAnimation::CreateScene()
{
    ResourceCache* cache = GetSubsystem<ResourceCache>();
    
    scene_ = new Scene(context_);
    
    // Create octree, use default volume (-1000, -1000, -1000) to (1000, 1000, 1000)
    // Also create a DebugRenderer component so that we can draw debug geometry
    scene_->CreateComponent<Octree>();
    scene_->CreateComponent<DebugRenderer>();
    
    // Create scene node & StaticModel component for showing a static plane
    Node* planeNode = scene_->CreateChild("Plane");
    planeNode->SetScale(Vector3(100.0f, 1.0f, 100.0f));
    StaticModel* planeObject = planeNode->CreateComponent<StaticModel>();
    planeObject->SetModel(cache->GetResource<Model>("Models/Plane.mdl"));
    planeObject->SetMaterial(cache->GetResource<Material>("Materials/StoneTiled.xml"));
    
    // Create a Zone component for ambient lighting & fog control
    Node* zoneNode = scene_->CreateChild("Zone");
    Zone* zone = zoneNode->CreateComponent<Zone>();
    zone->SetBoundingBox(BoundingBox(-1000.0f, 1000.0f));
    zone->SetAmbientColor(Color(0.15f, 0.15f, 0.15f));
    zone->SetFogColor(Color(0.5f, 0.5f, 0.7f));
    zone->SetFogStart(100.0f);
    zone->SetFogEnd(300.0f);
    
    // Create a directional light to the world. Enable cascaded shadows on it
    Node* lightNode = scene_->CreateChild("Directional light");
    lightNode->SetDirection(Vector3(0.6f, -1.0f, 0.8f));
    Light* light = lightNode->CreateComponent<Light>();
    light->SetLightType(LIGHT_DIRECTIONAL);
    light->SetCastShadows(true);
    light->SetShadowBias(BiasParameters(0.0001f, 0.5f));
    // Set cascade splits at 10, 50 and 200 world units, fade shadows out at 80% of maximum shadow distance
    light->SetShadowCascade(CascadeParameters(10.0f, 50.0f, 200.0f, 0.0f, 0.8f));
    
    // Create animated models
    const unsigned NUM_MODELS = 100;
    const float MODEL_MOVE_SPEED = 2.0f;
    const float MODEL_ROTATE_SPEED = 100.0f;
    const BoundingBox bounds(Vector3(-47.0f, 0.0f, -47.0f), Vector3(47.0f, 0.0f, 47.0f));
    
    for (unsigned i = 0; i < NUM_MODELS; ++i)
    {
        Node* modelNode = scene_->CreateChild("Jack");
        modelNode->SetPosition(Vector3(Random(90.0f) - 45.0f, 0.0f, Random(90.0f) - 45.0f));
        modelNode->SetRotation(Quaternion(0.0f, Random(360.0f), 0.0f));
        AnimatedModel* modelObject = modelNode->CreateComponent<AnimatedModel>();
        modelObject->SetModel(cache->GetResource<Model>("Models/Jack.mdl"));
        modelObject->SetMaterial(cache->GetResource<Material>("Materials/Jack.xml"));
        modelObject->SetCastShadows(true);
        
        // Create an AnimationState for a walk animation. Its time position will need to be manually updated to advance the
        // animation, The alternative would be to use an AnimationController component which updates the animation automatically,
        // but we need to update the model's position manually in any case
        Animation* walkAnimation = cache->GetResource<Animation>("Models/Jack_Walk.ani");
        AnimationState* state = modelObject->AddAnimationState(walkAnimation);
        // Enable full blending weight and looping
        state->SetWeight(1.0f);
        state->SetLooped(true);
        
        // Create our custom Mover component that will move & animate the model during each frame's update
        Mover* mover = modelNode->CreateComponent<Mover>();
        mover->SetParameters(MODEL_MOVE_SPEED, MODEL_ROTATE_SPEED, bounds);
    }
    
    // Create the camera. Limit far clip distance to match the fog
    cameraNode_ = scene_->CreateChild("Camera");
    Camera* camera = cameraNode_->CreateComponent<Camera>();
    camera->SetFarClip(300.0f);
    
    // Set an initial position for the camera scene node above the plane
    cameraNode_->SetPosition(Vector3(0.0f, 5.0f, 0.0f));
}
コード例 #24
0
void AnimationController::Update(float timeStep)
{
    AnimatedModel* model = GetComponent<AnimatedModel>();
    if (!model)
        return;
    
    // Loop through animations
    for (Vector<AnimationControl>::Iterator i = animations_.Begin(); i != animations_.End();)
    {
        bool remove = false;
        AnimationState* state = model->GetAnimationState(i->hash_);
        if (!state)
            remove = true;
        else
        {
            // Advance the animation
            if (i->speed_ != 0.0f)
                state->AddTime(i->speed_ * timeStep);
            
            float targetWeight = i->targetWeight_;
            float fadeTime = i->fadeTime_;
            
            // If non-looped animation at the end, activate autofade as applicable
            if (!state->IsLooped() && state->GetTime() >= state->GetLength() && i->autoFadeTime_ > 0.0f)
            {
                targetWeight = 0.0f;
                fadeTime = i->autoFadeTime_;
            }
            
            // Process weight fade
            float currentWeight = state->GetWeight();
            if (currentWeight != targetWeight)
            {
                if (fadeTime > 0.0f)
                {
                    float weightDelta = 1.0f / fadeTime * timeStep;
                    if (currentWeight < targetWeight)
                        currentWeight = Min(currentWeight + weightDelta, targetWeight);
                    else if (currentWeight > targetWeight)
                        currentWeight = Max(currentWeight - weightDelta, targetWeight);
                    state->SetWeight(currentWeight);
                }
                else
                    state->SetWeight(targetWeight);
            }
            
            // Remove if weight zero and target weight zero
            if (state->GetWeight() == 0.0f && (targetWeight == 0.0f || fadeTime == 0.0f))
                remove = true;
        }
        
        // Decrement the command time-to-live values
        if (i->setTimeTtl_ > 0.0f)
            i->setTimeTtl_ = Max(i->setTimeTtl_ - timeStep, 0.0f);
        if (i->setWeightTtl_ > 0.0f)
            i->setWeightTtl_ = Max(i->setWeightTtl_ - timeStep, 0.0f);
        
        if (remove)
        {
            if (state)
                model->RemoveAnimationState(state);
            i = animations_.Erase(i);
            MarkNetworkUpdate();
        }
        else
            ++i;
    }
}
コード例 #25
0
AnimationState* AnimationController::FindAnimationState(const String& name) const
{
    AnimatedModel* model = GetComponent<AnimatedModel>();
    return model ? model->GetAnimationState(StringHash(name)) : 0;
}
コード例 #26
0
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;
        }
    }
}
コード例 #27
0
ファイル: RibbonTrailDemo.cpp プロジェクト: JTippetts/Urho3D
void RibbonTrailDemo::CreateScene()
{
    ResourceCache* cache = GetSubsystem<ResourceCache>();

    scene_ = new Scene(context_);

    // Create octree, use default volume (-1000, -1000, -1000) to (1000, 1000, 1000)
    scene_->CreateComponent<Octree>();

    // Create scene node & StaticModel component for showing a static plane
    Node* planeNode = scene_->CreateChild("Plane");
    planeNode->SetScale(Vector3(100.0f, 1.0f, 100.0f));
    StaticModel* planeObject = planeNode->CreateComponent<StaticModel>();
    planeObject->SetModel(cache->GetResource<Model>("Models/Plane.mdl"));
    planeObject->SetMaterial(cache->GetResource<Material>("Materials/StoneTiled.xml"));

    // Create a directional light to the world.
    Node* lightNode = scene_->CreateChild("DirectionalLight");
    lightNode->SetDirection(Vector3(0.6f, -1.0f, 0.8f)); // The direction vector does not need to be normalized
    Light* light = lightNode->CreateComponent<Light>();
    light->SetLightType(LIGHT_DIRECTIONAL);
    light->SetCastShadows(true);
    light->SetShadowBias(BiasParameters(0.00005f, 0.5f));
    // Set cascade splits at 10, 50 and 200 world units, fade shadows out at 80% of maximum shadow distance
    light->SetShadowCascade(CascadeParameters(10.0f, 50.0f, 200.0f, 0.0f, 0.8f));

    // Create first box for face camera trail demo with 1 column.
    boxNode1_ = scene_->CreateChild("Box1");
    StaticModel* box1 = boxNode1_->CreateComponent<StaticModel>();
    box1->SetModel(cache->GetResource<Model>("Models/Box.mdl"));
    box1->SetCastShadows(true);
    RibbonTrail* boxTrail1 = boxNode1_->CreateComponent<RibbonTrail>();
    boxTrail1->SetMaterial(cache->GetResource<Material>("Materials/RibbonTrail.xml"));
    boxTrail1->SetStartColor(Color(1.0f, 0.5f, 0.0f, 1.0f));
    boxTrail1->SetEndColor(Color(1.0f, 1.0f, 0.0f, 0.0f));
    boxTrail1->SetWidth(0.5f);
    boxTrail1->SetUpdateInvisible(true);

    // Create second box for face camera trail demo with 4 column.
    // This will produce less distortion than first trail.
    boxNode2_ = scene_->CreateChild("Box2");
    StaticModel* box2 = boxNode2_->CreateComponent<StaticModel>();
    box2->SetModel(cache->GetResource<Model>("Models/Box.mdl"));
    box2->SetCastShadows(true);
    RibbonTrail* boxTrail2 = boxNode2_->CreateComponent<RibbonTrail>();
    boxTrail2->SetMaterial(cache->GetResource<Material>("Materials/RibbonTrail.xml"));
    boxTrail2->SetStartColor(Color(1.0f, 0.5f, 0.0f, 1.0f));
    boxTrail2->SetEndColor(Color(1.0f, 1.0f, 0.0f, 0.0f));
    boxTrail2->SetWidth(0.5f);
    boxTrail2->SetTailColumn(4);
    boxTrail2->SetUpdateInvisible(true);

    // Load ninja animated model for bone trail demo.
    Node* ninjaNode = scene_->CreateChild("Ninja");
    ninjaNode->SetPosition(Vector3(5.0f, 0.0f, 0.0f));
    ninjaNode->SetRotation(Quaternion(0.0f, 180.0f, 0.0f));
    AnimatedModel* ninja = ninjaNode->CreateComponent<AnimatedModel>();
    ninja->SetModel(cache->GetResource<Model>("Models/NinjaSnowWar/Ninja.mdl"));
    ninja->SetMaterial(cache->GetResource<Material>("Materials/NinjaSnowWar/Ninja.xml"));
    ninja->SetCastShadows(true);

    // Create animation controller and play attack animation.
    ninjaAnimCtrl_ = ninjaNode->CreateComponent<AnimationController>();
    ninjaAnimCtrl_->PlayExclusive("Models/NinjaSnowWar/Ninja_Attack3.ani", 0, true, 0.0f);

    // Add ribbon trail to tip of sword.
    Node* swordTip = ninjaNode->GetChild("Joint29", true);
    swordTrail_ = swordTip->CreateComponent<RibbonTrail>();

    // Set sword trail type to bone and set other parameters.
    swordTrail_->SetTrailType(TT_BONE);
    swordTrail_->SetMaterial(cache->GetResource<Material>("Materials/SlashTrail.xml"));
    swordTrail_->SetLifetime(0.22f);
    swordTrail_->SetStartColor(Color(1.0f, 1.0f, 1.0f, 0.75f));
    swordTrail_->SetEndColor(Color(0.2f, 0.5f, 1.0f, 0.0f));
    swordTrail_->SetTailColumn(4);
    swordTrail_->SetUpdateInvisible(true);

    // Add floating text for info.
    Node* boxTextNode1 = scene_->CreateChild("BoxText1");
    boxTextNode1->SetPosition(Vector3(-1.0f, 2.0f, 0.0f));
    Text3D* boxText1 = boxTextNode1->CreateComponent<Text3D>();
    boxText1->SetText(String("Face Camera Trail (4 Column)"));
    boxText1->SetFont(cache->GetResource<Font>("Fonts/BlueHighway.sdf"), 24);

    Node* boxTextNode2 = scene_->CreateChild("BoxText2");
    boxTextNode2->SetPosition(Vector3(-6.0f, 2.0f, 0.0f));
    Text3D* boxText2 = boxTextNode2->CreateComponent<Text3D>();
    boxText2->SetText(String("Face Camera Trail (1 Column)"));
    boxText2->SetFont(cache->GetResource<Font>("Fonts/BlueHighway.sdf"), 24);

    Node* ninjaTextNode2 = scene_->CreateChild("NinjaText");
    ninjaTextNode2->SetPosition(Vector3(4.0f, 2.5f, 0.0f));
    Text3D* ninjaText = ninjaTextNode2->CreateComponent<Text3D>();
    ninjaText->SetText(String("Bone Trail (4 Column)"));
    ninjaText->SetFont(cache->GetResource<Font>("Fonts/BlueHighway.sdf"), 24);

    // Create the camera.
    cameraNode_ = scene_->CreateChild("Camera");
    cameraNode_->CreateComponent<Camera>();

    // Set an initial position for the camera scene node above the plane
    cameraNode_->SetPosition(Vector3(0.0f, 2.0f, -14.0f));
}
コード例 #28
0
ファイル: Navigation.cpp プロジェクト: nonconforme/Urho3D
void Navigation::CreateScene()
{
    ResourceCache* cache = GetSubsystem<ResourceCache>();

    scene_ = new Scene(context_);

    // Create octree, use default volume (-1000, -1000, -1000) to (1000, 1000, 1000)
    // Also create a DebugRenderer component so that we can draw debug geometry
    scene_->CreateComponent<Octree>();
    scene_->CreateComponent<DebugRenderer>();

    // Create scene node & StaticModel component for showing a static plane
    Node* planeNode = scene_->CreateChild("Plane");
    planeNode->SetScale(Vector3(100.0f, 1.0f, 100.0f));
    StaticModel* planeObject = planeNode->CreateComponent<StaticModel>();
    planeObject->SetModel(cache->GetResource<Model>("Models/Plane.mdl"));
    planeObject->SetMaterial(cache->GetResource<Material>("Materials/StoneTiled.xml"));

    // Create a Zone component for ambient lighting & fog control
    Node* zoneNode = scene_->CreateChild("Zone");
    Zone* zone = zoneNode->CreateComponent<Zone>();
    zone->SetBoundingBox(BoundingBox(-1000.0f, 1000.0f));
    zone->SetAmbientColor(Color(0.15f, 0.15f, 0.15f));
    zone->SetFogColor(Color(0.5f, 0.5f, 0.7f));
    zone->SetFogStart(100.0f);
    zone->SetFogEnd(300.0f);

    // Create a directional light to the world. Enable cascaded shadows on it
    Node* lightNode = scene_->CreateChild("DirectionalLight");
    lightNode->SetDirection(Vector3(0.6f, -1.0f, 0.8f));
    Light* light = lightNode->CreateComponent<Light>();
    light->SetLightType(LIGHT_DIRECTIONAL);
    light->SetCastShadows(true);
    light->SetShadowBias(BiasParameters(0.00025f, 0.5f));
    // Set cascade splits at 10, 50 and 200 world units, fade shadows out at 80% of maximum shadow distance
    light->SetShadowCascade(CascadeParameters(10.0f, 50.0f, 200.0f, 0.0f, 0.8f));

    // Create some mushrooms
    const unsigned NUM_MUSHROOMS = 100;
    for (unsigned i = 0; i < NUM_MUSHROOMS; ++i)
        CreateMushroom(Vector3(Random(90.0f) - 45.0f, 0.0f, Random(90.0f) - 45.0f));

    // Create randomly sized boxes. If boxes are big enough, make them occluders
    const unsigned NUM_BOXES = 20;
    for (unsigned i = 0; i < NUM_BOXES; ++i)
    {
        Node* boxNode = scene_->CreateChild("Box");
        float size = 1.0f + Random(10.0f);
        boxNode->SetPosition(Vector3(Random(80.0f) - 40.0f, size * 0.5f, Random(80.0f) - 40.0f));
        boxNode->SetScale(size);
        StaticModel* boxObject = boxNode->CreateComponent<StaticModel>();
        boxObject->SetModel(cache->GetResource<Model>("Models/Box.mdl"));
        boxObject->SetMaterial(cache->GetResource<Material>("Materials/Stone.xml"));
        boxObject->SetCastShadows(true);
        if (size >= 3.0f)
            boxObject->SetOccluder(true);
    }

    // Create Jack node that will follow the path
    jackNode_ = scene_->CreateChild("Jack");
    jackNode_->SetPosition(Vector3(-5.0f, 0.0f, 20.0f));
    AnimatedModel* modelObject = jackNode_->CreateComponent<AnimatedModel>();
    modelObject->SetModel(cache->GetResource<Model>("Models/Jack.mdl"));
    modelObject->SetMaterial(cache->GetResource<Material>("Materials/Jack.xml"));
    modelObject->SetCastShadows(true);

    // Create a NavigationMesh component to the scene root
    NavigationMesh* navMesh = scene_->CreateComponent<NavigationMesh>();
    // Create a Navigable component to the scene root. This tags all of the geometry in the scene as being part of the
    // navigation mesh. By default this is recursive, but the recursion could be turned off from Navigable
    scene_->CreateComponent<Navigable>();
    // Add padding to the navigation mesh in Y-direction so that we can add objects on top of the tallest boxes
    // in the scene and still update the mesh correctly
    navMesh->SetPadding(Vector3(0.0f, 10.0f, 0.0f));
    // Now build the navigation geometry. This will take some time. Note that the navigation mesh will prefer to use
    // physics geometry from the scene nodes, as it often is simpler, but if it can not find any (like in this example)
    // it will use renderable geometry instead
    navMesh->Build();

    // Create the camera. Limit far clip distance to match the fog
    cameraNode_ = scene_->CreateChild("Camera");
    Camera* camera = cameraNode_->CreateComponent<Camera>();
    camera->SetFarClip(300.0f);

    // Set an initial position for the camera scene node above the plane and looking down
    cameraNode_->SetPosition(Vector3(0.0f, 50.0f, 0.0f));
    pitch_ = 80.0f;
    cameraNode_->SetRotation(Quaternion(pitch_, yaw_, 0.0f));
}