Thanks again, Lasse. Got it working, and here is the modified LightAnimation sample in case anybody else wants to do something similar.
LightAnimation.h
#pragma once
#include "Sample.h"
namespace Urho3D
{
class Node;
class Scene;
class AnimationState;
}
/// Light animation example.
/// This sample is base on StaticScene, and it demonstrates:
/// - Usage of attribute animation for light color animation
class LightAnimation : public Sample
{
OBJECT(LightAnimation);
public:
/// Construct.
LightAnimation(Context* context);
/// Setup after engine initialization and before running the main loop.
virtual void Start();
private:
/// Construct the scene content.
void CreateScene();
/// Construct an instruction text to the UI.
void CreateInstructions();
/// Set up a viewport for displaying the scene.
void SetupViewport();
/// Subscribe to application-wide logic update events.
void SubscribeToEvents();
/// Handle the logic update event.
void HandleUpdate(StringHash eventType, VariantMap& eventData);
// Camera node animation state instance
SharedPtr<AnimationState> animationState_;
};
LightAnimation.cpp:
#include "Camera.h"
#include "CoreEvents.h"
#include "Engine.h"
#include "Font.h"
#include "Graphics.h"
#include "Input.h"
#include "LightAnimation.h"
#include "Material.h"
#include "Model.h"
#include "Octree.h"
#include "Renderer.h"
#include "ResourceCache.h"
#include "Scene.h"
#include "StaticModel.h"
#include "Text.h"
#include "UI.h"
#include "Animation.h"
#include "AnimationState.h"
#include "DebugNew.h"
#include "Animatable.h"
DEFINE_APPLICATION_MAIN(LightAnimation)
LightAnimation::LightAnimation(Context* context) :
Sample(context)
{
}
void LightAnimation::Start()
{
// Execute base class startup
Sample::Start();
// Create the scene content
CreateScene();
// Setup the viewport for displaying the scene
SetupViewport();
// Hook up to the frame update events
SubscribeToEvents();
}
void LightAnimation::CreateScene()
{
ResourceCache* cache = GetSubsystem<ResourceCache>();
scene_ = new Scene(context_);
// Create the Octree component to the scene. This is required before adding any drawable components, or else nothing will
// show up. The default octree volume will be from (-1000, -1000, -1000) to (1000, 1000, 1000) in world coordinates; it
// is also legal to place objects outside the volume but their visibility can then not be checked in a hierarchically
// optimizing manner
scene_->CreateComponent<Octree>();
// Create a child scene node (at world origin) and a StaticModel component into it. Set the StaticModel to show a simple
// plane mesh with a "stone" material. Note that naming the scene nodes is optional. Scale the scene node larger
// (100 x 100 world units)
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 point light to the world so that we can see something.
Node* lightNode = scene_->CreateChild("PointLight");
Light* light = lightNode->CreateComponent<Light>();
light->SetLightType(LIGHT_POINT);
light->SetRange(200.0f);
// Create a scene node for the camera, which we will move around
// The camera will use default settings (1000 far clip distance, 45 degrees FOV, set aspect ratio automatically)
cameraNode_ = scene_->CreateChild("Camera");
cameraNode_->CreateComponent<Camera>();
// Set an initial position for the camera scene node above the plane
cameraNode_->SetPosition(Vector3(0.0f, 5.0f, 0.0f));
// Load animation from file, in this case exported from Blender and converted using AssetImporter
SharedPtr<Animation> anim(cache->GetResource<Animation>("Animations/CameraAnim1.ani"));
animationState_ = SharedPtr<AnimationState>(new AnimationState(cameraNode_, anim));
}
void LightAnimation::SetupViewport()
{
Renderer* renderer = GetSubsystem<Renderer>();
// Set up a viewport to the Renderer subsystem so that the 3D scene can be seen. We need to define the scene and the camera
// at minimum. Additionally we could configure the viewport screen size and the rendering path (eg. forward / deferred) to
// use, but now we just use full screen and default render path configured in the engine command line options
SharedPtr<Viewport> viewport(new Viewport(context_, scene_, cameraNode_->GetComponent<Camera>()));
renderer->SetViewport(0, viewport);
}
void LightAnimation::SubscribeToEvents()
{
// Subscribe HandleUpdate() function for processing update events
SubscribeToEvent(E_UPDATE, HANDLER(LightAnimation, HandleUpdate));
}
void LightAnimation::HandleUpdate(StringHash eventType, VariantMap& eventData)
{
using namespace Update;
// Take the frame time step, which is stored as a float
float timeStep = eventData[P_TIMESTEP].GetFloat();
// Update the camera animation state
animationState_->AddTime(timeStep);
animationState_->Apply();
}