Skip to content

Commit 3ad3e9c

Browse files
authored
Merge pull request #14 from mrehayden1/feature/animations
Animation support.
2 parents c5d8a96 + c5c363b commit 3ad3e9c

File tree

4 files changed

+133
-0
lines changed

4 files changed

+133
-0
lines changed

src/Text/GLTF/Loader/Gltf.hs

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,10 @@ module Text.GLTF.Loader.Gltf
22
( -- * Data constructors
33
Gltf (..),
44
Asset (..),
5+
Animation (..),
6+
Channel (..),
7+
ChannelSamplerInterpolation (..),
8+
ChannelSamplerOutput (..),
59
Image (..),
610
MagFilter (..),
711
MinFilter (..),
@@ -106,6 +110,7 @@ import RIO
106110
-- | The root data type for a glTF asset
107111
data Gltf = Gltf
108112
{ gltfAsset :: Asset,
113+
gltfAnimations :: Vector Animation,
109114
gltfImages :: Vector Image,
110115
gltfMaterials :: Vector Material,
111116
gltfMeshes :: Vector Mesh,
@@ -129,6 +134,16 @@ data Asset = Asset
129134
}
130135
deriving (Eq, Show)
131136

137+
-- | Keyframe animations for tranforming and morphing scene nodes
138+
data Animation = Animation
139+
{ -- | Defines the animation keyframes for up to one of each from translation
140+
-- , rotation, scale and morph weights.
141+
animationChannels :: Vector Channel,
142+
-- | The user-defined name of this object.
143+
animationName :: Maybe Text
144+
}
145+
deriving (Eq, Show)
146+
132147
-- | Image data used to create a texture.
133148
data Image = Image
134149
{ -- | The binary data of the image
@@ -320,6 +335,32 @@ data TextureInfo = TextureInfo
320335
}
321336
deriving (Eq, Show)
322337

338+
data Channel = Channel
339+
{ -- | The target node to apply this channel of the animation to.
340+
channelTargetNode :: Maybe Int,
341+
-- | The interpolation to use for inputs between each animation keyframe
342+
-- sample.
343+
channelSamplerInterpolation :: ChannelSamplerInterpolation,
344+
-- | The timestamps of each of the animation's keyframes.
345+
channelSamplerInputs :: Vector Float,
346+
-- | The values representing the animated property of each keyframe.
347+
channelSamplerOutputs :: ChannelSamplerOutput
348+
}
349+
deriving (Eq, Show)
350+
351+
data ChannelSamplerOutput
352+
= MorphTargetWeights (Vector Float)
353+
| Rotation (Vector (Quaternion Float))
354+
| Scale (Vector (V3 Float))
355+
| Translation (Vector (V3 Float))
356+
deriving (Eq, Show)
357+
358+
data ChannelSamplerInterpolation
359+
= CubicSpline
360+
| Linear
361+
| Step
362+
deriving (Eq, Show)
363+
323364
-- | Reference to a normal map texture
324365
data NormalTextureInfo = NormalTextureInfo
325366
{ -- | The index of the texture.

src/Text/GLTF/Loader/Internal/Adapter.hs

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ module Text.GLTF.Loader.Internal.Adapter
88
runAdapter,
99
adaptGltf,
1010
adaptAsset,
11+
adaptAnimations,
1112
adaptImages,
1213
adaptMaterials,
1314
adaptMeshes,
@@ -33,6 +34,7 @@ import Text.GLTF.Loader.Internal.MonadAdapter
3334

3435
import qualified Codec.GlTF as GlTF
3536
import qualified Codec.GlTF.Asset as Asset
37+
import qualified Codec.GlTF.Animation as Animation
3638
import qualified Codec.GlTF.Image as Image
3739
import qualified Codec.GlTF.Material as Material
3840
import qualified Codec.GlTF.Mesh as Mesh
@@ -77,12 +79,14 @@ adaptGltf :: Adapter Gltf
7779
adaptGltf = do
7880
GlTF.GlTF{..} <- getGltf
7981

82+
gltfAnimations <- adaptAnimations animations
8083
gltfImages <- adaptImages images
8184
gltfMeshes <- adaptMeshes meshes
8285

8386
return
8487
$ Gltf
8588
{ gltfAsset = adaptAsset asset,
89+
gltfAnimations = gltfAnimations,
8690
gltfImages = gltfImages,
8791
gltfMaterials = adaptMaterials materials,
8892
gltfMeshes = gltfMeshes,
@@ -101,6 +105,51 @@ adaptAsset Asset.Asset{..} =
101105
assetMinVersion = minVersion
102106
}
103107

108+
adaptAnimations
109+
:: Maybe (Vector Animation.Animation)
110+
-> Adapter (Vector Animation)
111+
adaptAnimations = maybe (return mempty) (mapM adaptAnimation)
112+
113+
adaptAnimation :: Animation.Animation -> Adapter Animation
114+
adaptAnimation Animation.Animation{..} = do
115+
gltfChannels <- mapM (adaptAnimationChannel samplers) channels
116+
return
117+
$ Animation
118+
{ animationChannels = gltfChannels,
119+
animationName = name
120+
}
121+
122+
adaptAnimationChannel
123+
:: Vector Animation.AnimationSampler
124+
-> Animation.AnimationChannel
125+
-> Adapter Channel
126+
adaptAnimationChannel samplers Animation.AnimationChannel{..} = do
127+
gltf <- getGltf
128+
buffers <- getBuffers
129+
let Animation.AnimationSampler{ input, interpolation, output } =
130+
samplers ! Animation.unAnimationSamplerIx sampler
131+
Animation.AnimationChannelTarget{ node, path } = target
132+
outputs = case path of
133+
Animation.ROTATION -> Rotation $ animationSamplerRotationOutputs gltf buffers output
134+
Animation.SCALE -> Scale $ animationSamplerScaleOutputs gltf buffers output
135+
Animation.TRANSLATION -> Translation $ animationSamplerTranslationOutputs gltf buffers output
136+
Animation.WEIGHTS -> MorphTargetWeights $ animationSamplerWeightsOutputs gltf buffers output
137+
_ -> error $ "Invalid Channel path: " <> show path
138+
return
139+
$ Channel
140+
{ channelTargetNode = fmap Node.unNodeIx node,
141+
channelSamplerInterpolation = adaptInterpolation interpolation,
142+
channelSamplerInputs = animationSamplerInputs gltf buffers input,
143+
channelSamplerOutputs = outputs
144+
}
145+
146+
adaptInterpolation :: Animation.AnimationSamplerInterpolation -> ChannelSamplerInterpolation
147+
adaptInterpolation Animation.CUBICSPLINE = CubicSpline
148+
adaptInterpolation Animation.LINEAR = Linear
149+
adaptInterpolation Animation.STEP = Step
150+
adaptInterpolation (Animation.AnimationSamplerInterpolation interpolation) =
151+
error $ "Invalid ChannelSamplerInterpolation: " <> show interpolation
152+
104153
adaptImages :: Maybe (Vector Image.Image) -> Adapter (Vector Image)
105154
adaptImages codecImages = do
106155
imageData <- getImages

src/Text/GLTF/Loader/Internal/BufferAccessor.hs

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,11 @@ module Text.GLTF.Loader.Internal.BufferAccessor
77
loadImages,
88

99
-- * Deserializing Accessors
10+
animationSamplerInputs,
11+
animationSamplerRotationOutputs,
12+
animationSamplerScaleOutputs,
13+
animationSamplerTranslationOutputs,
14+
animationSamplerWeightsOutputs,
1015
vertexIndices,
1116
vertexPositions,
1217
vertexNormals,
@@ -88,6 +93,35 @@ loadImages GlTF{images = images} basePath = do
8893
let fallbackImageData = return $ maybe NoImageData ImageBufferView bufferView
8994
maybe fallbackImageData (fmap ImageData . loadUri' basePath) uri
9095

96+
animationSamplerInputs :: GlTF -> Vector GltfBuffer -> AccessorIx -> Vector Float
97+
animationSamplerInputs = readBufferWithGet (getScalar getFloat)
98+
99+
animationSamplerRotationOutputs :: GlTF -> Vector GltfBuffer -> AccessorIx -> Vector (Quaternion Float)
100+
animationSamplerRotationOutputs gltf buffers' accessorId =
101+
fromMaybe (error "Invalid animation sampler output component type.") $ do
102+
buffer@BufferAccessor{componentType = componentType} <-
103+
bufferAccessor gltf buffers' accessorId
104+
105+
case componentType of
106+
FLOAT -> Just . readFromBuffer (Proxy @(Quaternion Float)) (getQuaternion getFloat) $ buffer
107+
_ -> Nothing
108+
109+
animationSamplerScaleOutputs :: GlTF -> Vector GltfBuffer -> AccessorIx -> Vector (V3 Float)
110+
animationSamplerScaleOutputs = readBufferWithGet (getVec3 getFloat)
111+
112+
animationSamplerTranslationOutputs :: GlTF -> Vector GltfBuffer -> AccessorIx -> Vector (V3 Float)
113+
animationSamplerTranslationOutputs = readBufferWithGet (getVec3 getFloat)
114+
115+
animationSamplerWeightsOutputs :: GlTF -> Vector GltfBuffer -> AccessorIx -> Vector Float
116+
animationSamplerWeightsOutputs gltf buffers' accessorId =
117+
fromMaybe (error "Invalid animation sampler output component type.") $ do
118+
buffer@BufferAccessor{componentType = componentType} <-
119+
bufferAccessor gltf buffers' accessorId
120+
121+
case componentType of
122+
FLOAT -> Just . readFromBuffer (Proxy @Float) (getScalar getFloat) $ buffer
123+
_ -> Nothing
124+
91125
-- | Decode vertex indices
92126
vertexIndices :: GlTF -> Vector GltfBuffer -> AccessorIx -> Vector Word32
93127
vertexIndices gltf buffers' accessorId =

src/Text/GLTF/Loader/Internal/Decoders.hs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ module Text.GLTF.Loader.Internal.Decoders
1818
getMat2,
1919
getMat3,
2020
getMat4,
21+
getQuaternion,
2122

2223
-- * GLTF Component Type decoders
2324
getByte,
@@ -121,6 +122,14 @@ getMat4 getter =
121122

122123
{- FOURMOLU_DISABLE -}
123124

125+
-- | Quaternion binary decoder
126+
getQuaternion :: Get a -> Get (Vector (Quaternion a))
127+
getQuaternion getter = getVector $ do
128+
v3 <- V3 <$> getter <*> getter <*> getter
129+
Quaternion
130+
<$> getter
131+
<*> pure v3
132+
124133
-- | Byte binary decoder
125134
getByte :: Get Int8
126135
getByte = getInt8

0 commit comments

Comments
 (0)