Files
2026-05-31 14:27:52 -07:00

179 lines
6.4 KiB
HLSL

#ifndef SKINNING_HLSL_
#define SKINNING_HLSL_
/////////////////////////////////////////////////////////////////////////////////
#pragma warning (disable: 4000)
#include "Packages/com.rukhanka.animation/Rukhanka.Runtime/Common/Shaders/GPUStructures/BoneTransform.hlsl"
#include "Packages/com.rukhanka.animation/Rukhanka.Runtime/Common/Shaders/GPUStructures/DualQuaternion.hlsl"
#include "Packages/com.rukhanka.animation/Rukhanka.Runtime/Common/Shaders/GPUStructures/SkinMatrix.hlsl"
/////////////////////////////////////////////////////////////////////////////////
ByteAddressBuffer framePerVertexWorkload;
// SourceSkinnedMeshVertex
ByteAddressBuffer inputMeshVertexData;
// BoneInfluence
ByteAddressBuffer inputBoneInfluences;
// DeformedVertex
ByteAddressBuffer inputBlendShapes;
// SkinMatrix
ByteAddressBuffer frameSkinMatrices;
StructuredBuffer<float> frameBlendShapeWeights;
#ifdef RUKHANKA_HALF_DEFORMED_DATA
RWStructuredBuffer<PackedDeformedVertex> outDeformedVertices;
#else
RWStructuredBuffer<DeformedVertex> outDeformedVertices;
#endif
uint totalSkinnedVerticesCount;
uint voidMeshVertexCount;
int currentSkinnedVertexOffset;
/////////////////////////////////////////////////////////////////////////////////
DeformedVertex ApplyBlendShapes(DeformedVertex v, uint meshVertexIndex, MeshFrameDeformationDescription mfd)
{
if (mfd.baseBlendShapeWeightIndex < 0)
return v;
for (int i = 0; i < mfd.meshBlendShapesCount; ++i)
{
float blendShapeWeight = frameBlendShapeWeights[mfd.baseBlendShapeWeightIndex + i];
if (blendShapeWeight == 0)
continue;
DeformedVertex blendShapeDelta = DeformedVertex::ReadFromRawBuffer
(
inputBlendShapes,
mfd.baseInputMeshBlendShapeIndex + meshVertexIndex + i * mfd.meshVerticesCount
);
blendShapeDelta.Scale(blendShapeWeight * 0.01f);
v.position += blendShapeDelta.position;
v.normal += blendShapeDelta.normal;
v.tangent += blendShapeDelta.tangent;
}
return v;
}
/////////////////////////////////////////////////////////////////////////////////
DeformedVertex ApplySkinMatrices
(
DeformedVertex v,
uint vertexBoneWeightsOffset,
uint vertexBoneWeightsCount,
MeshFrameDeformationDescription mfd
)
{
if (mfd.baseSkinMatrixIndex < 0 || vertexBoneWeightsCount == 0)
return v;
// Skinning loop
#ifdef RUKHANKA_DUAL_QUATERNION_SKINNING
DualQuaternion adq = (DualQuaternion)0;
#endif
DeformedVertex rv = (DeformedVertex)0;
float4 refRot = 0;
float3 skinnedScale = 0;
for (uint i = 0; i < vertexBoneWeightsCount; ++i)
{
uint boneInfluenceIndex = i + vertexBoneWeightsOffset;
BoneInfluence bi = BoneInfluence::ReadFromRawBuffer(inputBoneInfluences, boneInfluenceIndex);
int skinMatrixIndex = bi.boneIndex + mfd.baseSkinMatrixIndex;
float3x4 skinMatrix = SkinMatrix::ReadFromRawBuffer(frameSkinMatrices, skinMatrixIndex);
#ifdef RUKHANKA_DUAL_QUATERNION_SKINNING
BoneTransform skinPose = BoneTransform::FromMatrix(skinMatrix);
skinnedScale += skinPose.scale * bi.weight;
if (i == 0)
refRot = skinPose.rot.value;
else if (dot(skinPose.rot.value, refRot) < 0)
bi.weight = -bi.weight;
DualQuaternion dq = DualQuaternion::Construct(skinPose.pos, skinPose.rot);
DualQuaternion sdq = DualQuaternion::Scale(dq, bi.weight);
adq = DualQuaternion::Add(adq, sdq);
#else
rv.position += mul(skinMatrix, float4(v.position, 1)) * bi.weight;
rv.normal += mul(skinMatrix, float4(v.normal, 0)) * bi.weight;
rv.tangent += mul(skinMatrix, float4(v.tangent, 0)) * bi.weight;
#endif
}
#ifdef RUKHANKA_DUAL_QUATERNION_SKINNING
adq = DualQuaternion::Normalize(adq);
BoneTransform bt = adq.GetBoneTransform();
bt.scale = skinnedScale;
rv.position = BoneTransform::TransformPoint(bt, v.position);
rv.normal = BoneTransform::TransformDirection(bt, v.normal);
rv.tangent = BoneTransform::TransformDirection(bt, v.tangent);
#endif
return rv;
}
/////////////////////////////////////////////////////////////////////////////////
[numthreads(128, 1, 1)]
void Skinning(uint tid: SV_DispatchThreadID)
{
uint skinnedVertexIndex = tid + currentSkinnedVertexOffset;
// Skip zero vertex because it is uninitialized marker
if (skinnedVertexIndex >= totalSkinnedVerticesCount || skinnedVertexIndex == 0)
{
if (skinnedVertexIndex < totalSkinnedVerticesCount + voidMeshVertexCount)
{
#ifdef RUKHANKA_HALF_DEFORMED_DATA
outDeformedVertices[skinnedVertexIndex] = (PackedDeformedVertex)0;
#else
outDeformedVertices[skinnedVertexIndex] = (DeformedVertex)0;
#endif
CHECK_STRUCTURED_BUFFER_OUT_OF_BOUNDS(RUKHANKADEBUGMARKERS_DEFORMATION_COPY_MESH_DATA, skinnedVertexIndex, outDeformedVertices);
}
return;
}
CHECK_RAW_BUFFER_OUT_OF_BOUNDS(RUKHANKADEBUGMARKERS_DEFORMATION_PER_VERTEX_WORKLOAD_READ, skinnedVertexIndex * 4, 4, framePerVertexWorkload);
uint frameDeformedMeshIndex = framePerVertexWorkload.Load(skinnedVertexIndex * 4);
CHECK_STRUCTURED_BUFFER_OUT_OF_BOUNDS(RUKHANKADEBUGMARKERS_DEFORMATION_FRAME_DEFORMED_VERTEX_READ, frameDeformedMeshIndex, frameDeformedMeshes);
MeshFrameDeformationDescription mfd = frameDeformedMeshes[frameDeformedMeshIndex];
uint meshVertexIndex = skinnedVertexIndex - mfd.baseOutVertexIndex;
uint absoluteInputMeshVertexIndex = meshVertexIndex + mfd.baseInputMeshVertexIndex;
SourceSkinnedMeshVertex smv = SourceSkinnedMeshVertex::ReadFromRawBuffer(inputMeshVertexData, absoluteInputMeshVertexIndex);
DeformedVertex rv = (DeformedVertex)0;
#ifndef RUKHANKA_INPLACE_SKINNING
rv.position = smv.position;
rv.tangent = smv.tangent;
rv.normal = smv.normal;
#endif
rv = ApplyBlendShapes(rv, meshVertexIndex, mfd);
rv = ApplySkinMatrices(rv, smv.boneWeightsOffset, smv.boneWeightsCount, mfd);
#ifdef RUKHANKA_HALF_DEFORMED_DATA
outDeformedVertices[skinnedVertexIndex] = PackedDeformedVertex::Pack(rv);
#else
outDeformedVertices[skinnedVertexIndex] = rv;
#endif
CHECK_STRUCTURED_BUFFER_OUT_OF_BOUNDS(RUKHANKADEBUGMARKERS_DEFORMATION_DEFORMED_VERTEX_WRITE, skinnedVertexIndex, outDeformedVertices);
}
/////////////////////////////////////////////////////////////////////////////////
#endif // SKINNING_HLSL_