#include "./../../../GPUInstancer/Resources/Compute/Include/PlatformDefines.compute" #pragma kernel CSCrowdAnimatorController uniform RWStructuredBuffer gpuiAnimationData; // index: 0 x -> frameNo1, y -> frameNo2, z -> frameNo3, w -> frameNo4 // index: 1 x -> weight1, y -> weight2, z -> weight3, w -> weight4 uniform StructuredBuffer gpuiCrowdAnimatorController; // 0 to 4: x -> minFrame, y -> maxFrame (negative if not looping), z -> speed, w -> startTime uniform uint instanceCount; uniform float currentTime; uniform uint frameRate; #define MIN_SPEED 0.000001f [numthreads(GPUI_THREADS, 1, 1)] void CSCrowdAnimatorController(uint3 id : SV_DispatchThreadID) { if (id.x >= instanceCount) return; uint animationIndex = id.x * 2; uint crowdAnimatorIndex = id.x * 4; float4 animationData = gpuiAnimationData[animationIndex]; float4 crowdAnimatorData = gpuiCrowdAnimatorController[crowdAnimatorIndex]; // If loop is disabled max frame is negative (trick to conserve memory) int isLooping = sign(crowdAnimatorData.y); // absolute value crowdAnimatorData.y = crowdAnimatorData.y * isLooping; float clipTime = abs(currentTime - crowdAnimatorData.w) * crowdAnimatorData.z; float clipFrameCount = crowdAnimatorData.y - crowdAnimatorData.x; float length = clipFrameCount / frameRate; if (crowdAnimatorData.z > MIN_SPEED) { if (isLooping < 0 && clipTime > length) animationData.x = crowdAnimatorData.y; else animationData.x = frac(clipTime / length) * clipFrameCount + crowdAnimatorData.x; } if (animationData.y >= 0) { crowdAnimatorData = gpuiCrowdAnimatorController[crowdAnimatorIndex + 1]; if (crowdAnimatorData.z > MIN_SPEED) { isLooping = sign(crowdAnimatorData.y); crowdAnimatorData.y = crowdAnimatorData.y * isLooping; clipTime = abs(currentTime - crowdAnimatorData.w) * crowdAnimatorData.z; clipFrameCount = crowdAnimatorData.y - crowdAnimatorData.x; length = clipFrameCount / frameRate; if (isLooping < 0 && clipTime > length) animationData.y = crowdAnimatorData.y; else animationData.y = frac(clipTime / length) * clipFrameCount + crowdAnimatorData.x; } } if (animationData.z >= 0) { crowdAnimatorData = gpuiCrowdAnimatorController[crowdAnimatorIndex + 2]; if (crowdAnimatorData.z > MIN_SPEED) { isLooping = sign(crowdAnimatorData.y); crowdAnimatorData.y = crowdAnimatorData.y * isLooping; clipTime = abs(currentTime - crowdAnimatorData.w) * crowdAnimatorData.z; clipFrameCount = crowdAnimatorData.y - crowdAnimatorData.x; length = clipFrameCount / frameRate; if (isLooping < 0 && clipTime > length) animationData.z = crowdAnimatorData.y; else animationData.z = frac(clipTime / length) * clipFrameCount + crowdAnimatorData.x; } } if (animationData.w >= 0) { crowdAnimatorData = gpuiCrowdAnimatorController[crowdAnimatorIndex + 3]; if (crowdAnimatorData.z > MIN_SPEED) { isLooping = sign(crowdAnimatorData.y); crowdAnimatorData.y = crowdAnimatorData.y * isLooping; clipTime = abs(currentTime - crowdAnimatorData.w) * crowdAnimatorData.z; clipFrameCount = crowdAnimatorData.y - crowdAnimatorData.x; length = clipFrameCount / frameRate; if (isLooping < 0 && clipTime > length) animationData.w = crowdAnimatorData.y; else animationData.w = frac(clipTime / length) * clipFrameCount + crowdAnimatorData.x; } } gpuiAnimationData[animationIndex] = animationData; }