Polyphase Game Engine
Loading...
Searching...
No Matches
SkeletalMesh3d.h
Go to the documentation of this file.
1#pragma once
2
3#include "Nodes/3D/Mesh3d.h"
4#include "AssetRef.h"
5#include "Vertex.h"
6// std::vector<Animation> mBoundExternalAnims below needs the full Animation
7// type, so we can't fall back on the forward declarations the file used to
8// rely on for AnimEvent / Channel / Animation.
10
11class BoneMaskAsset;
12
14{
15 One,
16 Four,
17 Num
18};
19
28
29// How a slot's animation contributes to the per-bone blend.
30// Replace : standard weighted lerp into the accumulator (default).
31// Additive: the slot's pose is interpreted as a delta from bind pose;
32// that delta is scaled by mWeight and composed on top of the
33// accumulator. Used for hit reactions, recoil, breathing,
34// lean-into-turn — anything you want to layer on a base anim.
35enum class AnimLayerMode
36{
37 Replace,
39
40 Count
41};
42
43class SkeletalMesh;
44struct AnimEvent;
45struct Channel;
46struct Animation;
47
49{
50 std::string mName;
51 float mTime = 0.0f;
52 float mSpeed = 1.0f;
53 float mWeight = 0.0f;
54 int32_t mSlot = 0;
55 bool mLoop = false;
56
57 // Optional bone mask. When valid, only bones marked in the mask's
58 // resolved bitset receive this slot's contribution; the rest stay at
59 // whatever the lower slots (or bind pose) provided.
61
62 // Weight fade. Engaged when mWeightFadeRate != 0; on each tick mWeight
63 // advances toward mWeightTarget by mWeightFadeRate * dt and clamps. When
64 // the target is 0 and reached, the slot self-removes.
65 float mWeightTarget = -1.0f;
66 float mWeightFadeRate = 0.0f;
67
69};
70
72{
73 std::string mName;
74 std::string mDependentAnim;
75 float mTime = 0.0f;
76 float mSpeed = 1.0f;;
77 float mWeight = 0.0f;
78 bool mLoop = false;
79 int32_t mSlot = -1;
80};
81
82typedef void(*AnimEventHandlerFP)(const AnimEvent& animEvent);
83
84// A script callback registered to fire when playback of a given clip crosses a
85// normalized (0..1) point in its timeline. Unlike the Event_* anim-event system
86// -- which needs a bone named Event_Foo authored in the DCC and the rig
87// re-exported -- notifies are registered at runtime, so gameplay beats
88// (swap the sword into the hand, spawn a footstep) can be retimed from script.
90{
91 std::string mAnimName;
92 float mNormalizedTime = 0.0f;
94 int32_t mHandle = -1;
95};
96
97// Local, decomposed (TRS) bone pose shared between SkeletalMesh3D's animation
98// blend loop and any registered ISkeletalPoseModifier. Kept in the public header
99// so native addons (e.g. the procedural-rig / jiggle-bones addon) can read and
100// mutate the animated local pose after blending and before it is composed into
101// bone matrices. Field layout must stay in sync with the file-local
102// DecompTransform alias in SkeletalMesh3d.cpp.
104{
105 glm::vec3 mPosition = { 0.0f, 0.0f, 0.0f };
106 glm::quat mRotation = { 0.0f, 0.0f, 0.0f, 1.0f };
107 glm::vec3 mScale = { 1.0f, 1.0f, 1.0f };
108 bool mValid = false;
109};
110
111// Hook for procedural pose layers (spring / jiggle bones, spline IK, ...) that
112// run AFTER animation blending / masking / additive layering and BEFORE the
113// local pose is finalized into bone matrices. Implementers modify the decomposed
114// local pose in place; they must never touch finalized skinning matrices.
115// Register/unregister on the target mesh via SkeletalMesh3D::RegisterPoseModifier.
117{
118public:
119 virtual ~ISkeletalPoseModifier() = default;
120
121 virtual void ModifySkeletalPose(
122 class SkeletalMesh3D* component,
123 class SkeletalMesh* mesh,
124 std::vector<SkeletalLocalPoseTransform>& localPose,
125 float deltaTime) = 0;
126};
127
129{
130public:
131
133
136
137 virtual const char* GetTypeName() const override;
138 virtual void GatherProperties(std::vector<Property>& outProps) override;
139
140 virtual void Create() override;
141 virtual void Destroy() override;
142 SkeletalMeshCompResource* GetResource();
143
144 virtual void Tick(float deltaTime) override;
145 virtual void EditorTick(float deltaTime) override;
146
147 virtual bool IsStaticMesh3D() const override;
148 virtual bool IsSkeletalMesh3D() const override;
149
150 void SetSkeletalMesh(SkeletalMesh* skeletalMesh);
151 SkeletalMesh* GetSkeletalMesh();
152
153 void PlayAnimation(const char* animName, bool loop, float speed = 1.0f, float weight = 1.0f, int32_t priority = -1);
154 // Start `animName` on `slot`, restricted to the bones marked by `mask`.
155 // mask=nullptr is equivalent to PlayAnimation (full body). The slot's
156 // weight is the maximum contribution against lower slots; weight=1 and
157 // mask=UpperBody means upper-body bones are 100% driven by this clip
158 // while lower bones stay on whatever slot 0 (or bind pose) provided.
159 void PlayAnimationMasked(const char* animName, int32_t slot, BoneMaskAsset* mask,
160 bool loop, float speed = 1.0f, float weight = 1.0f);
161 // Start `animName` on `slot` as an additive layer — the slot's pose is
162 // interpreted as a delta from bind pose and composed on top of lower
163 // slots. Mask gates which bones receive the delta. Use for hit reactions,
164 // recoil, breathing, lean-into-turn over a base run/idle.
165 void PlayAnimationAdditive(const char* animName, int32_t slot, BoneMaskAsset* mask,
166 bool loop, float speed = 1.0f, float weight = 1.0f);
167 // Replace the bone mask on an already-playing slot. Pass nullptr to clear.
168 void SetSlotMask(int32_t slot, BoneMaskAsset* mask);
169 void SetSlotLayerMode(int32_t slot, AnimLayerMode mode);
170 // Snap a slot's weight without easing. Clamped to [0, 1].
171 void SetSlotWeight(int32_t slot, float weight);
172 // Fade a slot's weight from its current value to `targetWeight` over
173 // `seconds` (linear). If targetWeight == 0 and the fade completes, the
174 // slot self-removes.
175 void FadeSlotWeight(int32_t slot, float targetWeight, float seconds);
176 void QueueAnimation(const char* animName, bool loop, const char* targetAnim = nullptr, float speed = 1.0f, float weight = 1.0f, int32_t priority = -1);
177 void StopAnimation(const char* animName, bool cancelQueued = false);
178 void StopAllAnimations(bool cancelQueued = false);
179 void CancelQueuedAnimation(const char* animName);
180 void CancelAllQueuedAnimations();
181 bool IsAnimationPlaying(const char* animName);
182 void ResetAnimation();
183 float GetAnimationSpeed() const;
184 void SetAnimationSpeed(float speed);
185
186 void SetAnimationPaused(bool paused);
187 bool IsAnimationPaused() const;
188
189 void SetInheritPose(bool inherit);
190 bool IsInheritPoseEnabled() const;
191
192 void SetBoundsRadiusOverride(float radius);
193 float GetBoundsRadiusOverride() const;
194
195 bool HasAnimatedThisFrame() const;
196
197 ActiveAnimation* FindActiveAnimation(const char* animName);
198 std::vector<ActiveAnimation>& GetActiveAnimations();
199
200 QueuedAnimation* FindQueuedAnimation(const char* animName, const char* dependName = nullptr);
201 std::vector<QueuedAnimation>& GetQueuedAnimations();
202
203 glm::mat4 GetBoneTransform(const std::string& name) const;
204 glm::vec3 GetBonePosition(const std::string& name) const;
205 glm::quat GetBoneRotationQuat(const std::string& name) const;
206 glm::vec3 GetBoneRotationEuler(const std::string& name) const;
207 glm::vec3 GetBoneScale(const std::string& name) const;
208
209 glm::mat4 GetBoneTransform(int32_t index) const;
210 glm::vec3 GetBonePosition(int32_t boneIndex) const;
211 glm::quat GetBoneRotationQuat(int32_t boneIndex) const;
212 glm::vec3 GetBoneRotationEuler(int32_t boneIndex) const;
213 glm::vec3 GetBoneScale(int32_t boneIndex) const;
214
215 void SetBoneTransform(int32_t boneIndex, const glm::mat4& transform);
216 void SetBonePosition(int32_t boneIndex, glm::vec3 position);
217 void SetBoneRotation(int32_t boneIndex, glm::vec3 rotation);
218 void SetBoneScale(int32_t boneIndex, glm::vec2 scale);
219
220 uint32_t GetNumBones() const;
221 BoneInfluenceMode GetBoneInfluenceMode() const;
222
223 // Bone world matrix: node world * skinning matrix * bind pose. This is the
224 // single source of truth for "where is bone N right now"; GetBonePosition /
225 // RotationQuat / Scale below are decompositions of it.
226 glm::mat4 GetBoneWorldMatrix(int32_t boneIndex) const;
227
228 // Named sockets. A socket is a bone plus a constant authored offset; see
229 // MeshSocket. These return world space, so effects can be spawned at a
230 // socket without reparenting anything to it.
231 int32_t FindSocketIndex(const std::string& name) const;
232 uint32_t GetNumSockets() const;
233 std::string GetSocketName(uint32_t index) const;
234 glm::mat4 GetSocketTransform(const std::string& name) const;
235 glm::vec3 GetSocketPosition(const std::string& name) const;
236 glm::quat GetSocketRotationQuat(const std::string& name) const;
237 glm::vec3 GetSocketRotationEuler(const std::string& name) const;
238
239 // Playback time of an active clip. Returns -1 when the clip isn't playing.
240 // Time is in seconds; normalized time is 0..1 across the clip's duration.
241 float GetAnimationTime(const char* animName) const;
242 float GetAnimationNormalizedTime(const char* animName);
243 void SetAnimationTime(const char* animName, float seconds);
244 void SetAnimationNormalizedTime(const char* animName, float normalizedTime);
245 float GetAnimationDurationSeconds(const char* animName);
246
247 // Fire `callback` each time playback of `animName` crosses `normalizedTime`.
248 // Returns a handle for removal. Multiple notifies may share a clip and time.
249 int32_t AddAnimationNotify(const char* animName, float normalizedTime, const ScriptFunc& callback);
250 void RemoveAnimationNotify(int32_t handle);
251 void ClearAnimationNotifies(const char* animName = nullptr);
252
253 AnimationUpdateMode GetAnimationUpdateMode() const;
254 void SetAnimationUpdateMode(AnimationUpdateMode mode);
255
256 Vertex* GetSkinnedVertices();
257 uint32_t GetNumSkinnedVertices();
258
259 virtual Material* GetMaterial() override;
260 virtual void Render() override;
261
262 // Per-section material slot accessors. A "slot" maps 1:1 onto
263 // SkeletalMesh::GetSection(i). Resolution order for a slot:
264 // 1. component override (mSectionMaterialOverrides[slot])
265 // 2. section's own material (SkeletalMesh::GetSection(slot).mMaterial)
266 // 3. legacy mMaterialOverride (whole-mesh override)
267 // 4. legacy mesh-default mMaterial
268 // 5. renderer default material
269 uint32_t GetNumMaterialSlots() const;
270 Material* GetMaterialSlot(uint32_t slot) const;
271 void SetMaterialSlot(uint32_t slot, Material* material);
272 int32_t FindMaterialSlot(const std::string& sectionName) const;
273
274 void UpdateAnimation(float deltaTime, bool updateBones);
275
276 virtual Bounds GetLocalBounds() const override;
277 virtual AABB GetLocalAABB() const override;
278
279 int32_t FindBoneIndex(const std::string& name) const;
280
281 void SetAnimEventHandler(AnimEventHandlerFP handler);
282 AnimEventHandlerFP GetAnimEventHandler();
283 void SetScriptAnimEventHandler(const ScriptFunc& func);
284
285 // Procedural pose modifiers (spring / jiggle bones, spline IK, ...).
286 // Registered modifiers run each animation update after blending and before
287 // the local decomposed pose is composed into bone matrices. Registration is
288 // idempotent; unregister on modifier destruction / addon hot-reload to avoid
289 // a dangling pointer. See ISkeletalPoseModifier.
290 void RegisterPoseModifier(ISkeletalPoseModifier* modifier);
291 void UnregisterPoseModifier(ISkeletalPoseModifier* modifier);
292
293protected:
294
295 static bool HandlePropChange(Datum* datum, uint32_t index, const void* newValue);
296
297 void TickCommon(float deltaTime);
298
299 glm::vec3 InterpolateScale(float time, const Channel& channel);
300 glm::quat InterpolateRotation(float time, const Channel& channel);
301 glm::vec3 InterpolatePosition(float time, const Channel& channel);
302 void DetectTriggeredAnimEvents(
303 const Animation& animation,
304 float prevTickTime,
305 float tickTime,
306 float animationSpeed,
307 std::vector<AnimEvent>& outEvents);
308
309 uint32_t FindScaleIndex(float time, const Channel& channel);
310 uint32_t FindRotationIndex(float time, const Channel& channel);
311 uint32_t FindPositionIndex(float time, const Channel& channel);
312
313 void UpdateAttachedChildren(float deltaTime);
314 void CpuSkinVertices();
315
316 // Collects notifies whose normalized threshold lies in the interval the slot
317 // just advanced through. Appends to mPendingNotifies; dispatch happens after
318 // the blend loop so a callback can safely mutate mActiveAnimations.
319 void DetectTriggeredNotifies(const ActiveAnimation& active, float prevTime, float curTime, float durationSeconds);
320 void DispatchPendingNotifies();
321 void WarnIfNotifiesCantFire();
322
323 // External SkeletalAnimationAsset references. Resolution order in
324 // FindAnimation: embedded mesh animations first (preserves existing
325 // PlayAnimation behaviour), then animation-lookup-mesh chain, then
326 // bound external assets. Channels in external assets are keyed by bone
327 // NAME and get resolved into target-mesh bone indices lazily into the
328 // mBoundExternalAnims cache below.
329 const std::vector<SkeletalAnimationRef>& GetAnimationAssets() const { return mAnimationAssets; }
330 std::vector<SkeletalAnimationRef>& GetAnimationAssetsMutable();
331 void AddAnimationAsset(class SkeletalAnimationAsset* asset);
332 void RemoveAnimationAsset(class SkeletalAnimationAsset* asset);
333
334 const Animation* FindAnimation(const char* animName);
335 void InvalidateAnimationBindings();
336
338 std::vector<glm::mat4> mBoneMatrices;
339 std::vector<ISkeletalPoseModifier*> mPoseModifiers;
340 std::vector<Vertex> mSkinnedVertices; // Used by CPU skinning only.
341 std::vector<MaterialRef> mSectionMaterialOverrides;
342 std::vector<SkeletalAnimationRef> mAnimationAssets;
343
344 // Lazy cache of external animation clips with channel bone indices
345 // resolved against the currently assigned target mesh. Rebuilt on
346 // first FindAnimation after the mesh or asset list changes.
347 std::vector<Animation> mBoundExternalAnims;
348 bool mAnimBindingsValid = false;
349
351
352 // Runtime-registered animation notifies. mPendingNotifies is a member rather
353 // than a file-static (the pattern the legacy anim-event path uses) because
354 // UpdateAnimation re-enters itself through the inherit-pose path and a
355 // callback can re-enter too -- a shared static would corrupt across that.
356 std::vector<AnimationNotify> mAnimationNotifies;
357 std::vector<ScriptFunc> mPendingNotifies;
358 int32_t mNextNotifyHandle = 1;
359 bool mWarnedNotifyUpdateMode = false;
360 std::string mDefaultAnimation;
361 float mAnimationSpeed = 1.0f;
362 std::vector<ActiveAnimation> mActiveAnimations;
363 std::vector<QueuedAnimation> mQueuedAnimations;
364 float mBoundsRadiusOverride = 0.0f;
369
372
373 // Graphics Resource
375};
#define POLYPHASE_API
Definition PolyphaseAPI.h:31
AnimationUpdateMode
Definition SkeletalMesh3d.h:21
void(* AnimEventHandlerFP)(const AnimEvent &animEvent)
Definition SkeletalMesh3d.h:82
BoneInfluenceMode
Definition SkeletalMesh3d.h:14
AnimLayerMode
Definition SkeletalMesh3d.h:36
Definition AssetRef.h:18
Definition BoneMaskAsset.h:19
Definition Datum.h:169
Definition SkeletalMesh3d.h:117
virtual ~ISkeletalPoseModifier()=default
virtual void ModifySkeletalPose(class SkeletalMesh3D *component, class SkeletalMesh *mesh, std::vector< SkeletalLocalPoseTransform > &localPose, float deltaTime)=0
Definition Material.h:48
Definition Mesh3d.h:13
Definition ScriptFunc.h:10
Definition SkeletalAnimationAsset.h:26
Definition SkeletalMesh3d.h:129
std::vector< ActiveAnimation > mActiveAnimations
Definition SkeletalMesh3d.h:362
bool mInheritPose
Definition SkeletalMesh3d.h:367
std::vector< Vertex > mSkinnedVertices
Definition SkeletalMesh3d.h:340
ScriptableFP< AnimEventHandlerFP > mAnimEventHandler
Definition SkeletalMesh3d.h:350
std::vector< glm::mat4 > mBoneMatrices
Definition SkeletalMesh3d.h:338
BoneInfluenceMode mBoneInfluenceMode
Definition SkeletalMesh3d.h:370
std::vector< Animation > mBoundExternalAnims
Definition SkeletalMesh3d.h:347
std::string mDefaultAnimation
Definition SkeletalMesh3d.h:360
bool mHasAnimatedThisFrame
Definition SkeletalMesh3d.h:368
bool mRevertToBindPose
Definition SkeletalMesh3d.h:366
std::vector< QueuedAnimation > mQueuedAnimations
Definition SkeletalMesh3d.h:363
SkeletalMeshCompResource mResource
Definition SkeletalMesh3d.h:374
std::vector< SkeletalAnimationRef > mAnimationAssets
Definition SkeletalMesh3d.h:342
std::vector< ScriptFunc > mPendingNotifies
Definition SkeletalMesh3d.h:357
AnimationUpdateMode mAnimationUpdateMode
Definition SkeletalMesh3d.h:371
std::vector< ISkeletalPoseModifier * > mPoseModifiers
Definition SkeletalMesh3d.h:339
SkeletalMeshRef mSkeletalMesh
Definition SkeletalMesh3d.h:337
std::vector< MaterialRef > mSectionMaterialOverrides
Definition SkeletalMesh3d.h:341
const std::vector< SkeletalAnimationRef > & GetAnimationAssets() const
Definition SkeletalMesh3d.h:329
DECLARE_NODE(SkeletalMesh3D, Mesh3D)
bool mAnimationPaused
Definition SkeletalMesh3d.h:365
std::vector< AnimationNotify > mAnimationNotifies
Definition SkeletalMesh3d.h:356
Definition SkeletalMesh.h:114
Definition EngineTypes.h:213
Definition SkeletalMesh3d.h:49
AssetRef mBoneMask
Definition SkeletalMesh3d.h:60
bool mLoop
Definition SkeletalMesh3d.h:55
float mWeightFadeRate
Definition SkeletalMesh3d.h:66
float mSpeed
Definition SkeletalMesh3d.h:52
int32_t mSlot
Definition SkeletalMesh3d.h:54
std::string mName
Definition SkeletalMesh3d.h:50
float mWeightTarget
Definition SkeletalMesh3d.h:65
float mTime
Definition SkeletalMesh3d.h:51
float mWeight
Definition SkeletalMesh3d.h:53
AnimLayerMode mLayerMode
Definition SkeletalMesh3d.h:68
Definition SkeletalMesh.h:60
Definition SkeletalMesh3d.h:90
int32_t mHandle
Definition SkeletalMesh3d.h:94
ScriptFunc mCallback
Definition SkeletalMesh3d.h:93
std::string mAnimName
Definition SkeletalMesh3d.h:91
float mNormalizedTime
Definition SkeletalMesh3d.h:92
Definition SkeletalMesh.h:77
Definition EngineTypes.h:204
Definition SkeletalMesh.h:69
Definition SkeletalMesh3d.h:72
bool mLoop
Definition SkeletalMesh3d.h:78
float mTime
Definition SkeletalMesh3d.h:75
std::string mName
Definition SkeletalMesh3d.h:73
std::string mDependentAnim
Definition SkeletalMesh3d.h:74
float mWeight
Definition SkeletalMesh3d.h:77
float mSpeed
Definition SkeletalMesh3d.h:76
int32_t mSlot
Definition SkeletalMesh3d.h:79
Definition ScriptFunc.h:43
Definition SkeletalMesh3d.h:104
bool mValid
Definition SkeletalMesh3d.h:108
glm::vec3 mPosition
Definition SkeletalMesh3d.h:105
glm::vec3 mScale
Definition SkeletalMesh3d.h:107
glm::quat mRotation
Definition SkeletalMesh3d.h:106
Definition GraphicsTypes.h:238
Definition Vertex.h:20