Radium Engine  1.5.20
Loading...
Searching...
No Matches
SkeletonBasedAnimationSystem.cpp
1#include <Engine/Scene/SkeletonBasedAnimationSystem.hpp>
2
3#include <string>
4
5#include <Core/Asset/FileData.hpp>
6#include <Core/Math/Math.hpp>
7#include <Core/Resources/Resources.hpp>
8#include <Core/Tasks/Task.hpp>
9#include <Core/Tasks/TaskQueue.hpp>
10
11#include <Engine/Data/Texture.hpp>
12#include <Engine/Data/TextureManager.hpp>
13#include <Engine/FrameInfo.hpp>
14#include <Engine/RadiumEngine.hpp>
15#include <Engine/Scene/SkeletonComponent.hpp>
16#include <Engine/Scene/SkinningComponent.hpp>
17
18using namespace Ra::Core::Animation;
19
20namespace Ra {
21namespace Engine {
22namespace Scene {
23
25 auto resourceDir { Core::Resources::getRadiumResourcesPath() };
26 if ( resourceDir ) {
27 auto* engine = RadiumEngine::getInstance();
28 auto* texMngr = engine->getTextureManager();
29 // Register an entry into the texture manager
30 // load the texture image without OpenGL initialization
31 auto image = texMngr->loadTextureImage( *resourceDir + "/Textures/heatmap.png" );
32 Data::TextureParameters heatMapTexturePamameters = { "Engine:Skinning:weights", {}, image };
33 m_heatMapTextureHandle = texMngr->addTexture( heatMapTexturePamameters );
34 }
35}
36
37SkeletonBasedAnimationSystem::~SkeletonBasedAnimationSystem() {
38 SkeletonComponent::s_boneMesh.reset();
39 SkeletonComponent::s_boneMaterial.reset();
40 SkeletonComponent::s_boneRenderTechnique.reset();
41}
42
43// System Interface
44
46 const FrameInfo& frameInfo ) {
47 for ( auto compEntry : m_components ) {
48 // deal with AnimationComponents
49 if ( auto animComp = dynamic_cast<SkeletonComponent*>( compEntry.second ) ) {
50 if ( !Core::Math::areApproxEqual( m_time, frameInfo.m_animationTime ) ) {
51 // here we update the skeleton w.r.t. the animation
52 auto animFunc =
54 auto animTask = std::make_unique<Core::FunctionTask>(
55 animFunc, "AnimatorTask_" + animComp->getSkeleton()->getName() );
56 taskQueue->registerTask( std::move( animTask ) );
57 }
58 else {
59 // here we update the skeleton w.r.t. the manipulation
60 auto animFunc = std::bind( &SkeletonComponent::updateDisplay, animComp );
61 auto animTask = std::make_unique<Core::FunctionTask>(
62 animFunc, "AnimatorTask_" + animComp->getSkeleton()->getName() );
63 taskQueue->registerTask( std::move( animTask ) );
64 }
65 }
66 // deal with SkinningComponents
67 else if ( auto skinComp = dynamic_cast<SkinningComponent*>( compEntry.second ) ) {
68 auto skinFunc = std::bind( &SkinningComponent::skin, skinComp );
69 auto skinTask = std::make_unique<Core::FunctionTask>(
70 skinFunc, "SkinnerTask_" + skinComp->getMeshName() );
71 auto endFunc = std::bind( &SkinningComponent::endSkinning, skinComp );
72 auto endTask = std::make_unique<Core::FunctionTask>(
73 endFunc, "SkinnerEndTask_" + skinComp->getMeshName() );
74
75 auto skinTaskId = taskQueue->registerTask( std::move( skinTask ) );
76 auto endTaskId = taskQueue->registerTask( std::move( endTask ) );
77 taskQueue->addPendingDependency( "AnimatorTask_" + skinComp->getSkeletonName(),
78 skinTaskId );
79 taskQueue->addDependency( skinTaskId, endTaskId );
80 }
81 }
82
83 m_time = frameInfo.m_animationTime;
84}
85
87 const Core::Asset::FileData* fileData ) {
88 auto skelData = fileData->getHandleData();
89 auto animData = fileData->getAnimationData();
90
91 // deal with AnimationComponents
92 Scalar startTime = std::numeric_limits<Scalar>::max();
93 Scalar endTime = 0;
94 for ( const auto& skel : skelData ) {
95 auto component = new SkeletonComponent( "AC_" + skel->getName(), entity );
96 component->handleSkeletonLoading( skel );
97 component->handleAnimationLoading( animData );
98 auto [s, e] = component->getAnimationTimeInterval();
99 startTime = std::min( startTime, s );
100 endTime = std::max( endTime, e );
101 component->setXray( m_xrayOn );
102 registerComponent( entity, component );
103 }
104 // configure the time on the Engine
105 auto engine = RadiumEngine::getInstance();
106 engine->setStartTime( startTime );
107 engine->setEndTime( endTime );
108
109 // deal with SkinningComponents
110 auto geomData = fileData->getGeometryData();
111 if ( geomData.size() > 0 && skelData.size() > 0 ) {
112 for ( const auto& geom : geomData ) {
113 // look for a skeleton skinning this mesh
114 // warning: there should be at most one such skeleton!
115 auto it = std::find_if( skelData.begin(), skelData.end(), [&geom]( const auto& skel ) {
116 return std::find_if( skel->getBindMeshes().begin(),
117 skel->getBindMeshes().end(),
118 [&geom]( const auto& meshName ) {
119 return meshName == geom->getName();
120 } ) != skel->getBindMeshes().end();
121 } );
122 if ( it != skelData.end() ) {
123 const auto& skel = *it;
124 SkinningComponent* component = new SkinningComponent(
125 "SkC_" + geom->getName(), SkinningComponent::LBS, entity );
126 component->handleSkinDataLoading( skel, geom->getName() );
127 registerComponent( entity, component );
128 }
129 }
130 }
131}
132
133// Skeleton display
134
135void SkeletonBasedAnimationSystem::setXray( bool on ) {
136 m_xrayOn = on;
137 for ( const auto& comp : m_components ) {
138 if ( auto animComp = dynamic_cast<SkeletonComponent*>( comp.second ) ) {
139 animComp->setXray( on );
140 }
141 }
142}
143
144bool SkeletonBasedAnimationSystem::isXrayOn() {
145 return m_xrayOn;
146}
147
148void SkeletonBasedAnimationSystem::toggleSkeleton( const bool status ) {
149 for ( const auto& comp : m_components ) {
150 if ( auto animComp = dynamic_cast<SkeletonComponent*>( comp.second ) ) {
151 animComp->toggleSkeleton( status );
152 }
153 }
154}
155
156} // namespace Scene
157} // namespace Engine
158} // namespace Ra
T bind(T... args)
This class allows tasks to be registered and then executed in parallel on separate threads.
Definition TaskQueue.hpp:48
void addPendingDependency(const std::string &predecessors, TaskId successor)
void addDependency(TaskId predecessor, TaskId successor)
Definition TaskQueue.cpp:77
TaskId registerTask(std::unique_ptr< Task > task)
Definition TaskQueue.cpp:33
An entity is an scene element. It ties together components with a transform.
Definition Entity.hpp:23
void handleAssetLoading(Entity *entity, const Core::Asset::FileData *fileData) override
Loads Skeletons and Animations from a file data into the givn Entity.
void generateTasks(Core::TaskQueue *taskQueue, const FrameInfo &frameInfo) override
Creates a task for each AnimationComponent to update skeleton display.
void update(Scalar time)
Updates the skeleton pose as the pose corresponding to time time.
void updateDisplay()
Updates the skeleton display.
The SkinningComponent class is responsible for applying Geometric Skinning Methods on an animated obj...
void endSkinning()
Update internal data and update the skinned mesh.
void handleSkinDataLoading(const Core::Asset::HandleData *data, const std::string &meshName)
void skin()
Apply the Skinning Method and update the SkinningFrameData.
std::vector< std::pair< const Entity *, Component * > > m_components
List of active components.
Definition System.hpp:103
virtual void registerComponent(const Entity *entity, Component *component)
Definition System.cpp:10
T find_if(T... args)
T max(T... args)
T min(T... args)
T move(T... args)
std::enable_if<!std::numeric_limits< T >::is_integer, bool >::type areApproxEqual(T x, T y, T espilonBoostFactor=T(10))
Compare two numbers such that |x-y| < espilon*epsilonBoostFactor.
Definition Math.hpp:42
optional< std::string > getRadiumResourcesPath()
Get the path of Radium internal resources.
Definition Resources.cpp:35
hepler function to manage enum as underlying types in VariableSet
Definition Cage.cpp:3
Describes the sampler and image of a texture.
Definition Texture.hpp:99
Structure passed to each system before they fill the task queue.
Definition FrameInfo.hpp:8
Scalar m_animationTime
The current animation time.
Definition FrameInfo.hpp:10