123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361 |
- /**
- * @file animation.cpp
- * @brief LL GLTF Animation Implementation
- *
- * $LicenseInfo:firstyear=2024&license=viewerlgpl$
- * Second Life Viewer Source Code
- * Copyright (C) 2024, Linden Research, Inc.
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation;
- * version 2.1 of the License only.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- *
- * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
- * $/LicenseInfo$
- */
- #include "linden_common.h"
- #include "tinygltf/tiny_gltf.h"
- #include "llgltfanimation.h"
- #include "llgltfasset.h"
- #include "llgltfbufferutil.h"
- using namespace LLGLTF;
- ///////////////////////////////////////////////////////////////////////////////
- // LLGLTF::Animation::Sampler sub-class
- ///////////////////////////////////////////////////////////////////////////////
- Animation::Sampler::Sampler()
- : mMinTime(-F32_MAX),
- mMaxTime(F32_MAX),
- mInput(INVALID_INDEX),
- mOutput(INVALID_INDEX)
- {
- }
- const Animation::Sampler& Animation::Sampler::operator=(const tinygltf::AnimationSampler& src)
- {
- mInput = src.input;
- mOutput = src.output;
- mInterpolation = src.interpolation;
- return *this;
- }
- ///////////////////////////////////////////////////////////////////////////////
- // LLGLTF::Animation::Channel sub-class
- ///////////////////////////////////////////////////////////////////////////////
- Animation::Channel::Channel()
- : mSampler(INVALID_INDEX)
- {
- }
- const Animation::Channel& Animation::Channel::operator=(const tinygltf::AnimationChannel& src)
- {
- mSampler = src.sampler;
- mTarget.mNode = src.target_node;
- mTarget.mPath = src.target_path;
- return *this;
- }
- ///////////////////////////////////////////////////////////////////////////////
- // LLGLTF::Animation::RotationChannel sub-class
- ///////////////////////////////////////////////////////////////////////////////
- const Animation::RotationChannel& Animation::RotationChannel::operator=(const tinygltf::AnimationChannel& src)
- {
- Animation::Channel::operator=(src);
- return *this;
- }
- ///////////////////////////////////////////////////////////////////////////////
- // LLGLTF::Animation::TranslationChannel sub-class
- ///////////////////////////////////////////////////////////////////////////////
- const Animation::TranslationChannel& Animation::TranslationChannel::operator=(const tinygltf::AnimationChannel& src)
- {
- Animation::Channel::operator=(src);
- return *this;
- }
- ///////////////////////////////////////////////////////////////////////////////
- // LLGLTF::Animation::ScaleChannel sub-class
- ///////////////////////////////////////////////////////////////////////////////
- const Animation::ScaleChannel& Animation::ScaleChannel::operator=(const tinygltf::AnimationChannel& src)
- {
- Animation::Channel::operator=(src);
- return *this;
- }
- ///////////////////////////////////////////////////////////////////////////////
- // LLGLTF::Animation class
- ///////////////////////////////////////////////////////////////////////////////
- Animation::Animation()
- : mMinTime(0.f),
- mMaxTime(0.f),
- mTime(0.f)
- {
- }
- void Animation::allocateGLResources(Asset& asset)
- {
- if (!mSamplers.empty())
- {
- mMinTime = FLT_MAX;
- mMaxTime = -FLT_MAX;
- for (auto& sampler : mSamplers)
- {
- sampler.allocateGLResources(asset);
- mMinTime = llmin(sampler.mMinTime, mMinTime);
- mMaxTime = llmax(sampler.mMaxTime, mMaxTime);
- }
- }
- else
- {
- mMinTime = mMaxTime = 0.f;
- }
- for (auto& channel : mRotationChannels)
- {
- channel.allocateGLResources(asset, mSamplers[channel.mSampler]);
- }
- for (auto& channel : mTranslationChannels)
- {
- channel.allocateGLResources(asset, mSamplers[channel.mSampler]);
- }
- }
- void Animation::update(Asset& asset, F32 dt)
- {
- mTime += dt;
- apply(asset, mTime);
- }
- void Animation::apply(Asset& asset, F32 time)
- {
- // Convert time to animation loop time
- time = fmod(time, mMaxTime - mMinTime) + mMinTime;
- // apply each channel
- for (auto& channel : mRotationChannels)
- {
- channel.apply(asset, mSamplers[channel.mSampler], time);
- }
- for (auto& channel : mTranslationChannels)
- {
- channel.apply(asset, mSamplers[channel.mSampler], time);
- }
- };
- void Animation::Sampler::allocateGLResources(Asset& asset)
- {
- Accessor& accessor = asset.mAccessors[mInput];
- mMinTime = accessor.mMin[0];
- mMaxTime = accessor.mMax[0];
- mFrameTimes.resize(accessor.mCount);
- LLStrider<F32> frame_times = mFrameTimes.data();
- copy(asset, accessor, frame_times);
- }
- void Animation::Sampler::getFrameInfo(Asset& asset, F32 time, U32& frame_idx,
- F32& t)
- {
- if (time < mMinTime)
- {
- frame_idx = 0;
- t = 0.f;
- return;
- }
- if (mFrameTimes.size() > 1)
- {
- if (time > mMaxTime)
- {
- frame_idx = mFrameTimes.size() - 2;
- t = 1.f;
- return;
- }
- frame_idx = mFrameTimes.size() - 2;
- t = 1.f;
- for (U32 i = 0; i < mFrameTimes.size() - 1; ++i)
- {
- if (time >= mFrameTimes[i] && time < mFrameTimes[i + 1])
- {
- frame_idx = i;
- t = (time - mFrameTimes[i]) /
- (mFrameTimes[i + 1] - mFrameTimes[i]);
- return;
- }
- }
- }
- else
- {
- frame_idx = 0;
- t = 0.f;
- }
- }
- void Animation::RotationChannel::allocateGLResources(Asset& asset,
- Animation::Sampler& sampler)
- {
- Accessor& accessor = asset.mAccessors[sampler.mOutput];
- copy(asset, accessor, mRotations);
- }
- void Animation::RotationChannel::apply(Asset& asset, Sampler& sampler,
- F32 time)
- {
- Node& node = asset.mNodes[mTarget.mNode];
- U32 frame_idx;
- F32 t;
- sampler.getFrameInfo(asset, time, frame_idx, t);
- if (sampler.mFrameTimes.size() == 1)
- {
- node.setRotation(mRotations[0]);
- }
- else
- {
- // Interpolate
- LLQuaternion q0(mRotations[frame_idx].get_value());
- LLQuaternion q1(mRotations[frame_idx + 1].get_value());
- LLQuaternion qf = slerp(t, q0, q1);
- qf.normalize();
- node.setRotation(glh::quaternionf(qf.mQ));
- }
- }
- void Animation::TranslationChannel::allocateGLResources(Asset& asset,
- Animation::Sampler& sampler)
- {
- Accessor& accessor = asset.mAccessors[sampler.mOutput];
- copy(asset, accessor, mTranslations);
- }
- void Animation::TranslationChannel::apply(Asset& asset, Sampler& sampler,
- F32 time)
- {
- Node& node = asset.mNodes[mTarget.mNode];
- U32 frame_idx;
- F32 t;
- sampler.getFrameInfo(asset, time, frame_idx, t);
- if (sampler.mFrameTimes.size() == 1)
- {
- node.setTranslation(mTranslations[0]);
- }
- else
- {
- // Interpolate
- const glh::vec3f& v0 = mTranslations[frame_idx];
- const glh::vec3f& v1 = mTranslations[frame_idx + 1];
- glh::vec3f vf = v0 + t * (v1 - v0);
- node.setTranslation(vf);
- }
- }
- void Animation::ScaleChannel::allocateGLResources(Asset& asset,
- Animation::Sampler& sampler)
- {
- Accessor& accessor = asset.mAccessors[sampler.mOutput];
- copy(asset, accessor, mScales);
- }
- void Animation::ScaleChannel::apply(Asset& asset, Sampler& sampler, F32 time)
- {
- Node& node = asset.mNodes[mTarget.mNode];
- U32 frame_idx;
- F32 t;
- sampler.getFrameInfo(asset, time, frame_idx, t);
- if (sampler.mFrameTimes.size() == 1)
- {
- node.setScale(mScales[0]);
- }
- else
- {
- // Interpolate
- const glh::vec3f& v0 = mScales[frame_idx];
- const glh::vec3f& v1 = mScales[frame_idx + 1];
- glh::vec3f vf = v0 + t * (v1 - v0);
- node.setScale(vf);
- }
- }
- const Animation& Animation::operator=(const tinygltf::Animation& src)
- {
- mName = src.name;
- mSamplers.resize(src.samplers.size());
- for (U32 i = 0; i < src.samplers.size(); ++i)
- {
- mSamplers[i] = src.samplers[i];
- }
- for (U32 i = 0; i < src.channels.size(); ++i)
- {
- if (src.channels[i].target_path == "rotation")
- {
- mRotationChannels.push_back(RotationChannel());
- mRotationChannels.back() = src.channels[i];
- }
- if (src.channels[i].target_path == "translation")
- {
- mTranslationChannels.push_back(TranslationChannel());
- mTranslationChannels.back() = src.channels[i];
- }
- if (src.channels[i].target_path == "scale")
- {
- mScaleChannels.push_back(ScaleChannel());
- mScaleChannels.back() = src.channels[i];
- }
- }
- return *this;
- }
- ///////////////////////////////////////////////////////////////////////////////
- // LLGLTF::Skin class
- ///////////////////////////////////////////////////////////////////////////////
- // Note: this should be in llgltfasset.cpp, but for some reason copy() is not
- // found when placed over there... *TODO: investigate and move this method
- // where it does belong ! HB
- void Skin::allocateGLResources(Asset& asset)
- {
- if (mInverseBindMatrices != INVALID_INDEX)
- {
- Accessor& accessor = asset.mAccessors[mInverseBindMatrices];
- copy(asset, accessor, mInverseBindMatricesData);
- }
- }
|