Netcode Bootstrap
This commit is contained in:
+17
@@ -0,0 +1,17 @@
|
||||
|
||||
#pragma kernel ProcessAnimations
|
||||
#pragma kernel MakeRigSpaceBoneTransforms
|
||||
#pragma kernel ComputeSkinMatrices
|
||||
|
||||
//#pragma enable_d3d11_debug_symbols
|
||||
//#pragma use_dxc
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#include "Packages/com.rukhanka.animation/Rukhanka.Runtime/Common/Shaders/ShaderConf.hlsl"
|
||||
#include "Packages/com.rukhanka.animation/Rukhanka.Runtime/Common/Shaders/Debug.hlsl"
|
||||
#include "Packages/com.rukhanka.animation/Rukhanka.Runtime/GPUAnimationEngine/Resources/GPUStructures.hlsl"
|
||||
#include "Packages/com.rukhanka.animation/Rukhanka.Runtime/GPUAnimationEngine/Resources/MakeSkinMatrices.hlsl"
|
||||
#include "Packages/com.rukhanka.animation/Rukhanka.Runtime/GPUAnimationEngine/Resources/ProcessAnimations.hlsl"
|
||||
#include "Packages/com.rukhanka.animation/Rukhanka.Runtime/GPUAnimationEngine/Resources/MakeRigSpaceBoneTransforms.hlsl"
|
||||
#include "Packages/com.rukhanka.animation/Rukhanka.Runtime/GPUAnimationEngine/Resources/MakeSkinMatrices.hlsl"
|
||||
+14
@@ -0,0 +1,14 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 7fb582dc2671eaa40869fc5ceea5f2c4
|
||||
ComputeShaderImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
AssetOrigin:
|
||||
serializedVersion: 1
|
||||
productId: 298480
|
||||
packageName: Rukhanka Animation System 2
|
||||
packageVersion: 2.9.0
|
||||
assetPath: Packages/com.rukhanka.animation/Rukhanka.Runtime/GPUAnimationEngine/Resources/GPUAnimationEngine.compute
|
||||
uploadId: 897522
|
||||
+8
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: fb0379f8129846944bf9d56dca4b60fc
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
+66
@@ -0,0 +1,66 @@
|
||||
#pragma once
|
||||
|
||||
//#pragma enable_d3d11_debug_symbols
|
||||
|
||||
#include "Packages/com.unity.render-pipelines.core/ShaderLibrary/UnityInstancing.hlsl"
|
||||
#include "Packages/com.rukhanka.animation/Rukhanka.Runtime/GPUAnimationEngine/Resources/GPUStructures.hlsl"
|
||||
#include "Packages/com.rukhanka.animation/Rukhanka.Runtime/Common/Shaders/ShaderConf.hlsl"
|
||||
#include "Packages/com.rukhanka.animation/Rukhanka.Runtime/Common/Shaders/Debug.hlsl"
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#if defined(DOTS_INSTANCING_ON)
|
||||
|
||||
UNITY_DOTS_INSTANCING_START(MaterialPropertyMetadata)
|
||||
UNITY_DOTS_INSTANCED_PROP(int, _RukhankaGPUBoneIndex)
|
||||
UNITY_DOTS_INSTANCED_PROP(float4x4, _RukhankaAttachmentToBoneTransform)
|
||||
UNITY_DOTS_INSTANCED_PROP(float4x4, _RukhankaAnimatedEntityLocalToWorld)
|
||||
UNITY_DOTS_INSTANCING_END(MaterialPropertyMetadata)
|
||||
|
||||
StructuredBuffer<BoneTransform> boneLocalTransforms;
|
||||
StructuredBuffer<BoneTransform> rigSpaceBoneTransformsBuf;
|
||||
|
||||
#endif
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void GPUAttachmentMeshMover_float(in float3 vertex, in float3 normal, in float3 tangent, out float3 animatedVertex, out float3 animatedNormal, out float3 animatedTangent)
|
||||
{
|
||||
#if defined(DOTS_INSTANCING_ON)
|
||||
int gpuBoneIndex = UNITY_ACCESS_DOTS_INSTANCED_PROP(int, _RukhankaGPUBoneIndex);
|
||||
if (gpuBoneIndex < 0)
|
||||
{
|
||||
animatedVertex = vertex;
|
||||
animatedNormal = normal;
|
||||
animatedTangent = tangent;
|
||||
return;
|
||||
}
|
||||
|
||||
float4x4 attachmentToBoneTransform = UNITY_ACCESS_DOTS_INSTANCED_PROP(float4x4, _RukhankaAttachmentToBoneTransform);
|
||||
float4x4 entityRootLocalToWorld = UNITY_ACCESS_DOTS_INSTANCED_PROP(float4x4, _RukhankaAnimatedEntityLocalToWorld);
|
||||
|
||||
animatedVertex = mul(attachmentToBoneTransform, float4(vertex, 1)).xyz;
|
||||
CHECK_STRUCTURED_BUFFER_OUT_OF_BOUNDS(RUKHANKADEBUGMARKERS_GPUANIMATOR_GPUATTACHMENT_RIG_SPACE_BONE_TRANSFORMS_READ, gpuBoneIndex, rigSpaceBoneTransformsBuf)
|
||||
BoneTransform bt = rigSpaceBoneTransformsBuf[gpuBoneIndex];
|
||||
|
||||
float3 transformedPos = BoneTransform::TransformPoint(bt, animatedVertex);
|
||||
animatedVertex = transformedPos;
|
||||
animatedVertex = mul(entityRootLocalToWorld, float4(animatedVertex, 1)).xyz;
|
||||
animatedVertex = GetCameraRelativePositionWS(animatedVertex);
|
||||
animatedVertex = TransformWorldToObject(animatedVertex);
|
||||
|
||||
animatedNormal = mul((float3x3)attachmentToBoneTransform, normal);
|
||||
animatedNormal = BoneTransform::TransformDirection(bt, animatedNormal);
|
||||
animatedNormal = mul((float3x3)entityRootLocalToWorld, animatedNormal);
|
||||
animatedNormal = TransformWorldToObjectDir(animatedNormal);
|
||||
|
||||
animatedTangent = mul((float3x3)attachmentToBoneTransform, tangent);
|
||||
animatedTangent = BoneTransform::TransformDirection(bt, animatedTangent);
|
||||
animatedTangent = mul((float3x3)entityRootLocalToWorld, animatedTangent);
|
||||
animatedTangent = TransformWorldToObjectDir(animatedTangent);
|
||||
#else
|
||||
animatedVertex = vertex;
|
||||
animatedNormal = normal;
|
||||
animatedTangent = tangent;
|
||||
#endif
|
||||
}
|
||||
+14
@@ -0,0 +1,14 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 72cf2095e0e922349b94b239dcf25a14
|
||||
ShaderIncludeImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
AssetOrigin:
|
||||
serializedVersion: 1
|
||||
productId: 298480
|
||||
packageName: Rukhanka Animation System 2
|
||||
packageVersion: 2.9.0
|
||||
assetPath: Packages/com.rukhanka.animation/Rukhanka.Runtime/GPUAnimationEngine/Resources/GPUAttachment/GPUAttachmentShaderNode.hlsl
|
||||
uploadId: 897522
|
||||
+67
@@ -0,0 +1,67 @@
|
||||
|
||||
#ifndef GPU_STRUCTURES_HLSL_
|
||||
#define GPU_STRUCTURES_HLSL_
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// struct RigDefinition
|
||||
ByteAddressBuffer rigDefinitions;
|
||||
// struct RigBone
|
||||
ByteAddressBuffer rigBones;
|
||||
// struct AnimationClip
|
||||
ByteAddressBuffer animationClips;
|
||||
// struct HumanRotationData
|
||||
ByteAddressBuffer humanRotationDataBuffer;
|
||||
int animatedBonesCount;
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#include "Packages/com.rukhanka.animation/Rukhanka.Runtime/Common/Shaders/Debug.hlsl"
|
||||
#include "Packages/com.rukhanka.animation/Rukhanka.Runtime/Common/Shaders/GPUStructures/BoneTransform.hlsl"
|
||||
#include "Packages/com.rukhanka.animation/Rukhanka.Runtime/Common/Shaders/GPUStructures/AnimationClip.hlsl"
|
||||
#include "Packages/com.rukhanka.animation/Rukhanka.Runtime/Common/Shaders/GPUStructures/Track.hlsl"
|
||||
#include "Packages/com.rukhanka.animation/Rukhanka.Runtime/Common/Shaders/GPUStructures/SkinnedMeshBone.hlsl"
|
||||
#include "Packages/com.rukhanka.animation/Rukhanka.Runtime/Common/Shaders/GPUStructures/RigDefinition.hlsl"
|
||||
#include "Packages/com.rukhanka.animation/Rukhanka.Runtime/Common/Shaders/GPUStructures/RigBone.hlsl"
|
||||
#include "Packages/com.rukhanka.animation/Rukhanka.Runtime/Common/Shaders/GPUStructures/HumanRotationData.hlsl"
|
||||
#include "Packages/com.rukhanka.animation/Rukhanka.Runtime/Common/Shaders/GPUStructures/AnimationToProcess.hlsl"
|
||||
#include "Packages/com.rukhanka.animation/Rukhanka.Runtime/Common/Shaders/GPUStructures/AvatarMask.hlsl"
|
||||
#include "Packages/com.rukhanka.animation/Rukhanka.Runtime/Common/Shaders/GPUStructures/PerfectHashTable.hlsl"
|
||||
#include "Packages/com.rukhanka.animation/Rukhanka.Runtime/Common/Shaders/GPUStructures/SkinMatrix.hlsl"
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
struct AnimationJob
|
||||
{
|
||||
int rigDefinitionIndex;
|
||||
int animatedBoneIndexOffset;
|
||||
int2 animationsToProcessRange;
|
||||
};
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
struct SkinnedMeshWorkload
|
||||
{
|
||||
int skinMatrixBaseOutIndex;
|
||||
int boneRemapTableIndex;
|
||||
int skinMatricesCount;
|
||||
int rootBoneIndex;
|
||||
int animatedBoneIndexOffset;
|
||||
float4x4 skinnedRootBoneToEntityTransform;
|
||||
};
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
struct AnimatedBoneWorkload
|
||||
{
|
||||
int boneIndexInRig;
|
||||
int animationJobIndex;
|
||||
};
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
StructuredBuffer<AnimatedBoneWorkload> animatedBoneWorkload;
|
||||
StructuredBuffer<AnimationJob> animationJobs;
|
||||
StructuredBuffer<AnimationToProcess> animationsToProcess;
|
||||
|
||||
#endif
|
||||
+14
@@ -0,0 +1,14 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 73a44b85a6e0ce04896ab06edf8b01f5
|
||||
ShaderIncludeImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
AssetOrigin:
|
||||
serializedVersion: 1
|
||||
productId: 298480
|
||||
packageName: Rukhanka Animation System 2
|
||||
packageVersion: 2.9.0
|
||||
assetPath: Packages/com.rukhanka.animation/Rukhanka.Runtime/GPUAnimationEngine/Resources/GPUStructures.hlsl
|
||||
uploadId: 897522
|
||||
+42
@@ -0,0 +1,42 @@
|
||||
#ifndef MAKE_WORLD_SPACE_BONE_TRANSFORMS_HLSL_
|
||||
#define MAKE_WORLD_SPACE_BONE_TRANSFORMS_HLSL_
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
RWStructuredBuffer<BoneTransform> outBoneTransforms;
|
||||
StructuredBuffer<BoneTransform> boneLocalTransforms;
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
[numthreads(256, 1, 1)]
|
||||
void MakeRigSpaceBoneTransforms(uint tid: SV_DispatchThreadID)
|
||||
{
|
||||
if (tid >= (uint)animatedBonesCount)
|
||||
return;
|
||||
|
||||
CHECK_STRUCTURED_BUFFER_OUT_OF_BOUNDS(RUKHANKADEBUGMARKERS_GPUANIMATOR_MAKE_RIG_SPACE_BONE_TRANSFORMS_ANIMATED_BONE_WORKLOAD_READ, tid, animatedBoneWorkload);
|
||||
AnimatedBoneWorkload boneWorkload = animatedBoneWorkload[tid];
|
||||
|
||||
CHECK_STRUCTURED_BUFFER_OUT_OF_BOUNDS(RUKHANKADEBUGMARKERS_GPUANIMATOR_MAKE_RIG_SPACE_BONE_TRANSFORMS_ANIMATION_JOBS_READ, boneWorkload.animationJobIndex, animationJobs);
|
||||
AnimationJob animationJob = animationJobs[boneWorkload.animationJobIndex];
|
||||
RigDefinition rigDef = RigDefinition::ReadFromRawBuffer(rigDefinitions, animationJob.rigDefinitionIndex);
|
||||
RigBone rigBone = RigBone::ReadFromRawBuffer(rigBones, rigDef.rigBonesRange.x + boneWorkload.boneIndexInRig);
|
||||
|
||||
int absoluteBoneIndex = animationJob.animatedBoneIndexOffset + boneWorkload.boneIndexInRig;
|
||||
CHECK_STRUCTURED_BUFFER_OUT_OF_BOUNDS(RUKHANKADEBUGMARKERS_GPUANIMATOR_MAKE_RIG_SPACE_BONE_TRANSFORMS_BONE_LOCAL_TRANSFORMS_READ0, absoluteBoneIndex, boneLocalTransforms);
|
||||
BoneTransform bt = boneLocalTransforms[absoluteBoneIndex];
|
||||
int parentBoneIndex = rigBone.parentBoneIndex;
|
||||
while (parentBoneIndex > 0)
|
||||
{
|
||||
RigBone parentBoneData = RigBone::ReadFromRawBuffer(rigBones, rigDef.rigBonesRange.x + parentBoneIndex);
|
||||
int absoluteParentBoneIndex = animationJob.animatedBoneIndexOffset + parentBoneIndex;
|
||||
CHECK_STRUCTURED_BUFFER_OUT_OF_BOUNDS(RUKHANKADEBUGMARKERS_GPUANIMATOR_MAKE_RIG_SPACE_BONE_TRANSFORMS_BONE_LOCAL_TRANSFORMS_READ1, absoluteParentBoneIndex, boneLocalTransforms);
|
||||
BoneTransform parentBoneTransform = boneLocalTransforms[absoluteParentBoneIndex];
|
||||
bt = BoneTransform::Multiply(parentBoneTransform, bt);
|
||||
parentBoneIndex = parentBoneData.parentBoneIndex;
|
||||
}
|
||||
CHECK_STRUCTURED_BUFFER_OUT_OF_BOUNDS(RUKHANKADEBUGMARKERS_GPUANIMATOR_MAKE_RIG_SPACE_BONE_TRANSFORMS_OUT_BONE_TRANSFORMS_WRITE, absoluteBoneIndex, outBoneTransforms);
|
||||
outBoneTransforms[absoluteBoneIndex] = bt;
|
||||
}
|
||||
|
||||
#endif // MAKE_WORLD_SPACE_BONE_TRANSFORMS_HLSL_
|
||||
+14
@@ -0,0 +1,14 @@
|
||||
fileFormatVersion: 2
|
||||
guid: a93c55826c7c8b44c9a655d386904e4a
|
||||
ShaderIncludeImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
AssetOrigin:
|
||||
serializedVersion: 1
|
||||
productId: 298480
|
||||
packageName: Rukhanka Animation System 2
|
||||
packageVersion: 2.9.0
|
||||
assetPath: Packages/com.rukhanka.animation/Rukhanka.Runtime/GPUAnimationEngine/Resources/MakeRigSpaceBoneTransforms.hlsl
|
||||
uploadId: 897522
|
||||
+41
@@ -0,0 +1,41 @@
|
||||
#ifndef MAKE_SKIN_MATRICES_HLSL_
|
||||
#define MAKE_SKIN_MATRICES_HLSL_
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
RWByteAddressBuffer outSkinMatrices;
|
||||
StructuredBuffer<BoneTransform> rigSpaceBoneTransformsBuf;
|
||||
StructuredBuffer<SkinnedMeshWorkload> skinMatrixWorkloadBuf;
|
||||
ByteAddressBuffer skinnedMeshBoneData;
|
||||
uint totalSkinnedMeshes;
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
[numthreads(128, 1, 1)]
|
||||
void ComputeSkinMatrices(uint tid: SV_DispatchThreadID)
|
||||
{
|
||||
if (tid >= totalSkinnedMeshes)
|
||||
return;
|
||||
|
||||
CHECK_STRUCTURED_BUFFER_OUT_OF_BOUNDS(RUKHANKADEBUGMARKERS_GPUANIMATOR_COMPUTE_SKIN_MATRICES_SKIN_MATRIX_WORKLOAD_READ, tid, skinMatrixWorkloadBuf);
|
||||
SkinnedMeshWorkload smw = skinMatrixWorkloadBuf[tid];
|
||||
float4x4 w2l = smw.skinnedRootBoneToEntityTransform;
|
||||
|
||||
for (int i = 0; i < smw.skinMatricesCount; ++i)
|
||||
{
|
||||
SkinnedMeshBone smb = SkinnedMeshBone::ReadFromRawBuffer(skinnedMeshBoneData, smw.boneRemapTableIndex + i);
|
||||
|
||||
int boneTransformIndex = smb.boneRemapIndex + smw.animatedBoneIndexOffset;
|
||||
CHECK_STRUCTURED_BUFFER_OUT_OF_BOUNDS(RUKHANKADEBUGMARKERS_GPUANIMATOR_COMPUTE_SKIN_MATRICES_RIG_SPACE_BONE_TRANSFORMS_READ, boneTransformIndex, rigSpaceBoneTransformsBuf);
|
||||
BoneTransform bt = rigSpaceBoneTransformsBuf[boneTransformIndex];
|
||||
|
||||
float4x4 skinMatrix = bt.ToFloat4x4();
|
||||
skinMatrix = mul(w2l, skinMatrix);
|
||||
float4x4 outSkinMatrix = mul(skinMatrix, smb.bindPose);
|
||||
|
||||
int skinMatrixOutIndex = smw.skinMatrixBaseOutIndex + i;
|
||||
SkinMatrix::WriteToRawBuffer(outSkinMatrices, (float3x4)outSkinMatrix, skinMatrixOutIndex);
|
||||
}
|
||||
}
|
||||
|
||||
#endif //MAKE_SKIN_MATRICES_HLSL_
|
||||
+14
@@ -0,0 +1,14 @@
|
||||
fileFormatVersion: 2
|
||||
guid: f0c8e199e88b9894b92573b0636c8e6b
|
||||
ShaderIncludeImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
AssetOrigin:
|
||||
serializedVersion: 1
|
||||
productId: 298480
|
||||
packageName: Rukhanka Animation System 2
|
||||
packageVersion: 2.9.0
|
||||
assetPath: Packages/com.rukhanka.animation/Rukhanka.Runtime/GPUAnimationEngine/Resources/MakeSkinMatrices.hlsl
|
||||
uploadId: 897522
|
||||
+246
@@ -0,0 +1,246 @@
|
||||
#ifndef PROCESS_ANIMATIONS_HLSL_
|
||||
#define PROCESS_ANIMATIONS_HLSL_
|
||||
|
||||
#include "Packages/com.rukhanka.animation/Rukhanka.Runtime/GPUAnimationEngine/Resources/TrackGroupSampler.hlsl"
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#define NUM_MAXIMUM_LAYER_WEIGHTS 16
|
||||
RWStructuredBuffer<BoneTransform> outAnimatedBones;
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
struct LayerInfo
|
||||
{
|
||||
int index;
|
||||
float weight;
|
||||
int blendMode;
|
||||
};
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
float2 NormalizeAnimationTime(float at, AnimationClip ac)
|
||||
{
|
||||
at += ac.cycleOffset;
|
||||
if (at < 0) at = 1 + at;
|
||||
float normalizedTime = ac.IsLooped() ? frac(at) : saturate(at);
|
||||
float timeInSeconds = normalizedTime * ac.length;
|
||||
float2 rv = float2(timeInSeconds, normalizedTime);
|
||||
return rv;
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
BoneTransform MakeAdditiveAnimation(BoneTransform bonePose, BoneTransform zeroFramePose)
|
||||
{
|
||||
BoneTransform rv;
|
||||
rv.pos = bonePose.pos - zeroFramePose.pos;
|
||||
Quaternion conjugateZFRot = Quaternion::NormalizeSafe(Quaternion::Conjugate(zeroFramePose.rot));
|
||||
conjugateZFRot = Quaternion::ShortestRotation(bonePose.rot, conjugateZFRot);
|
||||
rv.rot = Quaternion::Multiply(conjugateZFRot, Quaternion::Normalize(bonePose.rot));
|
||||
rv.scale = bonePose.scale / zeroFramePose.scale;
|
||||
return rv;
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
BoneTransform CalculateLoopPose(BoneTransform bonePose, TrackSet ts, HumanRotationData hrd, float normalizedTime)
|
||||
{
|
||||
float lerpFactor = normalizedTime;
|
||||
|
||||
TrackSampler ffSampler = CreateFirstFrameTrackSampler();
|
||||
BoneTransformAndFlags rootPoseStart = SampleTrackGroup(ts, ffSampler, hrd);
|
||||
TrackSampler lfSampler = CreateLastFrameTrackSampler();
|
||||
BoneTransformAndFlags rootPoseEnd = SampleTrackGroup(ts, lfSampler, hrd);
|
||||
|
||||
float3 dPos = rootPoseEnd.bt.pos - rootPoseStart.bt.pos;
|
||||
Quaternion dRot = Quaternion::Multiply(Quaternion::Conjugate(rootPoseEnd.bt.rot), rootPoseStart.bt.rot);
|
||||
|
||||
BoneTransform rv;
|
||||
rv.pos = bonePose.pos - dPos * lerpFactor;
|
||||
rv.rot = Quaternion::Multiply(bonePose.rot, Quaternion::Slerp(Quaternion::Identity(), dRot, lerpFactor));
|
||||
return rv;
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
bool SampleAnimation(AnimationClip ac, uint baseAddress, float2 animTime, int rigBoneIndex, uint rigBoneHash, int blendMode, HumanRotationData hrd, out BoneTransformAndFlags btf)
|
||||
{
|
||||
btf = BoneTransformAndFlags::Identity();
|
||||
|
||||
TrackSet tsClip = ac.clipTracks;
|
||||
tsClip.OffsetByAddress(baseAddress);
|
||||
|
||||
int trackGroupIndex = tsClip.GetTrackGroupIndex(rigBoneHash);
|
||||
if (trackGroupIndex < 0)
|
||||
return false;
|
||||
|
||||
tsClip.trackGroupsOffset += trackGroupIndex * 4;
|
||||
|
||||
float timeInSeconds = animTime.x;
|
||||
TrackSampler tSampler = CreateDefaultTrackSampler(timeInSeconds);
|
||||
btf = SampleTrackGroup(tsClip, tSampler, hrd);
|
||||
|
||||
if (blendMode == BLEND_MODE_ADDITIVE)
|
||||
{
|
||||
TrackSet additiveTrackSet = ac.clipTracks;
|
||||
if (ac.additiveReferencePoseTracks.keyFramesOffset >= 0)
|
||||
additiveTrackSet = ac.additiveReferencePoseTracks;
|
||||
|
||||
additiveTrackSet.OffsetByAddress(baseAddress);
|
||||
|
||||
int additiveTrackGroupIndex = QueryPerfectHashTable(rigBoneHash, additiveTrackSet.trackGroupPHTSeed, additiveTrackSet.trackGroupPHTOffset, additiveTrackSet.trackGroupPHTSizeMask);
|
||||
if (additiveTrackGroupIndex >= 0)
|
||||
{
|
||||
TrackSampler ffSampler = CreateFirstFrameTrackSampler();
|
||||
additiveTrackSet.trackGroupsOffset += additiveTrackGroupIndex * 4;
|
||||
BoneTransformAndFlags additiveFramePose = SampleTrackGroup(additiveTrackSet, ffSampler, hrd);
|
||||
btf.bt = MakeAdditiveAnimation(btf.bt, additiveFramePose.bt);
|
||||
}
|
||||
}
|
||||
|
||||
bool calculateLoopPose = ac.LoopPoseBlend() & rigBoneIndex != 0;
|
||||
if (calculateLoopPose)
|
||||
{
|
||||
btf.bt = CalculateLoopPose(btf.bt, tsClip, hrd, animTime.y);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
BoneTransform AppendScaledPose(BoneTransform curPose, BoneTransform addedPose, float weight)
|
||||
{
|
||||
BoneTransform rv;
|
||||
rv.pos = curPose.pos + addedPose.pos * weight;
|
||||
rv.rot = Quaternion::Nlerp(curPose.rot, addedPose.rot, weight);
|
||||
rv.scale = curPose.scale + addedPose.scale * weight;
|
||||
return rv;
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
BoneTransform BlendLayerPose(BoneTransform curPose, BoneTransform layerPose, BoneTransform refPose, LayerInfo layerInfo, float weightSum, float3 layerFlags)
|
||||
{
|
||||
BoneTransform rv = curPose;
|
||||
|
||||
// Override
|
||||
if (layerInfo.blendMode == BLEND_MODE_OVERRIDE)
|
||||
{
|
||||
if (weightSum < 1)
|
||||
layerPose = AppendScaledPose(layerPose, refPose, max(0, 1 - weightSum));
|
||||
|
||||
if (layerFlags.x > 0)
|
||||
rv.pos = lerp(curPose.pos, layerPose.pos, layerInfo.weight);
|
||||
|
||||
if (layerFlags.y > 0)
|
||||
{
|
||||
layerPose.rot = Quaternion::ShortestRotation(curPose.rot, layerPose.rot);
|
||||
rv.rot = Quaternion::Nlerp(curPose.rot, layerPose.rot, layerInfo.weight);
|
||||
}
|
||||
|
||||
if (layerFlags.z > 0)
|
||||
rv.scale = lerp(curPose.scale, layerPose.scale, layerInfo.weight);
|
||||
}
|
||||
// Additive
|
||||
else
|
||||
{
|
||||
if (layerFlags.x > 0)
|
||||
rv.pos = curPose.pos + layerPose.pos * layerInfo.weight;
|
||||
|
||||
if (layerFlags.y > 0)
|
||||
{
|
||||
Quaternion layerRot;
|
||||
layerRot.value = float4(layerPose.rot.value.xyz * layerInfo.weight, layerPose.rot.value.w);
|
||||
layerRot = Quaternion::NormalizeSafe(layerRot);
|
||||
layerRot = Quaternion::ShortestRotation(curPose.rot, layerRot);
|
||||
rv.rot = Quaternion::Multiply(curPose.rot, layerRot);
|
||||
}
|
||||
|
||||
if (layerFlags.z > 0)
|
||||
rv.scale = curPose.scale * lerp(1, layerPose.scale, layerInfo.weight);
|
||||
}
|
||||
return rv;
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
LayerInfo GetLayerInfoFromAnimation(AnimationToProcess atp)
|
||||
{
|
||||
LayerInfo rv;
|
||||
rv.weight = atp.layerWeight;
|
||||
rv.blendMode = atp.blendMode;
|
||||
rv.index = atp.layerIndex;
|
||||
return rv;
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
[numthreads(128, 1, 1)]
|
||||
void ProcessAnimations(uint tid: SV_DispatchThreadID)
|
||||
{
|
||||
if (tid >= (uint)animatedBonesCount)
|
||||
return;
|
||||
|
||||
CHECK_STRUCTURED_BUFFER_OUT_OF_BOUNDS(RUKHANKADEBUGMARKERS_GPUANIMATOR_PROCESS_ANIMATIONS_ANIMATED_BONE_WORKLOAD_READ, tid, animatedBoneWorkload);
|
||||
AnimatedBoneWorkload boneWorkload = animatedBoneWorkload[tid];
|
||||
|
||||
CHECK_STRUCTURED_BUFFER_OUT_OF_BOUNDS(RUKHANKADEBUGMARKERS_GPUANIMATOR_PROCESS_ANIMATIONS_ANIMATION_JOBS_READ, boneWorkload.animationJobIndex, animationJobs);
|
||||
AnimationJob animationJob = animationJobs[boneWorkload.animationJobIndex];
|
||||
|
||||
RigDefinition rigDef = RigDefinition::ReadFromRawBuffer(rigDefinitions, animationJob.rigDefinitionIndex);
|
||||
RigBone rigBone = RigBone::ReadFromRawBuffer(rigBones, rigDef.rigBonesRange.x + boneWorkload.boneIndexInRig);
|
||||
|
||||
HumanRotationData hrd = (HumanRotationData)0;
|
||||
if (rigDef.humanRotationDataRange.x >= 0)
|
||||
hrd = HumanRotationData::ReadFromRawBuffer(humanRotationDataBuffer, rigDef.humanRotationDataRange.x + boneWorkload.boneIndexInRig);
|
||||
|
||||
BoneTransform blendedBonePose = rigBone.refPose;
|
||||
BoneTransform layerPose = BoneTransform::Zero();
|
||||
float weightSum = 0;
|
||||
float3 layerFlags = 0;
|
||||
LayerInfo layerInfo = (LayerInfo)0;
|
||||
|
||||
int atpIndexStart = animationJob.animationsToProcessRange.x;
|
||||
int atpIndexEnd = animationJob.animationsToProcessRange.x + animationJob.animationsToProcessRange.y;
|
||||
for (int i = atpIndexStart; i < atpIndexEnd; ++i)
|
||||
{
|
||||
AnimationToProcess atp = animationsToProcess[i];
|
||||
bool inAvatarMask = IsBoneInAvatarMask(atp.avatarMaskDataOffset, rigBone.humanBodyPart, boneWorkload.boneIndexInRig);
|
||||
|
||||
if (atp.animationClipAddress < 0 || atp.weight == 0 || atp.layerWeight == 0 || !inAvatarMask)
|
||||
continue;
|
||||
|
||||
LayerInfo curLayerInfo = GetLayerInfoFromAnimation(atp);
|
||||
if (layerInfo.index != curLayerInfo.index)
|
||||
{
|
||||
blendedBonePose = BlendLayerPose(blendedBonePose, layerPose, rigBone.refPose, layerInfo, weightSum, layerFlags);
|
||||
weightSum = 0;
|
||||
layerFlags = 0;
|
||||
layerPose = BoneTransform::Zero();
|
||||
}
|
||||
layerInfo = curLayerInfo;
|
||||
|
||||
int baseAddress = atp.animationClipAddress;
|
||||
AnimationClip ac = AnimationClip::ReadFromRawBuffer(animationClips, baseAddress);
|
||||
float2 animTime = NormalizeAnimationTime(atp.time, ac);
|
||||
|
||||
BoneTransformAndFlags btf;
|
||||
if (SampleAnimation(ac, baseAddress, animTime, boneWorkload.boneIndexInRig, rigBone.hash, atp.blendMode, hrd, btf))
|
||||
{
|
||||
weightSum += atp.weight;
|
||||
layerFlags += btf.flags;
|
||||
layerPose = AppendScaledPose(layerPose, btf.bt, atp.weight);
|
||||
}
|
||||
}
|
||||
|
||||
blendedBonePose = BlendLayerPose(blendedBonePose, layerPose, rigBone.refPose, layerInfo, weightSum, layerFlags);
|
||||
|
||||
int outIndex = animationJob.animatedBoneIndexOffset + boneWorkload.boneIndexInRig;
|
||||
|
||||
CHECK_STRUCTURED_BUFFER_OUT_OF_BOUNDS(RUKHANKADEBUGMARKERS_GPUANIMATOR_PROCESS_ANIMATIONS_OUT_ANIMATED_BONES_WRITE, outIndex, outAnimatedBones);
|
||||
outAnimatedBones[outIndex] = blendedBonePose;
|
||||
}
|
||||
|
||||
#endif // PROCESS_ANIMATIONS_HLSL_
|
||||
+14
@@ -0,0 +1,14 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 82f7bcf8fbdb6044181d80fc661b5392
|
||||
ShaderIncludeImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
AssetOrigin:
|
||||
serializedVersion: 1
|
||||
productId: 298480
|
||||
packageName: Rukhanka Animation System 2
|
||||
packageVersion: 2.9.0
|
||||
assetPath: Packages/com.rukhanka.animation/Rukhanka.Runtime/GPUAnimationEngine/Resources/ProcessAnimations.hlsl
|
||||
uploadId: 897522
|
||||
+146
@@ -0,0 +1,146 @@
|
||||
#ifndef TRACK_GROUP_SAMPLER_HLSL_
|
||||
#define TRACK_GROUP_SAMPLER_HLSL_
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#include "Packages/com.rukhanka.animation/Rukhanka.Runtime/GPUAnimationEngine/Resources/TrackSampler.hlsl"
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
struct BoneTransformAndFlags
|
||||
{
|
||||
BoneTransform bt;
|
||||
float3 flags;
|
||||
|
||||
static BoneTransformAndFlags Identity()
|
||||
{
|
||||
BoneTransformAndFlags rv;
|
||||
rv.bt = BoneTransform::Identity();
|
||||
rv.flags = 0;
|
||||
return rv;
|
||||
}
|
||||
};
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
Quaternion ApplyHumanoidPostTransform(HumanRotationData hrd, Quaternion q)
|
||||
{
|
||||
Quaternion rv = Quaternion::Multiply(Quaternion::Multiply(hrd.preRot, q), hrd.postRot);
|
||||
return rv;
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
float3 MuscleRangeToRadians(float3 minA, float3 maxA, float3 muscle)
|
||||
{
|
||||
float3 negativeRange = min(muscle, 0);
|
||||
float3 positiveRange = max(0, muscle);
|
||||
float3 negativeRot = lerp(0, minA, -negativeRange);
|
||||
float3 positiveRot = lerp(0, maxA, +positiveRange);
|
||||
|
||||
float3 rv = negativeRot + positiveRot;
|
||||
return rv;
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
Quaternion MuscleValuesToQuaternion(HumanRotationData humanBoneInfo, float3 muscleValues)
|
||||
{
|
||||
float3 r = MuscleRangeToRadians(humanBoneInfo.minMuscleAngles, humanBoneInfo.maxMuscleAngles, muscleValues);
|
||||
r *= humanBoneInfo.sign;
|
||||
|
||||
float3 rightVec = float3(1, 0, 0);
|
||||
float3 upVec = float3(0, 1, 0);
|
||||
float3 forwardVec = float3(0, 0, 1);
|
||||
|
||||
Quaternion qx = Quaternion::AxisAngle(rightVec, r.x);
|
||||
Quaternion qy = Quaternion::AxisAngle(upVec, r.y);
|
||||
Quaternion qz = Quaternion::AxisAngle(forwardVec, r.z);
|
||||
Quaternion qzy = Quaternion::Multiply(qz, qy);
|
||||
qzy.value.x = 0;
|
||||
Quaternion rv = Quaternion::Multiply(Quaternion::Normalize(qzy), qx);
|
||||
|
||||
rv = ApplyHumanoidPostTransform(humanBoneInfo, rv);
|
||||
return rv;
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
BoneTransformAndFlags SampleTrackGroup(TrackSet ts, TrackSampler trackSampler, HumanRotationData hrd)
|
||||
{
|
||||
int trackStartIndex = animationClips.Load(ts.trackGroupsOffset);
|
||||
int trackEndIndex = animationClips.Load(ts.trackGroupsOffset + 4);
|
||||
|
||||
float pos[3] = {0, 0, 0};
|
||||
float rot[4] = {0, 0, 0, 1};
|
||||
float scale[3] = {1, 1, 1};
|
||||
float3 flags = 0;
|
||||
bool eulerToQuaternion = false;
|
||||
bool isHumanMuscle = false;
|
||||
|
||||
for (int i = trackStartIndex; i < trackEndIndex; ++i)
|
||||
{
|
||||
Track tk = Track::ReadFromRawBuffer(animationClips, ts.tracksOffset, i);
|
||||
int channelIndex = tk.GetChannelIndex();
|
||||
float interpolatedCurveValue = trackSampler.Sample(tk, ts.keyFramesOffset);
|
||||
|
||||
switch (tk.GetBindingType())
|
||||
{
|
||||
case BINDING_TYPE_TRANSLATION:
|
||||
pos[channelIndex] = interpolatedCurveValue;
|
||||
flags.x = 1;
|
||||
break;
|
||||
case BINDING_TYPE_QUATERNION:
|
||||
rot[channelIndex] = interpolatedCurveValue;
|
||||
flags.y = 1;
|
||||
break;
|
||||
case BINDING_TYPE_SCALE:
|
||||
scale[channelIndex] = interpolatedCurveValue;
|
||||
flags.z = 1;
|
||||
break;
|
||||
case BINDING_TYPE_EULER_ANGLES:
|
||||
eulerToQuaternion = true;
|
||||
rot[channelIndex] = interpolatedCurveValue;
|
||||
flags.y = 1;
|
||||
break;
|
||||
case BINDING_TYPE_HUMAN_MUSCLE:
|
||||
rot[channelIndex] = interpolatedCurveValue;
|
||||
isHumanMuscle = true;
|
||||
flags.y = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (eulerToQuaternion)
|
||||
{
|
||||
float3 eulerAnglesInDegrees = float3(rot[0], rot[1], rot[2]);
|
||||
Quaternion q = Quaternion::EulerXYZ(eulerAnglesInDegrees * (1 / 180.0f * 3.1415926f));
|
||||
rot[0] = q.value.x;
|
||||
rot[1] = q.value.y;
|
||||
rot[2] = q.value.z;
|
||||
rot[3] = q.value.w;
|
||||
}
|
||||
|
||||
if (isHumanMuscle)
|
||||
{
|
||||
float3 muscleValues = float3(rot[0], rot[1], rot[2]);
|
||||
Quaternion q = MuscleValuesToQuaternion(hrd, muscleValues);
|
||||
rot[0] = q.value.x;
|
||||
rot[1] = q.value.y;
|
||||
rot[2] = q.value.z;
|
||||
rot[3] = q.value.w;
|
||||
}
|
||||
|
||||
BoneTransform bt = BoneTransform::Identity();
|
||||
bt.pos = float3(pos[0], pos[1], pos[2]);
|
||||
bt.rot.value = float4(rot[0], rot[1], rot[2], rot[3]);
|
||||
bt.scale = float3(scale[0], scale[1], scale[2]);
|
||||
|
||||
BoneTransformAndFlags rv;
|
||||
rv.bt = bt;
|
||||
rv.flags = flags;
|
||||
|
||||
return rv;
|
||||
};
|
||||
|
||||
#endif
|
||||
+14
@@ -0,0 +1,14 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 17fe18272a1400f40bd8ff451251ad4f
|
||||
ShaderIncludeImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
AssetOrigin:
|
||||
serializedVersion: 1
|
||||
productId: 298480
|
||||
packageName: Rukhanka Animation System 2
|
||||
packageVersion: 2.9.0
|
||||
assetPath: Packages/com.rukhanka.animation/Rukhanka.Runtime/GPUAnimationEngine/Resources/TrackGroupSampler.hlsl
|
||||
uploadId: 897522
|
||||
+62
@@ -0,0 +1,62 @@
|
||||
#ifndef TRACK_SAMPLER_HLSL_
|
||||
#define TRACK_SAMPLER_HLSL_
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#define TRACK_SAMPLER_TYPE_DEFAULT 0
|
||||
#define TRACK_SAMPLER_TYPE_FIRST_FRAME 1
|
||||
#define TRACK_SAMPLER_TYPE_LAST_FRAME 2
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
struct TrackSampler
|
||||
{
|
||||
float time;
|
||||
int samplerType;
|
||||
|
||||
float Sample(Track tk, int keyFrameBaseAddress)
|
||||
{
|
||||
// With absence of interfaces in DXC and templates (hello HLSL 2021) need to invent such apprach
|
||||
switch (samplerType)
|
||||
{
|
||||
case TRACK_SAMPLER_TYPE_DEFAULT:
|
||||
return tk.SampleByBinarySearch(time, keyFrameBaseAddress);
|
||||
break;
|
||||
case TRACK_SAMPLER_TYPE_FIRST_FRAME:
|
||||
return tk.GetFirstFrameValue(keyFrameBaseAddress);
|
||||
break;
|
||||
case TRACK_SAMPLER_TYPE_LAST_FRAME:
|
||||
return tk.GetLastFrameValue(keyFrameBaseAddress);
|
||||
break;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
};
|
||||
|
||||
//-----------------------------------------------------------------------------------------//
|
||||
// Helper functions to create typed samplers
|
||||
//-----------------------------------------------------------------------------------------//
|
||||
|
||||
TrackSampler CreateDefaultTrackSampler(float time)
|
||||
{
|
||||
TrackSampler rv = {time, TRACK_SAMPLER_TYPE_DEFAULT};
|
||||
return rv;
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
TrackSampler CreateFirstFrameTrackSampler()
|
||||
{
|
||||
TrackSampler rv = {0, TRACK_SAMPLER_TYPE_FIRST_FRAME};
|
||||
return rv;
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
TrackSampler CreateLastFrameTrackSampler()
|
||||
{
|
||||
TrackSampler rv = {0, TRACK_SAMPLER_TYPE_LAST_FRAME};
|
||||
return rv;
|
||||
}
|
||||
|
||||
#endif
|
||||
+14
@@ -0,0 +1,14 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 4000a1fb1ac3eec4fb7dfdac3670dafb
|
||||
ShaderIncludeImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
AssetOrigin:
|
||||
serializedVersion: 1
|
||||
productId: 298480
|
||||
packageName: Rukhanka Animation System 2
|
||||
packageVersion: 2.9.0
|
||||
assetPath: Packages/com.rukhanka.animation/Rukhanka.Runtime/GPUAnimationEngine/Resources/TrackSampler.hlsl
|
||||
uploadId: 897522
|
||||
Reference in New Issue
Block a user