animation updates
This commit is contained in:
@@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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<AnimationComponent>& animations,
|
||||
wiECS::ComponentManager<TransformComponent>& 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<TransformComponent>& transforms)
|
||||
{
|
||||
for (size_t i = 0; i < transforms.GetCount(); ++i)
|
||||
|
||||
@@ -660,6 +660,14 @@ namespace wiSceneSystem
|
||||
};
|
||||
|
||||
std::vector<AnimationChannel> 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<AnimationComponent>& animations,
|
||||
wiECS::ComponentManager<TransformComponent>& transforms,
|
||||
float dt
|
||||
);
|
||||
void RunTransformUpdateSystem(wiECS::ComponentManager<TransformComponent>& transforms);
|
||||
void RunHierarchyUpdateSystem(
|
||||
const wiECS::ComponentManager<ParentComponent>& parents,
|
||||
|
||||
Reference in New Issue
Block a user