Skip to content

Animation support. #14

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
May 10, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
41 changes: 41 additions & 0 deletions src/Text/GLTF/Loader/Gltf.hs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,10 @@ module Text.GLTF.Loader.Gltf
( -- * Data constructors
Gltf (..),
Asset (..),
Animation (..),
Channel (..),
ChannelSamplerInterpolation (..),
ChannelSamplerOutput (..),
Image (..),
MagFilter (..),
MinFilter (..),
Expand Down Expand Up @@ -106,6 +110,7 @@ import RIO
-- | The root data type for a glTF asset
data Gltf = Gltf
{ gltfAsset :: Asset,
gltfAnimations :: Vector Animation,
gltfImages :: Vector Image,
gltfMaterials :: Vector Material,
gltfMeshes :: Vector Mesh,
Expand All @@ -129,6 +134,16 @@ data Asset = Asset
}
deriving (Eq, Show)

-- | Keyframe animations for tranforming and morphing scene nodes
data Animation = Animation
{ -- | Defines the animation keyframes for up to one of each from translation
-- , rotation, scale and morph weights.
animationChannels :: Vector Channel,
-- | The user-defined name of this object.
animationName :: Maybe Text
}
deriving (Eq, Show)

-- | Image data used to create a texture.
data Image = Image
{ -- | The binary data of the image
Expand Down Expand Up @@ -320,6 +335,32 @@ data TextureInfo = TextureInfo
}
deriving (Eq, Show)

data Channel = Channel
{ -- | The target node to apply this channel of the animation to.
channelTargetNode :: Maybe Int,
-- | The interpolation to use for inputs between each animation keyframe
-- sample.
channelSamplerInterpolation :: ChannelSamplerInterpolation,
-- | The timestamps of each of the animation's keyframes.
channelSamplerInputs :: Vector Float,
-- | The values representing the animated property of each keyframe.
channelSamplerOutputs :: ChannelSamplerOutput
}
deriving (Eq, Show)

data ChannelSamplerOutput
= MorphTargetWeights (Vector Float)
| Rotation (Vector (Quaternion Float))
| Scale (Vector (V3 Float))
| Translation (Vector (V3 Float))
deriving (Eq, Show)

data ChannelSamplerInterpolation
= CubicSpline
| Linear
| Step
deriving (Eq, Show)

-- | Reference to a normal map texture
data NormalTextureInfo = NormalTextureInfo
{ -- | The index of the texture.
Expand Down
49 changes: 49 additions & 0 deletions src/Text/GLTF/Loader/Internal/Adapter.hs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ module Text.GLTF.Loader.Internal.Adapter
runAdapter,
adaptGltf,
adaptAsset,
adaptAnimations,
adaptImages,
adaptMaterials,
adaptMeshes,
Expand All @@ -33,6 +34,7 @@ import Text.GLTF.Loader.Internal.MonadAdapter

import qualified Codec.GlTF as GlTF
import qualified Codec.GlTF.Asset as Asset
import qualified Codec.GlTF.Animation as Animation
import qualified Codec.GlTF.Image as Image
import qualified Codec.GlTF.Material as Material
import qualified Codec.GlTF.Mesh as Mesh
Expand Down Expand Up @@ -77,12 +79,14 @@ adaptGltf :: Adapter Gltf
adaptGltf = do
GlTF.GlTF{..} <- getGltf

gltfAnimations <- adaptAnimations animations
gltfImages <- adaptImages images
gltfMeshes <- adaptMeshes meshes

return
$ Gltf
{ gltfAsset = adaptAsset asset,
gltfAnimations = gltfAnimations,
gltfImages = gltfImages,
gltfMaterials = adaptMaterials materials,
gltfMeshes = gltfMeshes,
Expand All @@ -101,6 +105,51 @@ adaptAsset Asset.Asset{..} =
assetMinVersion = minVersion
}

adaptAnimations
:: Maybe (Vector Animation.Animation)
-> Adapter (Vector Animation)
adaptAnimations = maybe (return mempty) (mapM adaptAnimation)

adaptAnimation :: Animation.Animation -> Adapter Animation
adaptAnimation Animation.Animation{..} = do
gltfChannels <- mapM (adaptAnimationChannel samplers) channels
return
$ Animation
{ animationChannels = gltfChannels,
animationName = name
}

adaptAnimationChannel
:: Vector Animation.AnimationSampler
-> Animation.AnimationChannel
-> Adapter Channel
adaptAnimationChannel samplers Animation.AnimationChannel{..} = do
gltf <- getGltf
buffers <- getBuffers
let Animation.AnimationSampler{ input, interpolation, output } =
samplers ! Animation.unAnimationSamplerIx sampler
Animation.AnimationChannelTarget{ node, path } = target
outputs = case path of
Animation.ROTATION -> Rotation $ animationSamplerRotationOutputs gltf buffers output
Animation.SCALE -> Scale $ animationSamplerScaleOutputs gltf buffers output
Animation.TRANSLATION -> Translation $ animationSamplerTranslationOutputs gltf buffers output
Animation.WEIGHTS -> MorphTargetWeights $ animationSamplerWeightsOutputs gltf buffers output
_ -> error $ "Invalid Channel path: " <> show path
return
$ Channel
{ channelTargetNode = fmap Node.unNodeIx node,
channelSamplerInterpolation = adaptInterpolation interpolation,
channelSamplerInputs = animationSamplerInputs gltf buffers input,
channelSamplerOutputs = outputs
}

adaptInterpolation :: Animation.AnimationSamplerInterpolation -> ChannelSamplerInterpolation
adaptInterpolation Animation.CUBICSPLINE = CubicSpline
adaptInterpolation Animation.LINEAR = Linear
adaptInterpolation Animation.STEP = Step
adaptInterpolation (Animation.AnimationSamplerInterpolation interpolation) =
error $ "Invalid ChannelSamplerInterpolation: " <> show interpolation

adaptImages :: Maybe (Vector Image.Image) -> Adapter (Vector Image)
adaptImages codecImages = do
imageData <- getImages
Expand Down
34 changes: 34 additions & 0 deletions src/Text/GLTF/Loader/Internal/BufferAccessor.hs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,11 @@ module Text.GLTF.Loader.Internal.BufferAccessor
loadImages,

-- * Deserializing Accessors
animationSamplerInputs,
animationSamplerRotationOutputs,
animationSamplerScaleOutputs,
animationSamplerTranslationOutputs,
animationSamplerWeightsOutputs,
vertexIndices,
vertexPositions,
vertexNormals,
Expand Down Expand Up @@ -88,6 +93,35 @@ loadImages GlTF{images = images} basePath = do
let fallbackImageData = return $ maybe NoImageData ImageBufferView bufferView
maybe fallbackImageData (fmap ImageData . loadUri' basePath) uri

animationSamplerInputs :: GlTF -> Vector GltfBuffer -> AccessorIx -> Vector Float
animationSamplerInputs = readBufferWithGet (getScalar getFloat)

animationSamplerRotationOutputs :: GlTF -> Vector GltfBuffer -> AccessorIx -> Vector (Quaternion Float)
animationSamplerRotationOutputs gltf buffers' accessorId =
fromMaybe (error "Invalid animation sampler output component type.") $ do
buffer@BufferAccessor{componentType = componentType} <-
bufferAccessor gltf buffers' accessorId

case componentType of
FLOAT -> Just . readFromBuffer (Proxy @(Quaternion Float)) (getQuaternion getFloat) $ buffer
_ -> Nothing

animationSamplerScaleOutputs :: GlTF -> Vector GltfBuffer -> AccessorIx -> Vector (V3 Float)
animationSamplerScaleOutputs = readBufferWithGet (getVec3 getFloat)

animationSamplerTranslationOutputs :: GlTF -> Vector GltfBuffer -> AccessorIx -> Vector (V3 Float)
animationSamplerTranslationOutputs = readBufferWithGet (getVec3 getFloat)

animationSamplerWeightsOutputs :: GlTF -> Vector GltfBuffer -> AccessorIx -> Vector Float
animationSamplerWeightsOutputs gltf buffers' accessorId =
fromMaybe (error "Invalid animation sampler output component type.") $ do
buffer@BufferAccessor{componentType = componentType} <-
bufferAccessor gltf buffers' accessorId

case componentType of
FLOAT -> Just . readFromBuffer (Proxy @Float) (getScalar getFloat) $ buffer
_ -> Nothing

-- | Decode vertex indices
vertexIndices :: GlTF -> Vector GltfBuffer -> AccessorIx -> Vector Word32
vertexIndices gltf buffers' accessorId =
Expand Down
9 changes: 9 additions & 0 deletions src/Text/GLTF/Loader/Internal/Decoders.hs
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ module Text.GLTF.Loader.Internal.Decoders
getMat2,
getMat3,
getMat4,
getQuaternion,

-- * GLTF Component Type decoders
getByte,
Expand Down Expand Up @@ -121,6 +122,14 @@ getMat4 getter =

{- FOURMOLU_DISABLE -}

-- | Quaternion binary decoder
getQuaternion :: Get a -> Get (Vector (Quaternion a))
getQuaternion getter = getVector $ do
v3 <- V3 <$> getter <*> getter <*> getter
Quaternion
<$> getter
<*> pure v3

-- | Byte binary decoder
getByte :: Get Int8
getByte = getInt8
Expand Down
Loading