Netcode Bootstrap

This commit is contained in:
Luis Gonzalez
2026-05-31 14:27:52 -07:00
parent 99d8d2d2a9
commit 7fa77ce821
1813 changed files with 2921554 additions and 84 deletions
@@ -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"
@@ -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
@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: fb0379f8129846944bf9d56dca4b60fc
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:
@@ -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
}
@@ -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
@@ -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
@@ -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
@@ -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_
@@ -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
@@ -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_
@@ -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
@@ -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_
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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