1//************************************ bs::framework - Copyright 2018 Marko Pintera **************************************//
2//*********** Licensed under the MIT license. See LICENSE.md for full terms. This notice is not to be removed. ***********//
3#include "Animation/BsAnimationManager.h"
4#include "Animation/BsAnimation.h"
5#include "Animation/BsAnimationClip.h"
6#include "Threading/BsTaskScheduler.h"
7#include "Utility/BsTime.h"
8#include "Scene/BsSceneManager.h"
9#include "Renderer/BsCamera.h"
10#include "Animation/BsMorphShapes.h"
11#include "Mesh/BsMeshData.h"
12#include "Mesh/BsMeshUtility.h"
13
14namespace bs
15{
16 AnimationManager::AnimationManager()
17 {
18 mBlendShapeVertexDesc = VertexDataDesc::create();
19 mBlendShapeVertexDesc->addVertElem(VET_FLOAT3, VES_POSITION, 1, 1);
20 mBlendShapeVertexDesc->addVertElem(VET_UBYTE4_NORM, VES_NORMAL, 1, 1);
21 }
22
23 void AnimationManager::setPaused(bool paused)
24 {
25 mPaused = paused;
26 }
27
28 void AnimationManager::setUpdateRate(UINT32 fps)
29 {
30 if (fps == 0)
31 fps = 1;
32
33 mUpdateRate = 1.0f / fps;
34 }
35
36 const EvaluatedAnimationData* AnimationManager::update(bool async)
37 {
38 // Wait for any workers to complete
39 {
40 Lock lock(mMutex);
41
42 while (mNumActiveWorkers > 0)
43 mWorkerDoneSignal.wait(lock);
44
45 // Advance the buffers (last write buffer becomes read buffer)
46 if(mSwapBuffers)
47 {
48 mPoseReadBufferIdx = (mPoseReadBufferIdx + 1) % (CoreThread::NUM_SYNC_BUFFERS + 1);
49 mPoseWriteBufferIdx = (mPoseWriteBufferIdx + 1) % (CoreThread::NUM_SYNC_BUFFERS + 1);
50
51 mSwapBuffers = false;
52 }
53 }
54
55 if(mPaused)
56 return &mAnimData[mPoseReadBufferIdx];
57
58 mAnimationTime += gTime().getFrameDelta();
59 if (mAnimationTime < mNextAnimationUpdateTime)
60 return &mAnimData[mPoseReadBufferIdx];
61
62 mNextAnimationUpdateTime = Math::floor(mAnimationTime / mUpdateRate) * mUpdateRate + mUpdateRate;
63
64 float timeDelta = mAnimationTime - mLastAnimationUpdateTime;
65 mLastAnimationUpdateTime = mAnimationTime;
66
67 // Trigger events and update attachments (for the data from the last frame)
68 if(async)
69 {
70 for (auto& anim : mAnimations)
71 {
72 anim.second->updateFromProxy();
73 anim.second->triggerEvents(mLastAnimationDeltaTime);
74 }
75 }
76
77 mLastAnimationDeltaTime = timeDelta;
78
79 // Update animation proxies from the latest data
80 mProxies.clear();
81 for (auto& anim : mAnimations)
82 {
83 anim.second->updateAnimProxy(timeDelta);
84 mProxies.push_back(anim.second->mAnimProxy);
85 }
86
87 // Build frustums for culling
88 mCullFrustums.clear();
89
90 auto& allCameras = gSceneManager().getAllCameras();
91 for(auto& entry : allCameras)
92 {
93 bool isOverlayCamera = entry.second->getRenderSettings()->overlayOnly;
94 if (isOverlayCamera)
95 continue;
96
97 // TODO: Not checking if camera and animation renderable's layers match. If we checked more animations could
98 // be culled.
99 mCullFrustums.push_back(entry.second->getWorldFrustum());
100 }
101
102 // Prepare the write buffer
103 UINT32 totalNumBones = 0;
104 for (auto& anim : mProxies)
105 {
106 if (anim->skeleton != nullptr)
107 totalNumBones += anim->skeleton->getNumBones();
108 }
109
110 // Prepare the write buffer
111 EvaluatedAnimationData& renderData = mAnimData[mPoseWriteBufferIdx];
112 renderData.transforms.resize(totalNumBones);
113 renderData.infos.clear();
114
115 // Queue animation evaluation tasks
116 {
117 Lock lock(mMutex);
118 mNumActiveWorkers = (UINT32)mProxies.size();
119 }
120
121 UINT32 curBoneIdx = 0;
122 for (auto& anim : mProxies)
123 {
124 auto evaluateAnimWorker = [this, anim, curBoneIdx]()
125 {
126 UINT32 boneIdx = curBoneIdx;
127 evaluateAnimation(anim.get(), boneIdx);
128
129 Lock lock(mMutex);
130 {
131 assert(mNumActiveWorkers > 0);
132 mNumActiveWorkers--;
133 }
134
135 mWorkerDoneSignal.notify_one();
136 };
137
138 SPtr<Task> task = Task::create("AnimWorker", evaluateAnimWorker);
139 TaskScheduler::instance().addTask(task);
140
141 if (anim->skeleton != nullptr)
142 curBoneIdx += anim->skeleton->getNumBones();
143 }
144
145 // Wait for tasks to complete
146 if(!async)
147 {
148 {
149 Lock lock(mMutex);
150
151 while (mNumActiveWorkers > 0)
152 mWorkerDoneSignal.wait(lock);
153 }
154
155 // Trigger events and update attachments (for the data we just evaluated)
156 for (auto& anim : mAnimations)
157 {
158 anim.second->updateFromProxy();
159 anim.second->triggerEvents(timeDelta);
160 }
161 }
162
163 mSwapBuffers = true;
164
165 if(!async)
166 return &mAnimData[mPoseWriteBufferIdx];
167 else
168 return &mAnimData[mPoseReadBufferIdx];
169 }
170
171 void AnimationManager::evaluateAnimation(AnimationProxy* anim, UINT32& curBoneIdx)
172 {
173 // Culling
174 if (anim->mCullEnabled)
175 {
176 bool isVisible = false;
177 for (auto& frustum : mCullFrustums)
178 {
179 if (frustum.intersects(anim->mBounds))
180 {
181 isVisible = true;
182 break;
183 }
184 }
185
186 if (!isVisible)
187 {
188 anim->wasCulled = true;
189 return;
190 }
191 }
192
193 anim->wasCulled = false;
194
195 // Evaluation
196 EvaluatedAnimationData& renderData = mAnimData[mPoseWriteBufferIdx];
197
198 UINT32 prevPoseBufferIdx = (mPoseWriteBufferIdx + CoreThread::NUM_SYNC_BUFFERS) % (CoreThread::NUM_SYNC_BUFFERS + 1);
199 EvaluatedAnimationData& prevRenderData = mAnimData[prevPoseBufferIdx];
200
201 EvaluatedAnimationData::AnimInfo animInfo;
202 bool hasAnimInfo = false;
203
204 // Evaluate skeletal animation
205 if (anim->skeleton != nullptr)
206 {
207 UINT32 numBones = anim->skeleton->getNumBones();
208
209 EvaluatedAnimationData::PoseInfo& poseInfo = animInfo.poseInfo;
210 poseInfo.animId = anim->id;
211 poseInfo.startIdx = curBoneIdx;
212 poseInfo.numBones = numBones;
213
214 memset(anim->skeletonPose.hasOverride, 0, sizeof(bool) * anim->skeletonPose.numBones);
215 Matrix4* boneDst = renderData.transforms.data() + curBoneIdx;
216
217 // Copy transforms from mapped scene objects
218 UINT32 boneTfrmIdx = 0;
219 for (UINT32 i = 0; i < anim->numSceneObjects; i++)
220 {
221 const AnimatedSceneObjectInfo& soInfo = anim->sceneObjectInfos[i];
222
223 if (soInfo.boneIdx == -1)
224 continue;
225
226 boneDst[soInfo.boneIdx] = anim->sceneObjectTransforms[boneTfrmIdx];
227 anim->skeletonPose.hasOverride[soInfo.boneIdx] = true;
228 boneTfrmIdx++;
229 }
230
231 // Animate bones
232 anim->skeleton->getPose(boneDst, anim->skeletonPose, anim->skeletonMask, anim->layers, anim->numLayers);
233
234 curBoneIdx += numBones;
235 hasAnimInfo = true;
236 }
237 else
238 {
239 EvaluatedAnimationData::PoseInfo& poseInfo = animInfo.poseInfo;
240 poseInfo.animId = anim->id;
241 poseInfo.startIdx = 0;
242 poseInfo.numBones = 0;
243 }
244
245 // Reset mapped SO transform
246 for (UINT32 i = 0; i < anim->sceneObjectPose.numBones; i++)
247 {
248 anim->sceneObjectPose.positions[i] = Vector3::ZERO;
249 anim->sceneObjectPose.rotations[i] = Quaternion::IDENTITY;
250 anim->sceneObjectPose.scales[i] = Vector3::ONE;
251 }
252
253 // Update mapped scene objects
254 memset(anim->sceneObjectPose.hasOverride, 1, sizeof(bool) * 3 * anim->numSceneObjects);
255
256 // Update scene object transforms
257 for (UINT32 i = 0; i < anim->numSceneObjects; i++)
258 {
259 const AnimatedSceneObjectInfo& soInfo = anim->sceneObjectInfos[i];
260
261 // We already evaluated bones
262 if (soInfo.boneIdx != -1)
263 continue;
264
265 if (soInfo.layerIdx == -1 || soInfo.stateIdx == -1)
266 continue;
267
268 const AnimationState& state = anim->layers[soInfo.layerIdx].states[soInfo.stateIdx];
269 if (state.disabled)
270 continue;
271
272 {
273 UINT32 curveIdx = soInfo.curveIndices.position;
274 if (curveIdx != (UINT32)-1)
275 {
276 const TAnimationCurve<Vector3>& curve = state.curves->position[curveIdx].curve;
277 anim->sceneObjectPose.positions[curveIdx] = curve.evaluate(state.time, state.positionCaches[curveIdx], state.loop);
278 anim->sceneObjectPose.hasOverride[i * 3 + 0] = false;
279 }
280 }
281
282 {
283 UINT32 curveIdx = soInfo.curveIndices.rotation;
284 if (curveIdx != (UINT32)-1)
285 {
286 const TAnimationCurve<Quaternion>& curve = state.curves->rotation[curveIdx].curve;
287 anim->sceneObjectPose.rotations[curveIdx] = curve.evaluate(state.time, state.rotationCaches[curveIdx], state.loop);
288 anim->sceneObjectPose.rotations[curveIdx].normalize();
289 anim->sceneObjectPose.hasOverride[i * 3 + 1] = false;
290 }
291 }
292
293 {
294 UINT32 curveIdx = soInfo.curveIndices.scale;
295 if (curveIdx != (UINT32)-1)
296 {
297 const TAnimationCurve<Vector3>& curve = state.curves->scale[curveIdx].curve;
298 anim->sceneObjectPose.scales[curveIdx] = curve.evaluate(state.time, state.scaleCaches[curveIdx], state.loop);
299 anim->sceneObjectPose.hasOverride[i * 3 + 2] = false;
300 }
301 }
302 }
303
304 // Update generic curves
305 // Note: No blending for generic animations, just use first animation
306 if (anim->numLayers > 0 && anim->layers[0].numStates > 0)
307 {
308 const AnimationState& state = anim->layers[0].states[0];
309 if (!state.disabled)
310 {
311 UINT32 numCurves = (UINT32)state.curves->generic.size();
312 for (UINT32 i = 0; i < numCurves; i++)
313 {
314 const TAnimationCurve<float>& curve = state.curves->generic[i].curve;
315 anim->genericCurveOutputs[i] = curve.evaluate(state.time, state.genericCaches[i], state.loop);
316 }
317 }
318 }
319
320 // Update morph shapes
321 if (anim->numMorphShapes > 0)
322 {
323 auto iterFind = prevRenderData.infos.find(anim->id);
324 if (iterFind != prevRenderData.infos.end())
325 animInfo.morphShapeInfo = iterFind->second.morphShapeInfo;
326 else
327 animInfo.morphShapeInfo.version = 1; // 0 is considered invalid version
328
329 // Recalculate weights if curves are present
330 bool hasMorphCurves = false;
331 for (UINT32 i = 0; i < anim->numMorphChannels; i++)
332 {
333 MorphChannelInfo& channelInfo = anim->morphChannelInfos[i];
334 if (channelInfo.weightCurveIdx != (UINT32)-1)
335 {
336 channelInfo.weight = Math::clamp01(anim->genericCurveOutputs[channelInfo.weightCurveIdx]);
337 hasMorphCurves = true;
338 }
339
340 float frameWeight;
341 if (channelInfo.frameCurveIdx != (UINT32)-1)
342 {
343 frameWeight = Math::clamp01(anim->genericCurveOutputs[channelInfo.frameCurveIdx]);
344 hasMorphCurves = true;
345 }
346 else
347 frameWeight = 0.0f;
348
349 if (channelInfo.shapeCount == 1)
350 {
351 MorphShapeInfo& shapeInfo = anim->morphShapeInfos[channelInfo.shapeStart];
352
353 // Blend between base shape and the only available frame
354 float relative = frameWeight - shapeInfo.frameWeight;
355 if (relative <= 0.0f)
356 {
357 float diff = shapeInfo.frameWeight;
358 if (diff > 0.0f)
359 {
360 float t = -relative / diff;
361 shapeInfo.finalWeight = 1.0f - std::min(t, 1.0f);
362 }
363 else
364 shapeInfo.finalWeight = 1.0f;
365 }
366 else // If past the final frame we clamp
367 shapeInfo.finalWeight = 1.0f;
368 }
369 else if (channelInfo.shapeCount > 1)
370 {
371 for (UINT32 j = 0; j < channelInfo.shapeCount - 1; j++)
372 {
373 float prevShapeWeight;
374 if (j > 0)
375 prevShapeWeight = anim->morphShapeInfos[j - 1].frameWeight;
376 else
377 prevShapeWeight = 0.0f; // Base shape, blend between it and the first frame
378
379 float nextShapeWeight = anim->morphShapeInfos[j + 1].frameWeight;
380 MorphShapeInfo& shapeInfo = anim->morphShapeInfos[j];
381
382 float relative = frameWeight - shapeInfo.frameWeight;
383 if (relative <= 0.0f)
384 {
385 float diff = shapeInfo.frameWeight - prevShapeWeight;
386 if (diff > 0.0f)
387 {
388 float t = -relative / diff;
389 shapeInfo.finalWeight = 1.0f - std::min(t, 1.0f);
390 }
391 else
392 shapeInfo.finalWeight = 1.0f;
393 }
394 else
395 {
396 float diff = nextShapeWeight - shapeInfo.frameWeight;
397 if (diff > 0.0f)
398 {
399 float t = relative / diff;
400 shapeInfo.finalWeight = std::min(t, 1.0f);
401 }
402 else
403 shapeInfo.finalWeight = 0.0f;
404 }
405 }
406
407 // Last frame
408 {
409 UINT32 lastFrame = channelInfo.shapeStart + channelInfo.shapeCount - 1;
410 MorphShapeInfo& prevShapeInfo = anim->morphShapeInfos[lastFrame - 1];
411 MorphShapeInfo& shapeInfo = anim->morphShapeInfos[lastFrame];
412
413 float relative = frameWeight - shapeInfo.frameWeight;
414 if (relative <= 0.0f)
415 {
416 float diff = shapeInfo.frameWeight - prevShapeInfo.frameWeight;
417 if (diff > 0.0f)
418 {
419 float t = -relative / diff;
420 shapeInfo.finalWeight = 1.0f - std::min(t, 1.0f);
421 }
422 else
423 shapeInfo.finalWeight = 1.0f;
424 }
425 else // If past the final frame we clamp
426 shapeInfo.finalWeight = 1.0f;
427 }
428 }
429
430 for (UINT32 j = 0; j < channelInfo.shapeCount; j++)
431 {
432 MorphShapeInfo& shapeInfo = anim->morphShapeInfos[channelInfo.shapeStart + j];
433 shapeInfo.finalWeight *= channelInfo.weight;
434 }
435 }
436
437 // Generate morph shape vertices
438 if (anim->morphChannelWeightsDirty || hasMorphCurves)
439 {
440 SPtr<MeshData> meshData = bs_shared_ptr_new<MeshData>(anim->numMorphVertices, 0, mBlendShapeVertexDesc);
441
442 UINT8* bufferData = meshData->getData();
443 memset(bufferData, 0, meshData->getSize());
444
445 UINT32 tempDataSize = (sizeof(Vector3) + sizeof(float)) * anim->numMorphVertices;
446 UINT8* tempData = (UINT8*)bs_stack_alloc(tempDataSize);
447 memset(tempData, 0, tempDataSize);
448
449 Vector3* tempNormals = (Vector3*)tempData;
450 float* accumulatedWeight = (float*)(tempData + sizeof(Vector3) * anim->numMorphVertices);
451
452 UINT8* positions = meshData->getElementData(VES_POSITION, 1, 1);
453 UINT8* normals = meshData->getElementData(VES_NORMAL, 1, 1);
454
455 UINT32 stride = mBlendShapeVertexDesc->getVertexStride(1);
456
457 for (UINT32 i = 0; i < anim->numMorphShapes; i++)
458 {
459 const MorphShapeInfo& info = anim->morphShapeInfos[i];
460 float absWeight = Math::abs(info.finalWeight);
461
462 if (absWeight < 0.0001f)
463 continue;
464
465 const Vector<MorphVertex>& morphVertices = info.shape->getVertices();
466 UINT32 numVertices = (UINT32)morphVertices.size();
467 for (UINT32 j = 0; j < numVertices; j++)
468 {
469 const MorphVertex& vertex = morphVertices[j];
470
471 Vector3* destPos = (Vector3*)(positions + vertex.sourceIdx * stride);
472 *destPos += vertex.deltaPosition * info.finalWeight;
473
474 tempNormals[vertex.sourceIdx] += vertex.deltaNormal * info.finalWeight;
475 accumulatedWeight[vertex.sourceIdx] += absWeight;
476 }
477 }
478
479 for (UINT32 i = 0; i < anim->numMorphVertices; i++)
480 {
481 PackedNormal* destNrm = (PackedNormal*)(normals + i * stride);
482
483 if (accumulatedWeight[i] > 0.0001f)
484 {
485 Vector3 normal = tempNormals[i] / accumulatedWeight[i];
486 normal /= 2.0f; // Accumulated normal is in range [-2, 2] but our normal packing method assumes [-1, 1] range
487
488 MeshUtility::packNormals(&normal, (UINT8*)destNrm, 1, sizeof(Vector3), stride);
489 destNrm->w = (UINT8)(std::min(1.0f, accumulatedWeight[i]) * 255.999f);
490 }
491 else
492 {
493 *destNrm = { { 127, 127, 127, 0 } };
494 }
495 }
496
497 bs_stack_free(tempData);
498
499 animInfo.morphShapeInfo.meshData = meshData;
500
501 animInfo.morphShapeInfo.version++;
502 anim->morphChannelWeightsDirty = false;
503 }
504
505 hasAnimInfo = true;
506 }
507 else
508 animInfo.morphShapeInfo.version = 1;
509
510 if (hasAnimInfo)
511 {
512 Lock lock(mMutex);
513 renderData.infos[anim->id] = animInfo;
514 }
515 }
516
517 UINT64 AnimationManager::registerAnimation(Animation* anim)
518 {
519 mAnimations[mNextId] = anim;
520 return mNextId++;
521 }
522
523 void AnimationManager::unregisterAnimation(UINT64 animId)
524 {
525 mAnimations.erase(animId);
526 }
527
528 AnimationManager& gAnimation()
529 {
530 return AnimationManager::instance();
531 }
532}