From c1e06841dc800271e70128a0281fc321dcadec8e Mon Sep 17 00:00:00 2001 From: Turanszki Janos Date: Thu, 6 Sep 2018 02:12:04 +0100 Subject: [PATCH] animation updates --- Editor/ModelImporter_GLTF.cpp | 9 ++- WickedEngine/wiRenderer.cpp | 4 ++ WickedEngine/wiSceneSystem.cpp | 123 +++++++++++++++++++++++++++++++++ WickedEngine/wiSceneSystem.h | 13 ++++ 4 files changed, 147 insertions(+), 2 deletions(-) diff --git a/Editor/ModelImporter_GLTF.cpp b/Editor/ModelImporter_GLTF.cpp index 21bec8f08..078499ca2 100644 --- a/Editor/ModelImporter_GLTF.cpp +++ b/Editor/ModelImporter_GLTF.cpp @@ -802,9 +802,13 @@ Entity ImportModel_GLTF(const std::string& fileName) const unsigned char* data = buffer.data.data() + accessor.byteOffset + bufferView.byteOffset; assert(stride == 4); + + animationcomponent.length = 0.0f; for (size_t i = 0; i < count; ++i) { - animationcomponent.channels.back().keyframe_times[i] = ((float*)data)[i]; + float time = ((float*)data)[i]; + animationcomponent.channels.back().keyframe_times[i] = time; + animationcomponent.length = max(animationcomponent.length, time); } } @@ -887,7 +891,8 @@ Entity ImportModel_GLTF(const std::string& fileName) } else { - assert(0); + // Not implemented: + animationcomponent.channels.pop_back(); } } diff --git a/WickedEngine/wiRenderer.cpp b/WickedEngine/wiRenderer.cpp index b9a828ac0..72e73b2bd 100644 --- a/WickedEngine/wiRenderer.cpp +++ b/WickedEngine/wiRenderer.cpp @@ -7891,6 +7891,10 @@ wiRenderer::RayIntersectWorldResult wiRenderer::RayIntersectWorld(const RAY& ray const XMVECTOR rayOrigin_local = XMVector3Transform(rayOrigin, objectMat_Inverse); const XMVECTOR rayDirection_local = XMVector3Normalize(XMVector3TransformNormal(rayDirection, objectMat_Inverse)); + if (!DirectX::Internal::XMVector3IsUnit(rayDirection_local)) + { + continue; + } MeshComponent::Vertex_FULL _tmpvert; diff --git a/WickedEngine/wiSceneSystem.cpp b/WickedEngine/wiSceneSystem.cpp index 7aba8b369..5e87944fa 100644 --- a/WickedEngine/wiSceneSystem.cpp +++ b/WickedEngine/wiSceneSystem.cpp @@ -720,6 +720,9 @@ namespace wiSceneSystem void Scene::Update(float dt) { + + RunAnimationUpdateSystem(animations, transforms, dt); + RunTransformUpdateSystem(transforms); RunHierarchyUpdateSystem(parents, transforms, layers); @@ -761,6 +764,7 @@ namespace wiSceneSystem probes.Remove(entity); forces.Remove(entity); decals.Remove(entity); + animations.Remove(entity); models.Remove(entity); } @@ -787,6 +791,7 @@ namespace wiSceneSystem probes.Remove(entity); forces.Remove(entity); decals.Remove(entity); + animations.Remove(entity); models.Remove(entity); } Entity Scene::Entity_FindByName(const std::string& name) @@ -1016,6 +1021,7 @@ namespace wiSceneSystem TransformComponent* transform_child = transforms.GetComponent(entity); if (transform_child != nullptr) { + // Child updated immediately, to that it can be immediately attached to afterwards: transform_child->UpdateParentedTransform(*transform_parent, parentcomponent->world_parent_inverse_bind); } @@ -1066,6 +1072,123 @@ namespace wiSceneSystem + void RunAnimationUpdateSystem( + wiECS::ComponentManager& animations, + wiECS::ComponentManager& transforms, + float dt + ) + { + for (size_t i = 0; i < animations.GetCount(); ++i) + { + AnimationComponent& animation = animations[i]; + + for (auto& channel : animation.channels) + { + if (channel.keyframe_times.empty()) + { + // No keyframes! + assert(0); + continue; + } + + int keyLeft = 0; + int keyRight = 0; + + if (channel.keyframe_times.back() < animation.timer) + { + // Rightmost keyframe is already outside animation, so just snap to last keyframe: + keyLeft = keyRight = (int)channel.keyframe_times.size() - 1; + } + else + { + // Search for the right keyframe (greater/equal to anim time): + while (channel.keyframe_times[keyRight++] < animation.timer) {} + keyRight--; + + // Left keyframe is just near right: + keyLeft = max(0, keyRight - 1); + } + + float left = channel.keyframe_times[keyLeft]; + + TransformComponent& transform = *transforms.GetComponent(channel.target); + + if (channel.mode == AnimationComponent::AnimationChannel::Mode::STEP || keyLeft == keyRight) + { + // Nearest neighbor method (snap to left): + switch (channel.type) + { + case AnimationComponent::AnimationChannel::Type::TRANSLATION: + { + transform.translation_local = ((const XMFLOAT3*)channel.keyframe_data.data())[keyLeft * 3]; + } + break; + case AnimationComponent::AnimationChannel::Type::ROTATION: + { + transform.rotation_local = ((const XMFLOAT4*)channel.keyframe_data.data())[keyLeft * 4]; + } + break; + case AnimationComponent::AnimationChannel::Type::SCALE: + { + transform.scale_local = ((const XMFLOAT3*)channel.keyframe_data.data())[keyLeft * 3]; + } + break; + } + } + else + { + // Linear interpolation method: + float right = channel.keyframe_times[keyRight]; + float t = (animation.timer - left) / (right - left); + + switch (channel.type) + { + case AnimationComponent::AnimationChannel::Type::TRANSLATION: + { + const XMFLOAT3* data = (const XMFLOAT3*)channel.keyframe_data.data(); + XMVECTOR vLeft = XMLoadFloat3(&data[keyLeft * 3]); + XMVECTOR vRight = XMLoadFloat3(&data[keyRight * 3]); + XMVECTOR vMiddle = XMVectorLerp(vLeft, vRight, t); + XMStoreFloat3(&transform.translation_local, vMiddle); + } + break; + case AnimationComponent::AnimationChannel::Type::ROTATION: + { + const XMFLOAT4* data = (const XMFLOAT4*)channel.keyframe_data.data(); + XMVECTOR vLeft = XMLoadFloat4(&data[keyLeft * 4]); + XMVECTOR vRight = XMLoadFloat4(&data[keyRight * 4]); + XMVECTOR vMiddle = XMQuaternionSlerp(vLeft, vRight, t); + vMiddle = XMQuaternionNormalize(vMiddle); + XMStoreFloat4(&transform.rotation_local, vMiddle); + } + break; + case AnimationComponent::AnimationChannel::Type::SCALE: + { + const XMFLOAT3* data = (const XMFLOAT3*)channel.keyframe_data.data(); + XMVECTOR vLeft = XMLoadFloat3(&data[keyLeft * 3]); + XMVECTOR vRight = XMLoadFloat3(&data[keyRight * 3]); + XMVECTOR vMiddle = XMVectorLerp(vLeft, vRight, t); + XMStoreFloat3(&transform.scale_local, vMiddle); + } + break; + } + } + + transform.dirty = true; + + } + + if (animation.playing) + { + animation.timer += dt; + } + + if (animation.looped && animation.timer > animation.length) + { + animation.timer = 0.0f; + } + } + } void RunTransformUpdateSystem(ComponentManager& transforms) { for (size_t i = 0; i < transforms.GetCount(); ++i) diff --git a/WickedEngine/wiSceneSystem.h b/WickedEngine/wiSceneSystem.h index 80bad86d7..3435a99d1 100644 --- a/WickedEngine/wiSceneSystem.h +++ b/WickedEngine/wiSceneSystem.h @@ -660,6 +660,14 @@ namespace wiSceneSystem }; std::vector channels; + float timer = 0.0f; + float length = 0.0f; + bool looped = false; + bool playing = true; + + inline void Pause() { playing = false; } + inline void Stop() { playing = false; timer = 0.0f; } + inline void Play() { playing = true; } }; struct ModelComponent @@ -778,6 +786,11 @@ namespace wiSceneSystem void Component_DetachChildren(wiECS::Entity parent); }; + void RunAnimationUpdateSystem( + wiECS::ComponentManager& animations, + wiECS::ComponentManager& transforms, + float dt + ); void RunTransformUpdateSystem(wiECS::ComponentManager& transforms); void RunHierarchyUpdateSystem( const wiECS::ComponentManager& parents,