Netcode Bootstrap
This commit is contained in:
@@ -0,0 +1,38 @@
|
||||
using Unity.Entities;
|
||||
using Unity.Mathematics;
|
||||
using Unity.Rendering;
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
namespace Rukhanka
|
||||
{
|
||||
// Just a copy of EG SkinMatrix
|
||||
public struct SkinMatrix: IBufferElementData
|
||||
{
|
||||
public float3x4 Value;
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// Just a copy of EG BlendShapeWeight
|
||||
public struct BlendShapeWeight : IBufferElementData
|
||||
{
|
||||
public float Value;
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#if RUKHANKA_ENABLE_DEFORMATION_MOTION_VECTORS
|
||||
[MaterialProperty("_DeformationParamsForMotionVectors")]
|
||||
public struct DeformedMeshIndex: IComponentData
|
||||
{
|
||||
public uint4 Value;
|
||||
}
|
||||
#else
|
||||
[MaterialProperty("_DeformedMeshIndex")]
|
||||
public struct DeformedMeshIndex: IComponentData
|
||||
{
|
||||
public uint Value;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
+18
@@ -0,0 +1,18 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 10bc942d521b8c74698b2b8bb41ecbb9
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
AssetOrigin:
|
||||
serializedVersion: 1
|
||||
productId: 298480
|
||||
packageName: Rukhanka Animation System 2
|
||||
packageVersion: 2.9.0
|
||||
assetPath: Packages/com.rukhanka.animation/Rukhanka.Runtime/Deformation/DeformationComponents.cs
|
||||
uploadId: 897522
|
||||
+153
@@ -0,0 +1,153 @@
|
||||
using System;
|
||||
using Rukhanka.Toolbox;
|
||||
using Unity.Collections;
|
||||
using Unity.Entities;
|
||||
using Unity.Mathematics;
|
||||
using Unity.Rendering;
|
||||
using UnityEngine.Rendering;
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
namespace Rukhanka
|
||||
{
|
||||
internal struct SkinnedMeshRendererFrameDeformationData
|
||||
{
|
||||
public int skinMatrixIndex;
|
||||
public int deformedVertexIndex;
|
||||
public int blendShapeWeightIndex;
|
||||
|
||||
public static SkinnedMeshRendererFrameDeformationData MakeDefault()
|
||||
{
|
||||
var rv = new SkinnedMeshRendererFrameDeformationData()
|
||||
{
|
||||
deformedVertexIndex = -1,
|
||||
skinMatrixIndex = -1,
|
||||
blendShapeWeightIndex = -1
|
||||
};
|
||||
return rv;
|
||||
}
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
internal struct SourceMeshVertex
|
||||
{
|
||||
#if !RUKHANKA_INPLACE_SKINNING
|
||||
public float3 position;
|
||||
public float3 normal;
|
||||
public float3 tangent;
|
||||
#endif
|
||||
public uint boneWeightsOffsetAndCount;
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
internal struct DeformedVertex
|
||||
{
|
||||
public float3 position;
|
||||
public float3 normal;
|
||||
public float3 tangent;
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
internal struct PackedDeformedVertex
|
||||
{
|
||||
public uint4 pack0;
|
||||
public uint pack1;
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
internal struct BlendShapeVertexDelta
|
||||
{
|
||||
public int originalMeshVertexIndex;
|
||||
public float3 positionDelta;
|
||||
public float3 normalDelta;
|
||||
public float3 tangentDelta;
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
internal struct SkinnedMeshDescription
|
||||
{
|
||||
public int baseVertex;
|
||||
public int vertexCount;
|
||||
public int baseBoneWeightIndex;
|
||||
public int baseBlendShapeIndex;
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
internal struct MeshFrameDeformationDescription
|
||||
{
|
||||
public int baseSkinMatrixIndex;
|
||||
public int baseBlendShapeWeightIndex;
|
||||
public int baseOutVertexIndex;
|
||||
public int baseInputMeshVertexIndex;
|
||||
public int baseInputMeshBlendShapeIndex;
|
||||
public int meshVerticesCount;
|
||||
public int meshBlendShapesCount;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------------------------------------------//
|
||||
|
||||
internal struct DeformationRuntimeData: IComponentData, IDisposable
|
||||
{
|
||||
public NativeParallelHashMap<int, BRGRenderMeshArray> renderMeshArrays;
|
||||
|
||||
public NativeParallelHashMap<Hash128, SkinnedMeshDescription> registeredSkinnedMeshesMap;
|
||||
public NativeParallelHashMap<BatchMeshID, BlobAssetReference<SkinnedMeshInfoBlob>> newSkinnedMeshesToRegister;
|
||||
public NativeParallelHashMap<Entity, SkinnedMeshRendererFrameDeformationData> entityToSMRFrameDataMap;
|
||||
|
||||
public int totalSkinnedVerticesCount;
|
||||
public int totalBoneWeightsCount;
|
||||
public int totalBlendShapeVerticesCount;
|
||||
public int frameSkinMatrixCount;
|
||||
public int frameBlendShapeWeightsCount;
|
||||
public int frameDeformedVerticesCount;
|
||||
public int frameActiveDeformedMeshesCount;
|
||||
|
||||
public int maximumVerticesAcrossAllRegisteredMeshes;
|
||||
public int maximumSkinMatrixCountAcrossAllRegisteredMeshes;
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
registeredSkinnedMeshesMap.Dispose();
|
||||
newSkinnedMeshesToRegister.Dispose();
|
||||
entityToSMRFrameDataMap.Dispose();
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
public static DeformationRuntimeData Construct(ref SystemState ss)
|
||||
{
|
||||
var registerMeshAndMaterialSystem = ss.World.GetExistingSystemManaged<RegisterMaterialsAndMeshesSystem>();
|
||||
BurstAssert.IsTrue(registerMeshAndMaterialSystem != null, $"{nameof(RegisterMaterialsAndMeshesSystem)} was not found!");
|
||||
if (registerMeshAndMaterialSystem == null)
|
||||
return default;
|
||||
|
||||
var rv = new DeformationRuntimeData();
|
||||
rv.renderMeshArrays = registerMeshAndMaterialSystem.BRGRenderMeshArrays;
|
||||
BurstAssert.IsTrue(rv.renderMeshArrays.IsCreated, "Render mesh arrays is not valid. Probably wrong system creation order.");
|
||||
|
||||
rv.registeredSkinnedMeshesMap = new (0xff, Allocator.Persistent);
|
||||
rv.newSkinnedMeshesToRegister = new (0xffff, Allocator.Persistent);
|
||||
rv.entityToSMRFrameDataMap = new (0xff, Allocator.Persistent);
|
||||
rv.totalSkinnedVerticesCount = 0;
|
||||
rv.totalBoneWeightsCount = 0;
|
||||
rv.totalBlendShapeVerticesCount = 0;
|
||||
rv.frameSkinMatrixCount = 0;
|
||||
rv.frameBlendShapeWeightsCount = 0;
|
||||
rv.frameDeformedVerticesCount = 0;
|
||||
rv.frameActiveDeformedMeshesCount = 0;
|
||||
rv.maximumVerticesAcrossAllRegisteredMeshes = 0;
|
||||
rv.maximumSkinMatrixCountAcrossAllRegisteredMeshes = 0;
|
||||
|
||||
return rv;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+18
@@ -0,0 +1,18 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 3b0a18f102cadf141aeb8e3d6d34d7e6
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
AssetOrigin:
|
||||
serializedVersion: 1
|
||||
productId: 298480
|
||||
packageName: Rukhanka Animation System 2
|
||||
packageVersion: 2.9.0
|
||||
assetPath: Packages/com.rukhanka.animation/Rukhanka.Runtime/Deformation/DeformationStructures.cs
|
||||
uploadId: 897522
|
||||
+27
@@ -0,0 +1,27 @@
|
||||
using Unity.Entities;
|
||||
using Unity.Rendering;
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
namespace Rukhanka
|
||||
{
|
||||
[WorldSystemFilter(WorldSystemFilterFlags.Default | WorldSystemFilterFlags.Editor)]
|
||||
[UpdateInGroup(typeof(PresentationSystemGroup))]
|
||||
[UpdateAfter(typeof(RegisterMaterialsAndMeshesSystem))]
|
||||
[UpdateAfter(typeof(UpdatePresentationSystemGroup))]
|
||||
[UpdateBefore(typeof(EntitiesGraphicsSystem))]
|
||||
public partial class RukhankaDeformationSystemGroup: ComponentSystemGroup
|
||||
{
|
||||
protected override void OnCreate()
|
||||
{
|
||||
#if !HYBRID_RENDERER_DISABLED
|
||||
if (!EntitiesGraphicsUtils.IsEntitiesGraphicsSupportedOnSystem())
|
||||
#endif
|
||||
{
|
||||
Enabled = false;
|
||||
UnityEngine.Debug.Log("No SRP present, no compute shader support, or running with -nographics. Rukhanka Mesh Deformation Systems disabled.");
|
||||
}
|
||||
base.OnCreate();
|
||||
}
|
||||
}
|
||||
}
|
||||
+18
@@ -0,0 +1,18 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 1c93484e0aed8374c8d20b05b1ab679a
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
AssetOrigin:
|
||||
serializedVersion: 1
|
||||
productId: 298480
|
||||
packageName: Rukhanka Animation System 2
|
||||
packageVersion: 2.9.0
|
||||
assetPath: Packages/com.rukhanka.animation/Rukhanka.Runtime/Deformation/DeformationSystemGroup.cs
|
||||
uploadId: 897522
|
||||
+554
@@ -0,0 +1,554 @@
|
||||
using Rukhanka.Toolbox;
|
||||
using Unity.Assertions;
|
||||
using Unity.Collections;
|
||||
using Unity.Collections.LowLevel.Unsafe;
|
||||
using Unity.Entities;
|
||||
using Unity.Jobs;
|
||||
using Unity.Mathematics;
|
||||
using Unity.Rendering;
|
||||
using UnityEngine;
|
||||
using UnityEngine.Rendering;
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
namespace Rukhanka
|
||||
{
|
||||
|
||||
[WorldSystemFilter(WorldSystemFilterFlags.Default | WorldSystemFilterFlags.Editor)]
|
||||
[UpdateInGroup(typeof(RukhankaDeformationSystemGroup))]
|
||||
[UpdateAfter(typeof(SkinnedMeshPreparationSystem))]
|
||||
public partial class MeshDeformationSystem: SystemBase
|
||||
{
|
||||
GraphicsBuffer meshVertexDataCB;
|
||||
GraphicsBuffer meshBoneWeightDataCB;
|
||||
GraphicsBuffer meshBlendShapesDataCB;
|
||||
GraphicsBuffer newMeshBonesPerVertexCB;
|
||||
GraphicsBuffer frameVertexSkinningWorkloadCB;
|
||||
|
||||
GraphicsBuffer finalDeformedVerticesCB;
|
||||
#if RUKHANKA_ENABLE_DEFORMATION_MOTION_VECTORS
|
||||
// Double buffer scheme. Current frame will read previous frame data to calculate motion delta
|
||||
GraphicsBuffer finalDeformedVerticesCB1;
|
||||
uint bufferSwapCounter = 0;
|
||||
#endif
|
||||
|
||||
SparseUploader sparseUploader;
|
||||
// Small dummy raw compute buffer to calm down SparseUploader initialization
|
||||
GraphicsBuffer dummyRawGB;
|
||||
FrameFencedGPUBufferPool<SkinMatrix> frameSkinMatricesBuffer;
|
||||
FrameFencedGPUBufferPool<float> frameBlendShapeWeightsBuffer;
|
||||
FrameFencedGPUBufferPool<MeshFrameDeformationDescription> frameMeshDeformationDescriptionBuffer;
|
||||
|
||||
ComputeShader meshDeformationSystemCS;
|
||||
ComputeKernel fillInitialMeshDataKernel;
|
||||
ComputeKernel fillInitialMeshBlendShapesKernel;
|
||||
ComputeKernel createPerVertexDeformationWorkloadKernel;
|
||||
ComputeKernel skinningKernel;
|
||||
|
||||
EntitiesGraphicsSystem entitiesGraphicsSystem;
|
||||
GPUAnimationSystem gpuAnimationSystem;
|
||||
|
||||
SharedComponentTypeHandle<RenderMeshArray> renderMeshArrayTypeHandle;
|
||||
|
||||
struct InputMeshVertexDesc
|
||||
{
|
||||
public VertexAttribute vertexAttribute;
|
||||
public VertexAttributeFormat vertexAttributeFormat;
|
||||
public int streamIndex;
|
||||
public int dimension;
|
||||
}
|
||||
|
||||
static readonly InputMeshVertexDesc[] inputMeshVertexDesc =
|
||||
{
|
||||
new () {vertexAttribute = VertexAttribute.Position, vertexAttributeFormat = VertexAttributeFormat.Float32, streamIndex = 0, dimension = 3 },
|
||||
new () {vertexAttribute = VertexAttribute.Normal, vertexAttributeFormat = VertexAttributeFormat.Float32, streamIndex = 0, dimension = 3 },
|
||||
new () {vertexAttribute = VertexAttribute.Tangent, vertexAttributeFormat = VertexAttributeFormat.Float32, streamIndex = 0, dimension = 4 },
|
||||
};
|
||||
|
||||
EntityQuery activeDeformedEntitiesQuery, activeDeformedMeshesQuery;
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
protected override void OnCreate()
|
||||
{
|
||||
#if !HYBRID_RENDERER_DISABLED
|
||||
if (!EntitiesGraphicsUtils.IsEntitiesGraphicsSupportedOnSystem())
|
||||
#endif
|
||||
{
|
||||
Enabled = false;
|
||||
return;
|
||||
}
|
||||
|
||||
renderMeshArrayTypeHandle = GetSharedComponentTypeHandle<RenderMeshArray>();
|
||||
entitiesGraphicsSystem = World.GetExistingSystemManaged<EntitiesGraphicsSystem>();
|
||||
gpuAnimationSystem = World.GetExistingSystemManaged<GPUAnimationSystem>();
|
||||
frameSkinMatricesBuffer = new (0xffff, GraphicsBuffer.Target.Raw, GraphicsBuffer.UsageFlags.None);
|
||||
frameBlendShapeWeightsBuffer = new (0xffff, GraphicsBuffer.Target.Structured, GraphicsBuffer.UsageFlags.LockBufferForWrite);
|
||||
frameMeshDeformationDescriptionBuffer = new (0xffff, GraphicsBuffer.Target.Structured, GraphicsBuffer.UsageFlags.LockBufferForWrite);
|
||||
|
||||
dummyRawGB = new (GraphicsBuffer.Target.Raw, GraphicsBuffer.UsageFlags.None, 1, 4);
|
||||
sparseUploader = new (dummyRawGB);
|
||||
|
||||
activeDeformedEntitiesQuery = SystemAPI.QueryBuilder()
|
||||
.WithAll<SkinnedMeshRendererComponent>()
|
||||
.Build();
|
||||
|
||||
activeDeformedMeshesQuery = SystemAPI.QueryBuilder()
|
||||
.WithAll<SkinnedMeshRendererComponent>()
|
||||
.Build();
|
||||
|
||||
RequireForUpdate(activeDeformedEntitiesQuery);
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
protected override void OnDestroy()
|
||||
{
|
||||
#if !HYBRID_RENDERER_DISABLED
|
||||
if (!EntitiesGraphicsUtils.IsEntitiesGraphicsSupportedOnSystem())
|
||||
#endif
|
||||
{ return; }
|
||||
|
||||
meshVertexDataCB?.Dispose();
|
||||
meshBoneWeightDataCB?.Dispose();
|
||||
meshBlendShapesDataCB?.Dispose();
|
||||
newMeshBonesPerVertexCB?.Dispose();
|
||||
frameVertexSkinningWorkloadCB?.Dispose();
|
||||
|
||||
finalDeformedVerticesCB?.Dispose();
|
||||
#if RUKHANKA_ENABLE_DEFORMATION_MOTION_VECTORS
|
||||
finalDeformedVerticesCB1?.Dispose();
|
||||
#endif
|
||||
|
||||
frameMeshDeformationDescriptionBuffer?.Dispose();
|
||||
frameSkinMatricesBuffer?.Dispose();
|
||||
frameBlendShapeWeightsBuffer?.Dispose();
|
||||
sparseUploader.Dispose();
|
||||
dummyRawGB.Dispose();
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
protected override void OnUpdate()
|
||||
{
|
||||
renderMeshArrayTypeHandle.Update(this);
|
||||
|
||||
ref var deformationRuntimeData = ref SystemAPI.GetSingletonRW<DeformationRuntimeData>().ValueRW;
|
||||
|
||||
var resetFrameCountersJH = ResetFrameCounters(ref deformationRuntimeData, Dependency);
|
||||
var prepareSkinningDataJH = PrepareMeshGPUSkinningData(ref deformationRuntimeData, resetFrameCountersJH);
|
||||
|
||||
// Complete previous jobs here, because we need to know skin matrix buffer and blend shape weights sizes here to resize GPU buffers
|
||||
prepareSkinningDataJH.Complete();
|
||||
|
||||
var (copySkinMatricesToGPUBufferJH, skinMatrixThreadedUploader) = CopySkinMatricesToGPUBuffer(deformationRuntimeData, default);
|
||||
var copyBlendShapeWeightsToGPUBufferJH = CopyBlendShapeWeightsToGPUBuffer(deformationRuntimeData, default);
|
||||
var copyFrameDeformationDataToGPUBuffersJH = JobHandle.CombineDependencies(copySkinMatricesToGPUBufferJH, copyBlendShapeWeightsToGPUBufferJH);
|
||||
|
||||
// Complete dependency second time before compute shader execution. Need to make sure that SkinMatrix GPU buffer data writes
|
||||
// is complete.
|
||||
copyFrameDeformationDataToGPUBuffersJH.Complete();
|
||||
|
||||
sparseUploader.EndAndCommit(skinMatrixThreadedUploader);
|
||||
frameBlendShapeWeightsBuffer.UnlockBufferAfterWrite(deformationRuntimeData.frameBlendShapeWeightsCount);
|
||||
frameMeshDeformationDescriptionBuffer.UnlockBufferAfterWrite(deformationRuntimeData.frameActiveDeformedMeshesCount);
|
||||
|
||||
CopyNewMeshesToInitialMeshDataBuffer(deformationRuntimeData);
|
||||
|
||||
// Need to inject GPU animation system here, for GPU animated entities skin matrices computation directly to skin matrix frame GPU buffer
|
||||
// It is not pretty approach, I know
|
||||
gpuAnimationSystem?.BuildSkinMatrices(deformationRuntimeData.entityToSMRFrameDataMap, frameSkinMatricesBuffer);
|
||||
|
||||
#if RUKHANKA_INPLACE_SKINNING
|
||||
SetInplaceSkinningGlobalBuffers();
|
||||
#else
|
||||
ScheduleSkinningDispatch(deformationRuntimeData);
|
||||
#endif
|
||||
|
||||
frameSkinMatricesBuffer.EndFrame();
|
||||
sparseUploader.FrameCleanup();
|
||||
frameBlendShapeWeightsBuffer.EndFrame();
|
||||
frameMeshDeformationDescriptionBuffer.EndFrame();
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
unsafe JobHandle ResetFrameCounters(ref DeformationRuntimeData drd, JobHandle dependsOn)
|
||||
{
|
||||
var resetFrameCountersJob = new ResetFrameCountersJob()
|
||||
{
|
||||
frameActiveDeformedMeshesCounter = new UnsafeAtomicCounter32(UnsafeUtility.AddressOf(ref drd.frameActiveDeformedMeshesCount))
|
||||
};
|
||||
|
||||
var rv = resetFrameCountersJob.Schedule(dependsOn);
|
||||
return rv;
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void SetInplaceSkinningGlobalBuffers()
|
||||
{
|
||||
Shader.SetGlobalBuffer(ShaderID_frameDeformedMeshes, frameMeshDeformationDescriptionBuffer);
|
||||
Shader.SetGlobalBuffer(ShaderID_frameSkinMatrices, frameSkinMatricesBuffer);
|
||||
Shader.SetGlobalBuffer(ShaderID_frameBlendShapeWeights, frameBlendShapeWeightsBuffer);
|
||||
Shader.SetGlobalBuffer(ShaderID_inputBlendShapes, meshBlendShapesDataCB);
|
||||
Shader.SetGlobalBuffer(ShaderID_inputBoneInfluences, meshBoneWeightDataCB);
|
||||
Shader.SetGlobalBuffer(ShaderID_inputMeshVertexData, meshVertexDataCB);
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void ScheduleSkinningDispatch(in DeformationRuntimeData drd)
|
||||
{
|
||||
var frameDeformedVerticesCount = drd.frameDeformedVerticesCount;
|
||||
frameVertexSkinningWorkloadCB = ComputeBufferTools.CreateOrGrowGraphicsBuffer<uint>(frameVertexSkinningWorkloadCB, GraphicsBuffer.Target.Raw, GraphicsBuffer.UsageFlags.None, frameDeformedVerticesCount, false);
|
||||
|
||||
// Schedule workload generation dispatch if we have visible/existing skinned mesh renderers
|
||||
if (drd.frameActiveDeformedMeshesCount > 0)
|
||||
{
|
||||
var cs0 = createPerVertexDeformationWorkloadKernel.computeShader;
|
||||
cs0.SetBuffer(createPerVertexDeformationWorkloadKernel, ShaderID_outFramePerVertexWorkload, frameVertexSkinningWorkloadCB);
|
||||
cs0.SetBuffer(createPerVertexDeformationWorkloadKernel, ShaderID_frameDeformedMeshes, frameMeshDeformationDescriptionBuffer);
|
||||
cs0.SetInt(ShaderID_totalDeformedMeshesCount, drd.frameActiveDeformedMeshesCount);
|
||||
createPerVertexDeformationWorkloadKernel.Dispatch(drd.frameActiveDeformedMeshesCount, 1, 1);
|
||||
}
|
||||
|
||||
var deformedVerticesBufferSize = frameDeformedVerticesCount + drd.maximumVerticesAcrossAllRegisteredMeshes;
|
||||
#if RUKHANKA_HALF_DEFORMED_DATA
|
||||
finalDeformedVerticesCB = ComputeBufferTools.CreateOrGrowGraphicsBuffer<PackedDeformedVertex>(finalDeformedVerticesCB, GraphicsBuffer.Target.Structured, GraphicsBuffer.UsageFlags.None, deformedVerticesBufferSize, false);
|
||||
#else
|
||||
finalDeformedVerticesCB = ComputeBufferTools.CreateOrGrowGraphicsBuffer<DeformedVertex>(finalDeformedVerticesCB, GraphicsBuffer.Target.Structured, GraphicsBuffer.UsageFlags.None, deformedVerticesBufferSize, false);
|
||||
#endif
|
||||
|
||||
var outDeformedVerticesCB = finalDeformedVerticesCB;
|
||||
|
||||
// Schedule skinning even for zero visible meshes, because we need to actualize void mesh zone to properly cull invisible meshes
|
||||
if (deformedVerticesBufferSize > 0)
|
||||
{
|
||||
var cs1 = skinningKernel.computeShader;
|
||||
cs1.SetBuffer(skinningKernel, ShaderID_frameDeformedMeshes, frameMeshDeformationDescriptionBuffer);
|
||||
cs1.SetBuffer(skinningKernel, ShaderID_framePerVertexWorkload, frameVertexSkinningWorkloadCB);
|
||||
cs1.SetBuffer(skinningKernel, ShaderID_inputMeshVertexData, meshVertexDataCB);
|
||||
cs1.SetBuffer(skinningKernel, ShaderID_inputBoneInfluences, meshBoneWeightDataCB);
|
||||
cs1.SetBuffer(skinningKernel, ShaderID_inputBlendShapes, meshBlendShapesDataCB);
|
||||
cs1.SetBuffer(skinningKernel, ShaderID_frameSkinMatrices, frameSkinMatricesBuffer);
|
||||
cs1.SetBuffer(skinningKernel, ShaderID_frameBlendShapeWeights, frameBlendShapeWeightsBuffer);
|
||||
cs1.SetBuffer(skinningKernel, ShaderID_outDeformedVertices, outDeformedVerticesCB);
|
||||
cs1.SetInt(ShaderID_totalSkinnedVerticesCount, frameDeformedVerticesCount);
|
||||
cs1.SetInt(ShaderID_voidMeshVertexCount, drd.maximumVerticesAcrossAllRegisteredMeshes);
|
||||
|
||||
var maxWorkGroupSize = (int)skinningKernel.GetMaxWorkGroupSize().x;
|
||||
var numDispatchCalls = 0;
|
||||
for (var currentVertexOffset = 0; currentVertexOffset < deformedVerticesBufferSize; currentVertexOffset += maxWorkGroupSize)
|
||||
{
|
||||
var deformedVertexCount = math.min(maxWorkGroupSize, deformedVerticesBufferSize - currentVertexOffset);
|
||||
cs1.SetInt(ShaderID_currentSkinnedVertexOffset, currentVertexOffset);
|
||||
skinningKernel.Dispatch(deformedVertexCount, 1, 1);
|
||||
numDispatchCalls += 1;
|
||||
}
|
||||
}
|
||||
|
||||
Shader.SetGlobalBuffer(ShaderID_DeformedMeshData, outDeformedVerticesCB);
|
||||
|
||||
#if RUKHANKA_ENABLE_DEFORMATION_MOTION_VECTORS
|
||||
if (finalDeformedVerticesCB1 != null)
|
||||
Shader.SetGlobalBuffer(ShaderID_PreviousFrameDeformedMeshData, finalDeformedVerticesCB1);
|
||||
(finalDeformedVerticesCB, finalDeformedVerticesCB1) = (finalDeformedVerticesCB1, finalDeformedVerticesCB);
|
||||
bufferSwapCounter += 1;
|
||||
#endif
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
(JobHandle, ThreadedSparseUploader) CopySkinMatricesToGPUBuffer(in DeformationRuntimeData drd, JobHandle dependsOn)
|
||||
{
|
||||
var skinMatrixCount = drd.frameSkinMatrixCount;
|
||||
frameSkinMatricesBuffer.Grow(skinMatrixCount);
|
||||
frameSkinMatricesBuffer.BeginFrame();
|
||||
sparseUploader.ReplaceBuffer(frameSkinMatricesBuffer);
|
||||
|
||||
var q = SystemAPI.QueryBuilder()
|
||||
.WithAll<SkinnedMeshRendererComponent>()
|
||||
.Build();
|
||||
var numEntities = q.CalculateEntityCount();
|
||||
|
||||
var skinMatrixDataSize = skinMatrixCount * UnsafeUtility.SizeOf<SkinMatrix>();
|
||||
var maxDataUploadSize = drd.maximumSkinMatrixCountAcrossAllRegisteredMeshes * UnsafeUtility.SizeOf<SkinMatrix>();
|
||||
var gpuSkinMatrixThreadedUploader = sparseUploader.Begin(skinMatrixDataSize, maxDataUploadSize, numEntities);
|
||||
|
||||
var isEditor = (this.World.Flags & WorldFlags.Editor) == WorldFlags.Editor;
|
||||
var copySkinMatricesToGPUJob = new CopySkinMatricesToGPUJob()
|
||||
{
|
||||
entityToSMRFrameDataMap = drd.entityToSMRFrameDataMap,
|
||||
mappedGPUSkinMatrixBuffer = gpuSkinMatrixThreadedUploader,
|
||||
gpuAnimationEngineTag = SystemAPI.GetComponentLookup<GPUAnimationEngineTag>(true),
|
||||
isEditor = isEditor,
|
||||
};
|
||||
|
||||
var jh = copySkinMatricesToGPUJob.ScheduleParallel(dependsOn);
|
||||
return (jh, gpuSkinMatrixThreadedUploader);
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
JobHandle CopyBlendShapeWeightsToGPUBuffer(in DeformationRuntimeData drd, JobHandle dependsOn)
|
||||
{
|
||||
var blendShapeWeightsCount = drd.frameBlendShapeWeightsCount;
|
||||
frameBlendShapeWeightsBuffer.Grow(blendShapeWeightsCount);
|
||||
frameBlendShapeWeightsBuffer.BeginFrame();
|
||||
|
||||
var gpuBufferOutArr = frameBlendShapeWeightsBuffer.LockBufferForWrite(0, blendShapeWeightsCount);
|
||||
|
||||
var copyBlendShapeWeightsToGPUJob = new CopyBlendShapeWeightToGPUJob()
|
||||
{
|
||||
entityToSMRFrameDataMap = drd.entityToSMRFrameDataMap,
|
||||
mappedGPUBlendShapeWeightsBuffer = gpuBufferOutArr
|
||||
};
|
||||
|
||||
var jh = copyBlendShapeWeightsToGPUJob.ScheduleParallel(dependsOn);
|
||||
return jh;
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
JobHandle PrepareMeshGPUSkinningData(ref DeformationRuntimeData drd, JobHandle dependsOn)
|
||||
{
|
||||
var deformedMeshCount = activeDeformedEntitiesQuery.CalculateEntityCount();
|
||||
frameMeshDeformationDescriptionBuffer.Grow(deformedMeshCount);
|
||||
frameMeshDeformationDescriptionBuffer.BeginFrame();
|
||||
var gpuBufferMeshDeformationOutArr = frameMeshDeformationDescriptionBuffer.LockBufferForWrite(0, deformedMeshCount);
|
||||
|
||||
var setDeformedMeshIndicesJH = SetDeformedMeshIndicesForRenderEntities(ref drd, dependsOn);
|
||||
var prepareSkinningDataJH = PrepareSkinningCommands(ref drd, gpuBufferMeshDeformationOutArr, dependsOn);
|
||||
|
||||
var rv = JobHandle.CombineDependencies(setDeformedMeshIndicesJH, prepareSkinningDataJH);
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
JobHandle PrepareMeshGPUSkinningDataForInplaceSkinning(ref DeformationRuntimeData drd, JobHandle dependsOn)
|
||||
{
|
||||
var deformedMeshCount = activeDeformedMeshesQuery.CalculateEntityCount();
|
||||
frameMeshDeformationDescriptionBuffer.Grow(deformedMeshCount);
|
||||
frameMeshDeformationDescriptionBuffer.BeginFrame();
|
||||
var gpuBufferMeshDeformationOutArr = frameMeshDeformationDescriptionBuffer.LockBufferForWrite(0, deformedMeshCount);
|
||||
|
||||
var setDeformedMeshIndicesJH = SetDeformedMeshIndicesForRenderEntities(ref drd, dependsOn);
|
||||
var prepareSkinningDataJH = PrepareSkinningCommands(ref drd, gpuBufferMeshDeformationOutArr, dependsOn);
|
||||
|
||||
var rv = JobHandle.CombineDependencies(setDeformedMeshIndicesJH, prepareSkinningDataJH);
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
unsafe JobHandle PrepareSkinningCommands(ref DeformationRuntimeData drd, NativeArray<MeshFrameDeformationDescription> gpuBufferMeshDeformationOutArr, JobHandle dependsOn)
|
||||
{
|
||||
var prepareSkinningDataJob = new PrepareSkinningCommandsJob()
|
||||
{
|
||||
meshFrameDeformationData = gpuBufferMeshDeformationOutArr,
|
||||
entityToSMRFrameDataMap = drd.entityToSMRFrameDataMap,
|
||||
registeredSkinnedMeshes = drd.registeredSkinnedMeshesMap,
|
||||
frameActiveDeformedMeshesCounter = new UnsafeAtomicCounter32(UnsafeUtility.AddressOf(ref drd.frameActiveDeformedMeshesCount))
|
||||
};
|
||||
var jh = prepareSkinningDataJob.ScheduleParallel(dependsOn);
|
||||
return jh;
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
unsafe JobHandle SetDeformedMeshIndicesForRenderEntities(ref DeformationRuntimeData drd, JobHandle dependsOn)
|
||||
{
|
||||
var setDeformedMeshIndexJob = new SetDeformedMeshIndicesJob()
|
||||
{
|
||||
frameDeformedVerticesCounter = new UnsafeAtomicCounter32(UnsafeUtility.AddressOf(ref drd.frameDeformedVerticesCount)),
|
||||
entityToSMRFrameDataMap = drd.entityToSMRFrameDataMap,
|
||||
#if RUKHANKA_ENABLE_DEFORMATION_MOTION_VECTORS
|
||||
currentFrameDeformedBufferIndex = (int)(bufferSwapCounter & 1)
|
||||
#endif
|
||||
};
|
||||
|
||||
var jh = setDeformedMeshIndexJob.ScheduleParallel(dependsOn);
|
||||
return jh;
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void InitComputeShaders()
|
||||
{
|
||||
if (meshDeformationSystemCS != null)
|
||||
return;
|
||||
|
||||
meshDeformationSystemCS = Resources.Load<ComputeShader>("RukhankaMeshDeformation");
|
||||
fillInitialMeshDataKernel = new ComputeKernel(meshDeformationSystemCS, "CopyInitialMeshData");
|
||||
fillInitialMeshBlendShapesKernel = new ComputeKernel(meshDeformationSystemCS, "CopyInitialMeshBlendShapes");
|
||||
createPerVertexDeformationWorkloadKernel = new ComputeKernel(meshDeformationSystemCS, "CreatePerVertexDeformationWorkload");
|
||||
skinningKernel = new ComputeKernel(meshDeformationSystemCS, "Skinning");
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void CopyNewMeshesToInitialMeshDataBuffer(in DeformationRuntimeData drd)
|
||||
{
|
||||
if (drd.newSkinnedMeshesToRegister.IsEmpty)
|
||||
return;
|
||||
|
||||
meshVertexDataCB = ComputeBufferTools.CreateOrGrowGraphicsBuffer<SourceMeshVertex>(meshVertexDataCB, GraphicsBuffer.Target.Raw, GraphicsBuffer.UsageFlags.None, drd.totalSkinnedVerticesCount, true);
|
||||
meshBoneWeightDataCB = ComputeBufferTools.CreateOrGrowGraphicsBuffer<BoneWeight1>(meshBoneWeightDataCB, GraphicsBuffer.Target.Raw, GraphicsBuffer.UsageFlags.None, drd.totalBoneWeightsCount, true);
|
||||
meshBlendShapesDataCB = ComputeBufferTools.CreateOrGrowGraphicsBuffer<DeformedVertex>(meshBlendShapesDataCB, GraphicsBuffer.Target.Raw, GraphicsBuffer.UsageFlags.None, drd.totalBlendShapeVerticesCount, true);
|
||||
|
||||
InitComputeShaders();
|
||||
var meshToBoneWeightsOffsetMap = CreateNewMeshesBoneIndicesComputeBuffer(drd);
|
||||
|
||||
sparseUploader.ReplaceBuffer(meshBoneWeightDataCB);
|
||||
var boneWeightDataSize = drd.totalBoneWeightsCount * UnsafeUtility.SizeOf<BoneWeight1>();
|
||||
var tsu = sparseUploader.Begin(boneWeightDataSize, boneWeightDataSize, 1);
|
||||
|
||||
foreach (var sm in drd.newSkinnedMeshesToRegister)
|
||||
{
|
||||
var batchMeshID = sm.Key;
|
||||
var skinnedMeshHash = sm.Value.Value.hash;
|
||||
var smd = drd.registeredSkinnedMeshesMap[skinnedMeshHash];
|
||||
var mesh = entitiesGraphicsSystem.GetMesh(batchMeshID);
|
||||
var boneWeightsOffsetForMesh = meshToBoneWeightsOffsetMap[batchMeshID];
|
||||
|
||||
CopyMeshVertexData(smd, boneWeightsOffsetForMesh, mesh);
|
||||
CopyMeshBoneWeightsData(smd, mesh, tsu);
|
||||
CopyMeshBlendShapes(smd, mesh);
|
||||
}
|
||||
sparseUploader.EndAndCommit(tsu);
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
unsafe NativeHashMap<BatchMeshID, int> CreateNewMeshesBoneIndicesComputeBuffer(in DeformationRuntimeData drd)
|
||||
{
|
||||
var meshToBoneWeightsOffsetMap = new NativeHashMap<BatchMeshID, int>(0xff, Allocator.Temp);
|
||||
var newMeshesBonesPerVertexData = new NativeList<uint>(0xff, Allocator.Temp);
|
||||
|
||||
foreach (var newMesh in drd.newSkinnedMeshesToRegister)
|
||||
{
|
||||
var baseVertexIndex = newMeshesBonesPerVertexData.Length;
|
||||
var mesh = entitiesGraphicsSystem.GetMesh(newMesh.Key);
|
||||
|
||||
if (!HasSupportedVertexLayout(mesh))
|
||||
continue;
|
||||
|
||||
meshToBoneWeightsOffsetMap[newMesh.Key] = baseVertexIndex;
|
||||
newMeshesBonesPerVertexData.Resize(baseVertexIndex + mesh.vertexCount, NativeArrayOptions.UninitializedMemory);
|
||||
|
||||
ref var bwi = ref newMesh.Value.Value.boneWeightsIndices;
|
||||
//BurstAssert.IsTrue(bwi.Length == mesh.vertexCount, "Bone weights offsets array does not match vertex count.");
|
||||
UnsafeUtility.MemCpy(newMeshesBonesPerVertexData.GetUnsafePtr() + baseVertexIndex, bwi.GetUnsafePtr(), bwi.Length * 4);
|
||||
}
|
||||
|
||||
newMeshBonesPerVertexCB = ComputeBufferTools.CreateOrGrowGraphicsBuffer<uint>(newMeshBonesPerVertexCB, GraphicsBuffer.Target.Raw, GraphicsBuffer.UsageFlags.None, newMeshesBonesPerVertexData.Length, false);
|
||||
newMeshBonesPerVertexCB.SetData(newMeshesBonesPerVertexData.AsArray());
|
||||
return meshToBoneWeightsOffsetMap;
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void CopyMeshBlendShapes(SkinnedMeshDescription smd, Mesh mesh)
|
||||
{
|
||||
if (mesh.blendShapeCount == 0)
|
||||
return;
|
||||
|
||||
using var meshAllBlendShapes = mesh.GetBlendShapeBuffer(BlendShapeBufferLayout.PerShape);
|
||||
var blendShapeVertexDeltaSize = UnsafeUtility.SizeOf<BlendShapeVertexDelta>();
|
||||
Assert.IsTrue(blendShapeVertexDeltaSize == meshAllBlendShapes.stride);
|
||||
|
||||
var cs = fillInitialMeshBlendShapesKernel.computeShader;
|
||||
cs.SetBuffer(fillInitialMeshBlendShapesKernel, ShaderID_meshBlendShapesBuffer, meshAllBlendShapes);
|
||||
cs.SetBuffer(fillInitialMeshBlendShapesKernel, ShaderID_outInitialMeshBlendShapesData, meshBlendShapesDataCB);
|
||||
|
||||
var deformedVertexSize = UnsafeUtility.SizeOf<DeformedVertex>();
|
||||
ComputeBufferTools.Clear(meshBlendShapesDataCB, (uint)(smd.baseBlendShapeIndex * deformedVertexSize), (uint)(smd.vertexCount * deformedVertexSize * mesh.blendShapeCount));
|
||||
|
||||
for (var i = 0; i < mesh.blendShapeCount; ++i)
|
||||
{
|
||||
var bsr = mesh.GetBlendShapeBufferRange(i);
|
||||
cs.SetInt(ShaderID_inputBlendShapeVerticesCount, (int)(bsr.endIndex - bsr.startIndex) + 1);
|
||||
cs.SetInt(ShaderID_inputBlendShapeVertexOffset, (int)bsr.startIndex);
|
||||
cs.SetInt(ShaderID_outBlendShapeVertexOffset, smd.baseBlendShapeIndex + i * smd.vertexCount );
|
||||
fillInitialMeshBlendShapesKernel.Dispatch(smd.vertexCount, 1, 1);
|
||||
}
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void CopyMeshBoneWeightsData(SkinnedMeshDescription smd, Mesh mesh, ThreadedSparseUploader boneWeightDataUploader)
|
||||
{
|
||||
var meshAllBoneWeights = mesh.GetAllBoneWeights();
|
||||
boneWeightDataUploader.AddUpload(meshAllBoneWeights, smd.baseBoneWeightIndex * UnsafeUtility.SizeOf<BoneWeight1>(), 1);
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void CopyMeshVertexData(SkinnedMeshDescription smd, int meshBoneWeightsOffset, Mesh mesh)
|
||||
{
|
||||
// Copy initial vertex data
|
||||
mesh.vertexBufferTarget |= GraphicsBuffer.Target.Raw;
|
||||
using var meshVertexBuffer = mesh.GetVertexBuffer(0);
|
||||
|
||||
meshDeformationSystemCS.SetInt(ShaderID_totalMeshVertices, smd.vertexCount);
|
||||
meshDeformationSystemCS.SetInt(ShaderID_outDataVertexOffset, smd.baseVertex);
|
||||
var vertexBufferStride = mesh.GetVertexBufferStride(0);
|
||||
meshDeformationSystemCS.SetInt(ShaderID_inputVertexSizeInBytes, vertexBufferStride);
|
||||
meshDeformationSystemCS.SetInt(ShaderID_inputBonesWeightsDataOffset, meshBoneWeightsOffset);
|
||||
meshDeformationSystemCS.SetInt(ShaderID_outBonesWeightsDataOffset, smd.baseBoneWeightIndex);
|
||||
meshDeformationSystemCS.SetBuffer(fillInitialMeshDataKernel, ShaderID_meshVertexData, meshVertexBuffer);
|
||||
meshDeformationSystemCS.SetBuffer(fillInitialMeshDataKernel, ShaderID_outInitialDeformedMeshData, meshVertexDataCB);
|
||||
meshDeformationSystemCS.SetBuffer(fillInitialMeshDataKernel, ShaderID_meshBonesPerVertexData, newMeshBonesPerVertexCB);
|
||||
|
||||
fillInitialMeshDataKernel.Dispatch(smd.vertexCount, 1, 1);
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
bool HasSupportedVertexLayout(Mesh mesh)
|
||||
{
|
||||
if (mesh.vertexAttributeCount < inputMeshVertexDesc.Length)
|
||||
{
|
||||
Debug.LogError($"Unsupported vertex layout for deformations in mesh ({mesh.name}). Expecting {inputMeshVertexDesc.Length} attributes but mash has only {mesh.vertexAttributeCount}.");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Check each attribute
|
||||
for (var i = 0; i < inputMeshVertexDesc.Length; ++i)
|
||||
{
|
||||
var attrib = mesh.GetVertexAttribute(i);
|
||||
var vd = inputMeshVertexDesc[i];
|
||||
|
||||
if (attrib.attribute != vd.vertexAttribute)
|
||||
{
|
||||
Debug.LogError($"Attribute mismatch for deformations in mesh ({mesh.name}). Expecting '{vd.vertexAttribute}', got '{attrib.attribute}'.");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (attrib.format != vd.vertexAttributeFormat)
|
||||
{
|
||||
Debug.LogError($"Format mismatch for deformations in mesh ({mesh.name}). Expecting '{vd.vertexAttributeFormat}', got '{attrib.format}'.");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (attrib.dimension != vd.dimension)
|
||||
{
|
||||
Debug.LogError($"Attribute dimension mismatch for deformations in mesh ({mesh.name}). Expecting '{vd.dimension}', got '{attrib.dimension}'.");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (attrib.stream != vd.streamIndex)
|
||||
{
|
||||
Debug.LogError($"Attribute stream index mismatch for deformations in mesh ({mesh.name}). Expecting '{vd.streamIndex}', got '{attrib.stream}'.");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
+18
@@ -0,0 +1,18 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 4bc9121c8c63c494089c778003a9a9b2
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
AssetOrigin:
|
||||
serializedVersion: 1
|
||||
productId: 298480
|
||||
packageName: Rukhanka Animation System 2
|
||||
packageVersion: 2.9.0
|
||||
assetPath: Packages/com.rukhanka.animation/Rukhanka.Runtime/Deformation/MeshDeformationSystem.cs
|
||||
uploadId: 897522
|
||||
+191
@@ -0,0 +1,191 @@
|
||||
using Rukhanka.Toolbox;
|
||||
using Unity.Burst;
|
||||
using Unity.Collections;
|
||||
using Unity.Collections.LowLevel.Unsafe;
|
||||
using Unity.Entities;
|
||||
using Unity.Jobs;
|
||||
using Unity.Rendering;
|
||||
using Hash128 = Unity.Entities.Hash128;
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
namespace Rukhanka
|
||||
{
|
||||
public partial class MeshDeformationSystem
|
||||
{
|
||||
|
||||
//-----------------------------------------------------------------------------------------------------------------//
|
||||
|
||||
[BurstCompile]
|
||||
struct ResetFrameCountersJob: IJob
|
||||
{
|
||||
[NativeDisableUnsafePtrRestriction]
|
||||
public UnsafeAtomicCounter32 frameActiveDeformedMeshesCounter;
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
public void Execute()
|
||||
{
|
||||
frameActiveDeformedMeshesCounter.Reset(0);
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------------------------------------------//
|
||||
|
||||
[BurstCompile]
|
||||
partial struct PrepareSkinningCommandsJob: IJobEntity
|
||||
{
|
||||
[ReadOnly]
|
||||
public NativeParallelHashMap<Entity, SkinnedMeshRendererFrameDeformationData> entityToSMRFrameDataMap;
|
||||
[ReadOnly]
|
||||
public NativeParallelHashMap<Hash128, SkinnedMeshDescription> registeredSkinnedMeshes;
|
||||
|
||||
[NativeDisableUnsafePtrRestriction]
|
||||
public UnsafeAtomicCounter32 frameActiveDeformedMeshesCounter;
|
||||
[NativeDisableParallelForRestriction]
|
||||
public NativeArray<MeshFrameDeformationDescription> meshFrameDeformationData;
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void Execute(Entity e, in SkinnedMeshRendererComponent arc)
|
||||
{
|
||||
if (!entityToSMRFrameDataMap.TryGetValue(e, out var smrdd))
|
||||
return;
|
||||
|
||||
if (!registeredSkinnedMeshes.TryGetValue(arc.smrInfoBlob.Value.hash, out var smd))
|
||||
{
|
||||
#if RUKHANKA_DEBUG_INFO
|
||||
BurstAssert.IsTrue(false, $"Skinned mesh '{arc.smrInfoBlob.Value.skeletonName.ToFixedString()}' is not properly registered.");
|
||||
#else
|
||||
BurstAssert.IsTrue(false, $"Skinned mesh with hash '{arc.smrInfoBlob.Value.hash.Value}' is not properly registered. Enable 'RUKHANKA_DEBUG_INFO' to see the mesh name.");
|
||||
#endif
|
||||
return;
|
||||
}
|
||||
|
||||
// Mesh skinning data offsets
|
||||
var meshFrameData = new MeshFrameDeformationDescription();
|
||||
meshFrameData.baseOutVertexIndex = smrdd.deformedVertexIndex;
|
||||
meshFrameData.baseSkinMatrixIndex = smrdd.skinMatrixIndex;
|
||||
meshFrameData.baseBlendShapeWeightIndex = smrdd.blendShapeWeightIndex;
|
||||
meshFrameData.baseInputMeshVertexIndex = smd.baseVertex;
|
||||
meshFrameData.baseInputMeshBlendShapeIndex = smd.baseBlendShapeIndex;
|
||||
meshFrameData.meshVerticesCount = arc.smrInfoBlob.Value.meshVerticesCount;
|
||||
meshFrameData.meshBlendShapesCount = arc.smrInfoBlob.Value.meshBlendShapesCount;
|
||||
|
||||
var currentMeshFrameDeformationDataIndex = frameActiveDeformedMeshesCounter.Add(1);
|
||||
#if RUKHANKA_INPLACE_SKINNING
|
||||
// Yes, I am overwriting the value here. Frame active meshes counter need to be incremented in any case
|
||||
currentMeshFrameDeformationDataIndex = smrdd.deformedVertexIndex;
|
||||
#endif
|
||||
meshFrameDeformationData[currentMeshFrameDeformationDataIndex] = meshFrameData;
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------------------------------------------//
|
||||
|
||||
[BurstCompile]
|
||||
[WithAll(typeof(SkinnedMeshRendererComponent))]
|
||||
partial struct SetDeformedMeshIndicesJob: IJobEntity
|
||||
{
|
||||
[ReadOnly]
|
||||
public NativeParallelHashMap<Entity, SkinnedMeshRendererFrameDeformationData> entityToSMRFrameDataMap;
|
||||
[NativeDisableUnsafePtrRestriction]
|
||||
public UnsafeAtomicCounter32 frameDeformedVerticesCounter;
|
||||
|
||||
#if RUKHANKA_ENABLE_DEFORMATION_MOTION_VECTORS
|
||||
// Either 0 or 1
|
||||
public int currentFrameDeformedBufferIndex;
|
||||
#endif
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
unsafe void Execute(Entity e, ref DeformedMeshIndex dri)
|
||||
{
|
||||
#if RUKHANKA_ENABLE_DEFORMATION_MOTION_VECTORS
|
||||
dri.Value[2] = (uint)currentFrameDeformedBufferIndex;
|
||||
#endif
|
||||
|
||||
// Handle invisible mesh renderers by assigning theirs deformed mesh index to some value that can be handled in shaders:
|
||||
// * In case of in-place skinning I need to simply check for this index for some given predefined distinct value
|
||||
// * In case of preskinning path set deformed mesh index beyond valid data. Previously I have added some zeroes at the end
|
||||
// of skinned vertices data. Indexing it will return zero values for skinning mesh
|
||||
if (!entityToSMRFrameDataMap.TryGetValue(e, out var smrdd))
|
||||
{
|
||||
#if RUKHANKA_ENABLE_DEFORMATION_MOTION_VECTORS
|
||||
#if RUKHANKA_INPLACE_SKINNING
|
||||
dri.Value[currentFrameDeformedBufferIndex] = 0xffffffff;
|
||||
#else
|
||||
dri.Value[currentFrameDeformedBufferIndex] = (uint)*frameDeformedVerticesCounter.Counter;
|
||||
#endif
|
||||
#else
|
||||
#if RUKHANKA_INPLACE_SKINNING
|
||||
dri.Value = 0xffffffff;
|
||||
#else
|
||||
dri.Value = (uint)*frameDeformedVerticesCounter.Counter;
|
||||
#endif
|
||||
#endif
|
||||
return;
|
||||
}
|
||||
|
||||
#if RUKHANKA_ENABLE_DEFORMATION_MOTION_VECTORS
|
||||
dri.Value[currentFrameDeformedBufferIndex] = (uint)smrdd.deformedVertexIndex;
|
||||
#else
|
||||
dri.Value = (uint)smrdd.deformedVertexIndex;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------------------------------------------//
|
||||
|
||||
[BurstCompile]
|
||||
partial struct CopySkinMatricesToGPUJob: IJobEntity
|
||||
{
|
||||
[ReadOnly]
|
||||
public NativeParallelHashMap<Entity, SkinnedMeshRendererFrameDeformationData> entityToSMRFrameDataMap;
|
||||
[ReadOnly]
|
||||
public ComponentLookup<GPUAnimationEngineTag> gpuAnimationEngineTag;
|
||||
|
||||
[NativeDisableParallelForRestriction]
|
||||
public ThreadedSparseUploader mappedGPUSkinMatrixBuffer;
|
||||
|
||||
public bool isEditor;
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
unsafe void Execute(Entity e, SkinnedMeshRendererComponent arc, in DynamicBuffer<SkinMatrix> skinMatrices)
|
||||
{
|
||||
bool isGPUAnimator = !isEditor && arc.IsGPUAnimator(gpuAnimationEngineTag);
|
||||
if (isGPUAnimator || !entityToSMRFrameDataMap.TryGetValue(e, out var smrdd))
|
||||
return;
|
||||
|
||||
var srcPtr = skinMatrices.GetUnsafeReadOnlyPtr();
|
||||
var srcSize = skinMatrices.Length * UnsafeUtility.SizeOf<SkinMatrix>();
|
||||
var dstOffset = smrdd.skinMatrixIndex * UnsafeUtility.SizeOf<SkinMatrix>();
|
||||
mappedGPUSkinMatrixBuffer.AddUpload(srcPtr, srcSize, dstOffset);
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------------------------------------------//
|
||||
|
||||
[BurstCompile]
|
||||
partial struct CopyBlendShapeWeightToGPUJob: IJobEntity
|
||||
{
|
||||
[ReadOnly]
|
||||
public NativeParallelHashMap<Entity, SkinnedMeshRendererFrameDeformationData> entityToSMRFrameDataMap;
|
||||
|
||||
[NativeDisableParallelForRestriction]
|
||||
public NativeArray<float> mappedGPUBlendShapeWeightsBuffer;
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
unsafe void Execute(Entity e, in DynamicBuffer<BlendShapeWeight> blendShapeWeights)
|
||||
{
|
||||
if (!entityToSMRFrameDataMap.TryGetValue(e, out var smrdd))
|
||||
return;
|
||||
|
||||
var dstPtr = (float*)mappedGPUBlendShapeWeightsBuffer.GetUnsafePtr() + smrdd.blendShapeWeightIndex;
|
||||
UnsafeUtility.MemCpy(dstPtr, blendShapeWeights.GetUnsafeReadOnlyPtr(), UnsafeUtility.SizeOf<float>() * blendShapeWeights.Length);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+18
@@ -0,0 +1,18 @@
|
||||
fileFormatVersion: 2
|
||||
guid: a488787543b55e04ca6cbf69c833fc52
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
AssetOrigin:
|
||||
serializedVersion: 1
|
||||
productId: 298480
|
||||
packageName: Rukhanka Animation System 2
|
||||
packageVersion: 2.9.0
|
||||
assetPath: Packages/com.rukhanka.animation/Rukhanka.Runtime/Deformation/MeshDeformationSystem_Jobs.cs
|
||||
uploadId: 897522
|
||||
+38
@@ -0,0 +1,38 @@
|
||||
using UnityEngine;
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
namespace Rukhanka
|
||||
{
|
||||
public partial class MeshDeformationSystem
|
||||
{
|
||||
readonly int ShaderID_inputVertexSizeInBytes = Shader.PropertyToID("inputVertexSizeInBytes");
|
||||
readonly int ShaderID_outDataVertexOffset = Shader.PropertyToID("outDataVertexOffset");
|
||||
readonly int ShaderID_totalMeshVertices = Shader.PropertyToID("totalMeshVertices");
|
||||
readonly int ShaderID_meshVertexData = Shader.PropertyToID("meshVertexData");
|
||||
readonly int ShaderID_outInitialDeformedMeshData = Shader.PropertyToID("outInitialDeformedMeshData");
|
||||
readonly int ShaderID_meshBonesPerVertexData = Shader.PropertyToID("meshBonesPerVertexData");
|
||||
readonly int ShaderID_inputBonesWeightsDataOffset = Shader.PropertyToID("inputBonesWeightsDataOffset");
|
||||
readonly int ShaderID_outBonesWeightsDataOffset = Shader.PropertyToID("outBonesWeightsDataOffset");
|
||||
readonly int ShaderID_frameDeformedMeshes = Shader.PropertyToID("frameDeformedMeshes");
|
||||
readonly int ShaderID_outFramePerVertexWorkload = Shader.PropertyToID("outFramePerVertexWorkload");
|
||||
readonly int ShaderID_framePerVertexWorkload = Shader.PropertyToID("framePerVertexWorkload");
|
||||
readonly int ShaderID_inputMeshVertexData = Shader.PropertyToID("inputMeshVertexData");
|
||||
readonly int ShaderID_inputBoneInfluences = Shader.PropertyToID("inputBoneInfluences");
|
||||
readonly int ShaderID_inputBlendShapes = Shader.PropertyToID("inputBlendShapes");
|
||||
readonly int ShaderID_frameSkinMatrices = Shader.PropertyToID("frameSkinMatrices");
|
||||
readonly int ShaderID_frameBlendShapeWeights = Shader.PropertyToID("frameBlendShapeWeights");
|
||||
readonly int ShaderID_outDeformedVertices = Shader.PropertyToID("outDeformedVertices");
|
||||
readonly int ShaderID_totalDeformedMeshesCount = Shader.PropertyToID("totalDeformedMeshesCount");
|
||||
readonly int ShaderID_totalSkinnedVerticesCount = Shader.PropertyToID("totalSkinnedVerticesCount");
|
||||
readonly int ShaderID_voidMeshVertexCount = Shader.PropertyToID("voidMeshVertexCount");
|
||||
readonly int ShaderID_currentSkinnedVertexOffset = Shader.PropertyToID("currentSkinnedVertexOffset");
|
||||
readonly int ShaderID_DeformedMeshData = Shader.PropertyToID("_DeformedMeshData");
|
||||
readonly int ShaderID_PreviousFrameDeformedMeshData = Shader.PropertyToID("_PreviousFrameDeformedMeshData");
|
||||
readonly int ShaderID_meshBlendShapesBuffer = Shader.PropertyToID("meshBlendShapesBuffer");
|
||||
readonly int ShaderID_outInitialMeshBlendShapesData = Shader.PropertyToID("outInitialMeshBlendShapesData");
|
||||
readonly int ShaderID_inputBlendShapeVerticesCount = Shader.PropertyToID("inputBlendShapeVerticesCount");
|
||||
readonly int ShaderID_inputBlendShapeVertexOffset = Shader.PropertyToID("inputBlendShapeVertexOffset");
|
||||
readonly int ShaderID_outBlendShapeVertexOffset = Shader.PropertyToID("outBlendShapeVertexOffset");
|
||||
}
|
||||
}
|
||||
+18
@@ -0,0 +1,18 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 18b67e86e77ad8d43be1128243afd5ae
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
AssetOrigin:
|
||||
serializedVersion: 1
|
||||
productId: 298480
|
||||
packageName: Rukhanka Animation System 2
|
||||
packageVersion: 2.9.0
|
||||
assetPath: Packages/com.rukhanka.animation/Rukhanka.Runtime/Deformation/MeshDeformationSystem_ShaderVars.cs
|
||||
uploadId: 897522
|
||||
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 4e239222e57e79545b256b045a930c76
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
+90
@@ -0,0 +1,90 @@
|
||||
#pragma once
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#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/Deformation/Resources/DeformationCommon.hlsl"
|
||||
#ifdef RUKHANKA_INPLACE_SKINNING
|
||||
#include "Packages/com.rukhanka.animation/Rukhanka.Runtime/Deformation/Resources/Skinning.hlsl"
|
||||
#endif
|
||||
|
||||
#ifdef RUKHANKA_HALF_DEFORMED_DATA
|
||||
StructuredBuffer<PackedDeformedVertex> _DeformedMeshData;
|
||||
#else
|
||||
StructuredBuffer<DeformedVertex> _DeformedMeshData;
|
||||
#endif
|
||||
|
||||
#undef _DeformedMeshIndex
|
||||
#undef _DeformationParamsForMotionVectors
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
DeformedVertex GetDeformedVertexForMesh(uint vertexID, DeformedVertex originalVertex, uint vertexOffsetOrMeshIndex)
|
||||
{
|
||||
#ifndef RUKHANKA_INPLACE_SKINNING
|
||||
|
||||
uint vertexOffsetForMesh = vertexOffsetOrMeshIndex;
|
||||
#ifdef RUKHANKA_HALF_DEFORMED_DATA
|
||||
PackedDeformedVertex vertexData = _DeformedMeshData[vertexOffsetForMesh + vertexID];
|
||||
DeformedVertex rv = vertexData.Unpack();
|
||||
#else
|
||||
DeformedVertex rv = _DeformedMeshData[vertexOffsetForMesh + vertexID];
|
||||
#endif // RUKHANKA_HALF_DEFORMED_DATA
|
||||
|
||||
//-------- Inplace skinning code path -------------//
|
||||
#else
|
||||
|
||||
DeformedVertex rv = originalVertex;
|
||||
|
||||
uint meshIndex = vertexOffsetOrMeshIndex;
|
||||
if (meshIndex != 0xffffffff)
|
||||
{
|
||||
MeshFrameDeformationDescription mfd = frameDeformedMeshes[meshIndex];
|
||||
|
||||
uint absoluteInputMeshVertexIndex = vertexID + mfd.baseInputMeshVertexIndex;
|
||||
SourceSkinnedMeshVertex smv = SourceSkinnedMeshVertex::ReadFromRawBuffer(inputMeshVertexData, absoluteInputMeshVertexIndex);
|
||||
|
||||
rv = ApplyBlendShapes(rv, vertexID, mfd);
|
||||
rv = ApplySkinMatrices(rv, smv.boneWeightsOffset, smv.boneWeightsCount, mfd);
|
||||
}
|
||||
else
|
||||
{
|
||||
rv = (DeformedVertex)0;
|
||||
}
|
||||
|
||||
#endif
|
||||
return rv;
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void ComputeDeformedVertex_float(in uint vertexID, in float3 vertex, in float3 normal, in float3 tangent, out float3 deformedVertex, out float3 deformedNormal, out float3 deformedTangent)
|
||||
{
|
||||
deformedVertex = vertex;
|
||||
deformedNormal = normal;
|
||||
deformedTangent = tangent;
|
||||
|
||||
#ifdef DOTS_INSTANCING_ON
|
||||
|
||||
#ifdef RUKHANKA_ENABLE_DEFORMATION_MOTION_VECTORS
|
||||
const uint4 materialProperty = asuint(UNITY_ACCESS_DOTS_INSTANCED_PROP(float4, _DeformationParamsForMotionVectors));
|
||||
const uint currentFrameIndex = materialProperty[2];
|
||||
const uint index = materialProperty[currentFrameIndex];
|
||||
#else
|
||||
const uint index = asuint(UNITY_ACCESS_DOTS_INSTANCED_PROP(float, _DeformedMeshIndex));
|
||||
#endif // RUKHANKA_ENABLE_DEFORMATION_MOTION_VECTORS
|
||||
|
||||
DeformedVertex v;
|
||||
v.position = deformedVertex;
|
||||
v.normal = deformedNormal;
|
||||
v.tangent = deformedTangent;
|
||||
|
||||
v = GetDeformedVertexForMesh(vertexID, v, index);
|
||||
|
||||
deformedVertex = v.position;
|
||||
deformedNormal = v.normal;
|
||||
deformedTangent = v.tangent;
|
||||
|
||||
#endif // DOTS_INSTANCING_ON
|
||||
}
|
||||
+14
@@ -0,0 +1,14 @@
|
||||
fileFormatVersion: 2
|
||||
guid: a387024f61981304ca17ea1e3ffd997b
|
||||
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/Deformation/Resources/ComputeDeformedVertex.hlsl
|
||||
uploadId: 897522
|
||||
+52
@@ -0,0 +1,52 @@
|
||||
#ifndef COPY_INITIAL_MESH_BLEND_SHAPES_HLSL_
|
||||
#define COPY_INITIAL_MESH_BLEND_SHAPES_HLSL_
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
ByteAddressBuffer meshBlendShapesBuffer;
|
||||
RWByteAddressBuffer outInitialMeshBlendShapesData;
|
||||
|
||||
uint inputBlendShapeVerticesCount;
|
||||
uint inputBlendShapeVertexOffset;
|
||||
uint outBlendShapeVertexOffset;
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
InputBlendShapeVertex ReadBlendShapeVertexDelta(uint vertexID)
|
||||
{
|
||||
uint vertexByteOffset = vertexID * InputBlendShapeVertex::size;
|
||||
uint4 v0 = meshBlendShapesBuffer.Load4(vertexByteOffset + 0);
|
||||
uint4 v1 = meshBlendShapesBuffer.Load4(vertexByteOffset + 16);
|
||||
uint2 v2 = meshBlendShapesBuffer.Load2(vertexByteOffset + 32);
|
||||
|
||||
InputBlendShapeVertex rv;
|
||||
rv.meshVertexIndex = v0.x;
|
||||
rv.positionDelta = asfloat(v0.yzw);
|
||||
rv.normalDelta = asfloat(v1.xyz);
|
||||
rv.tangentDelta = asfloat(uint3(v1.w, v2.xy));
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
[numthreads(128, 1, 1)]
|
||||
void CopyInitialMeshBlendShapes(uint tid: SV_DispatchThreadID)
|
||||
{
|
||||
if (tid >= inputBlendShapeVerticesCount)
|
||||
return;
|
||||
|
||||
InputBlendShapeVertex v = ReadBlendShapeVertexDelta(tid + inputBlendShapeVertexOffset);
|
||||
|
||||
uint4 o0 = asuint(float4(v.positionDelta, v.normalDelta.x));
|
||||
uint4 o1 = asuint(float4(v.normalDelta.yz, v.tangentDelta.xy));
|
||||
uint o2 = asuint(v.tangentDelta.z);
|
||||
|
||||
uint outVertexOffset = v.meshVertexIndex + outBlendShapeVertexOffset;
|
||||
uint outVertexByteOffset = outVertexOffset * DeformedVertex::size;
|
||||
outInitialMeshBlendShapesData.Store4(outVertexByteOffset + 0, o0);
|
||||
outInitialMeshBlendShapesData.Store4(outVertexByteOffset + 16, o1);
|
||||
outInitialMeshBlendShapesData.Store(outVertexByteOffset + 32, o2);
|
||||
}
|
||||
|
||||
#endif // COPY_INITIAL_MESH_BLEND_SHAPES_HLSL_
|
||||
+14
@@ -0,0 +1,14 @@
|
||||
fileFormatVersion: 2
|
||||
guid: b3da0895509ba5a44b90be032bfb9819
|
||||
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/Deformation/Resources/CopyInitialMeshBlendShapes.hlsl
|
||||
uploadId: 897522
|
||||
+57
@@ -0,0 +1,57 @@
|
||||
#ifndef COPY_INITIAL_MESH_DATA_HLSL_
|
||||
#define COPY_INITIAL_MESH_DATA_HLSL_
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
ByteAddressBuffer meshVertexData;
|
||||
ByteAddressBuffer meshBonesPerVertexData;
|
||||
RWByteAddressBuffer outInitialDeformedMeshData;
|
||||
|
||||
int inputVertexSizeInBytes;
|
||||
int outDataVertexOffset;
|
||||
uint totalMeshVertices;
|
||||
int outBonesWeightsDataOffset;
|
||||
int inputBonesWeightsDataOffset;
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
SourceSkinnedMeshVertex ReadSourceVertex(int vertexIndex)
|
||||
{
|
||||
int vertexByteOffset = vertexIndex * inputVertexSizeInBytes;
|
||||
SourceSkinnedMeshVertex rv = (SourceSkinnedMeshVertex)0;
|
||||
#ifndef RUKHANKA_INPLACE_SKINNING
|
||||
CHECK_RAW_BUFFER_OUT_OF_BOUNDS(RUKHANKADEBUGMARKERS_DEFORMATION_COPY_MESH_DATA, vertexByteOffset, 40, meshVertexData);
|
||||
|
||||
float4 v0 = asfloat(meshVertexData.Load4(vertexByteOffset + 0));
|
||||
float4 v1 = asfloat(meshVertexData.Load4(vertexByteOffset + 16));
|
||||
float1 v2 = asfloat(meshVertexData.Load(vertexByteOffset + 32));
|
||||
rv.position = v0.xyz;
|
||||
rv.normal = float3(v0.w, v1.xy);
|
||||
rv.tangent = float3(v1.zw, v2.x);
|
||||
#endif
|
||||
|
||||
int baseBoneWeightIndex = inputBonesWeightsDataOffset + vertexIndex;
|
||||
|
||||
CHECK_RAW_BUFFER_OUT_OF_BOUNDS(RUKHANKADEBUGMARKERS_DEFORMATION_COPY_MESH_DATA, baseBoneWeightIndex * 4, 4, meshBonesPerVertexData);
|
||||
uint boneWeightsOffsetAndCountPacked = meshBonesPerVertexData.Load(baseBoneWeightIndex * 4);
|
||||
rv.boneWeightsOffset = SourceSkinnedMeshVertex::GetBoneWeightsOffsetFromPackedUINT(boneWeightsOffsetAndCountPacked) + outBonesWeightsDataOffset;
|
||||
rv.boneWeightsCount = SourceSkinnedMeshVertex::GetBoneWeightsCountFromPackedUINT(boneWeightsOffsetAndCountPacked);
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
[numthreads(128, 1, 1)]
|
||||
void CopyInitialMeshData(uint tid: SV_DispatchThreadID)
|
||||
{
|
||||
if (tid >= totalMeshVertices)
|
||||
return;
|
||||
|
||||
SourceSkinnedMeshVertex v = ReadSourceVertex(tid);
|
||||
|
||||
int outVertexOffset = tid + outDataVertexOffset;
|
||||
v.WriteIntoRawBuffer(outInitialDeformedMeshData, outVertexOffset);
|
||||
}
|
||||
|
||||
#endif // COPY_INITIAL_MESH_DATA_HLSL_
|
||||
+14
@@ -0,0 +1,14 @@
|
||||
fileFormatVersion: 2
|
||||
guid: e286f97e31bb11943af1a6b97b753b28
|
||||
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/Deformation/Resources/CopyInitialMeshData.hlsl
|
||||
uploadId: 897522
|
||||
+26
@@ -0,0 +1,26 @@
|
||||
#ifndef CREATE_PER_VERTEX_DEFORMATION_WORKLOAD_HLSL_
|
||||
#define CREATE_PER_VERTEX_DEFORMATION_WORKLOAD_HLSL_
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
RWByteAddressBuffer outFramePerVertexWorkload;
|
||||
uint totalDeformedMeshesCount;
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
[numthreads(128, 1, 1)]
|
||||
void CreatePerVertexDeformationWorkload(uint tid: SV_DispatchThreadID)
|
||||
{
|
||||
if (tid >= totalDeformedMeshesCount)
|
||||
return;
|
||||
|
||||
MeshFrameDeformationDescription md = frameDeformedMeshes[tid];
|
||||
|
||||
for (int i = 0; i < md.meshVerticesCount; ++i)
|
||||
{
|
||||
int outVertexIndex = i + md.baseOutVertexIndex;
|
||||
outFramePerVertexWorkload.Store(outVertexIndex * 4, tid);
|
||||
}
|
||||
}
|
||||
|
||||
#endif // CREATE_PER_VERTEX_DEFORMATION_WORKLOAD_HLSL_
|
||||
+14
@@ -0,0 +1,14 @@
|
||||
fileFormatVersion: 2
|
||||
guid: fd557c506788751409cfce5117c0adbc
|
||||
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/Deformation/Resources/CreatePerVertexDeformationWorkload.hlsl
|
||||
uploadId: 897522
|
||||
+205
@@ -0,0 +1,205 @@
|
||||
#ifndef DEFORMATION_COMMON_HLSL_
|
||||
#define DEFORMATION_COMMON_HLSL_
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
struct SourceSkinnedMeshVertex
|
||||
{
|
||||
#ifndef RUKHANKA_INPLACE_SKINNING
|
||||
float3 position;
|
||||
float3 normal;
|
||||
float3 tangent;
|
||||
static const int size = 40;
|
||||
#else
|
||||
static const int size = 4;
|
||||
#endif
|
||||
uint boneWeightsOffset;
|
||||
uint boneWeightsCount;
|
||||
|
||||
static uint GetBoneWeightsOffsetFromPackedUINT(uint boneWeightsOffsetAndCount)
|
||||
{
|
||||
return boneWeightsOffsetAndCount >> 8;
|
||||
}
|
||||
|
||||
static uint GetBoneWeightsCountFromPackedUINT(uint boneWeightsOffsetAndCount)
|
||||
{
|
||||
return boneWeightsOffsetAndCount & 0xff;
|
||||
}
|
||||
|
||||
static uint PackBoneOffsetAndCount(uint count, uint offset)
|
||||
{
|
||||
return count | (offset << 8);
|
||||
}
|
||||
|
||||
void WriteIntoRawBuffer(RWByteAddressBuffer outBuffer, uint index)
|
||||
{
|
||||
uint boneWeightsOffsetAndCount = PackBoneOffsetAndCount(boneWeightsCount, boneWeightsOffset);
|
||||
|
||||
uint byteOffset = index * size;
|
||||
CHECK_RAW_BUFFER_OUT_OF_BOUNDS(RUKHANKADEBUGMARKERS_DEFORMATION_SKINNED_MESH_VERTEX_WRITE, byteOffset, size, outBuffer);
|
||||
#ifndef RUKHANKA_INPLACE_SKINNING
|
||||
uint4 u0 = asuint(float4(position, normal.x));
|
||||
uint4 u1 = asuint(float4(normal.yz, tangent.xy));
|
||||
uint2 u2 = uint2(asuint(tangent.z), boneWeightsOffsetAndCount);
|
||||
outBuffer.Store4(byteOffset + 0, u0);
|
||||
outBuffer.Store4(byteOffset + 16, u1);
|
||||
outBuffer.Store2(byteOffset + 32, u2);
|
||||
#else
|
||||
outBuffer.Store(byteOffset + 0, boneWeightsOffsetAndCount);
|
||||
#endif
|
||||
}
|
||||
|
||||
static SourceSkinnedMeshVertex ReadFromRawBuffer(ByteAddressBuffer inBuffer, uint index)
|
||||
{
|
||||
SourceSkinnedMeshVertex rv;
|
||||
|
||||
uint byteOffset = index * size;
|
||||
CHECK_RAW_BUFFER_OUT_OF_BOUNDS(RUKHANKADEBUGMARKERS_DEFORMATION_SKINNED_MESH_VERTEX_READ, byteOffset, size, inBuffer);
|
||||
#ifndef RUKHANKA_INPLACE_SKINNING
|
||||
uint4 u0 = inBuffer.Load4(byteOffset + 0);
|
||||
uint4 u1 = inBuffer.Load4(byteOffset + 16);
|
||||
uint2 u2 = inBuffer.Load2(byteOffset + 32);
|
||||
|
||||
rv.position = asfloat(u0.xyz);
|
||||
rv.normal = asfloat(uint3(u0.w, u1.xy));
|
||||
rv.tangent = asfloat(uint3(u1.zw, u2.x));
|
||||
uint boneWeightsOffsetAndCount = u2.y;
|
||||
#else
|
||||
uint boneWeightsOffsetAndCount = inBuffer.Load(byteOffset + 0);
|
||||
#endif
|
||||
|
||||
rv.boneWeightsOffset = GetBoneWeightsOffsetFromPackedUINT(boneWeightsOffsetAndCount);
|
||||
rv.boneWeightsCount = GetBoneWeightsCountFromPackedUINT(boneWeightsOffsetAndCount);
|
||||
|
||||
return rv;
|
||||
}
|
||||
};
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
struct DeformedVertex
|
||||
{
|
||||
float3 position;
|
||||
float3 normal;
|
||||
float3 tangent;
|
||||
|
||||
static const int size = 3 * 3 * 4;
|
||||
|
||||
static DeformedVertex ReadFromRawBuffer(ByteAddressBuffer inBuffer, uint index)
|
||||
{
|
||||
uint byteOffset = index * size;
|
||||
uint4 v0 = inBuffer.Load4(byteOffset + 0);
|
||||
uint4 v1 = inBuffer.Load4(byteOffset + 16);
|
||||
uint v2 = inBuffer.Load(byteOffset + 32);
|
||||
CHECK_RAW_BUFFER_OUT_OF_BOUNDS(RUKHANKADEBUGMARKERS_DEFORMATION_DEFORMED_VERTEX_READ, byteOffset, size * 4, inBuffer);
|
||||
|
||||
DeformedVertex rv;
|
||||
rv.position = asfloat(v0.xyz);
|
||||
rv.normal = asfloat(uint3(v0.w, v1.xy));
|
||||
rv.tangent = asfloat(uint3(v1.zw, v2.x));
|
||||
return rv;
|
||||
}
|
||||
|
||||
void Scale(float v)
|
||||
{
|
||||
position *= v;
|
||||
normal *= v;
|
||||
tangent *= v;
|
||||
}
|
||||
};
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
struct PackedDeformedVertex
|
||||
{
|
||||
uint4 pack0;
|
||||
uint pack1;
|
||||
|
||||
DeformedVertex Unpack()
|
||||
{
|
||||
DeformedVertex rv;
|
||||
|
||||
rv.position.x = f16tof32(pack0.x >> 16);
|
||||
rv.position.y = f16tof32(pack0.x);
|
||||
rv.position.z = f16tof32(pack0.y >> 16);
|
||||
|
||||
rv.normal.x = f16tof32(pack0.y);
|
||||
rv.normal.y = f16tof32(pack0.z >> 16);
|
||||
rv.normal.z = f16tof32(pack0.z);
|
||||
|
||||
rv.tangent.x = f16tof32(pack0.w >> 16);
|
||||
rv.tangent.y = f16tof32(pack0.w);
|
||||
rv.tangent.z = f16tof32(pack1 >> 16);
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
static PackedDeformedVertex Pack(DeformedVertex v)
|
||||
{
|
||||
PackedDeformedVertex rv;
|
||||
|
||||
uint3 p = f32tof16(v.position);
|
||||
uint3 n = f32tof16(v.normal);
|
||||
uint3 t = f32tof16(v.tangent);
|
||||
|
||||
rv.pack0.x = p.x << 16 | p.y;
|
||||
rv.pack0.y = p.z << 16 | n.x;
|
||||
rv.pack0.z = n.y << 16 | n.z;
|
||||
rv.pack0.w = t.x << 16 | t.y;
|
||||
rv.pack1 = t.z << 16;
|
||||
|
||||
return rv;
|
||||
}
|
||||
};
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
struct BoneInfluence
|
||||
{
|
||||
float weight;
|
||||
int boneIndex;
|
||||
|
||||
static BoneInfluence ReadFromRawBuffer(ByteAddressBuffer inBuffer, uint index)
|
||||
{
|
||||
uint byteOffset = index * 8;
|
||||
uint2 u0 = inBuffer.Load2(byteOffset + 0);
|
||||
CHECK_RAW_BUFFER_OUT_OF_BOUNDS(RUKHANKADEBUGMARKERS_DEFORMATION_BONE_INFLUENCE_READ, byteOffset, 8, inBuffer);
|
||||
|
||||
BoneInfluence rv;
|
||||
rv.weight = asfloat(u0.x);
|
||||
rv.boneIndex = u0.y;
|
||||
return rv;
|
||||
}
|
||||
};
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
struct MeshFrameDeformationDescription
|
||||
{
|
||||
int baseSkinMatrixIndex;
|
||||
int baseBlendShapeWeightIndex;
|
||||
int baseOutVertexIndex;
|
||||
int baseInputMeshVertexIndex;
|
||||
int baseInputMeshBlendShapeIndex;
|
||||
int meshVerticesCount;
|
||||
int meshBlendShapesCount;
|
||||
};
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
struct InputBlendShapeVertex
|
||||
{
|
||||
uint meshVertexIndex;
|
||||
float3 positionDelta;
|
||||
float3 normalDelta;
|
||||
float3 tangentDelta;
|
||||
|
||||
static const int size = (1 + 3 * 3) * 4;
|
||||
};
|
||||
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
StructuredBuffer<MeshFrameDeformationDescription> frameDeformedMeshes;
|
||||
|
||||
#endif // DEFORMATION_COMMON_HLSL_
|
||||
+14
@@ -0,0 +1,14 @@
|
||||
fileFormatVersion: 2
|
||||
guid: f4b5c1545ea2e514fb6d61c2b2215f6b
|
||||
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/Deformation/Resources/DeformationCommon.hlsl
|
||||
uploadId: 897522
|
||||
+17
@@ -0,0 +1,17 @@
|
||||
#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/Deformation/Resources/DeformationCommon.hlsl"
|
||||
#include "Packages/com.rukhanka.animation/Rukhanka.Runtime/Deformation/Resources/CopyInitialMeshData.hlsl"
|
||||
#include "Packages/com.rukhanka.animation/Rukhanka.Runtime/Deformation/Resources/CopyInitialMeshBlendShapes.hlsl"
|
||||
#include "Packages/com.rukhanka.animation/Rukhanka.Runtime/Deformation/Resources/CreatePerVertexDeformationWorkload.hlsl"
|
||||
#include "Packages/com.rukhanka.animation/Rukhanka.Runtime/Deformation/Resources/Skinning.hlsl"
|
||||
|
||||
//#pragma enable_d3d11_debug_symbols
|
||||
//#pragma use_dxc
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#pragma kernel CopyInitialMeshData
|
||||
#pragma kernel CopyInitialMeshBlendShapes
|
||||
#pragma kernel CreatePerVertexDeformationWorkload
|
||||
#pragma kernel Skinning
|
||||
+14
@@ -0,0 +1,14 @@
|
||||
fileFormatVersion: 2
|
||||
guid: c82cd9a4a3fa4854a9b4dd3290fd978f
|
||||
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/Deformation/Resources/RukhankaMeshDeformation.compute
|
||||
uploadId: 897522
|
||||
@@ -0,0 +1,178 @@
|
||||
#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_
|
||||
+14
@@ -0,0 +1,14 @@
|
||||
fileFormatVersion: 2
|
||||
guid: c99bf944d5948e649b631c5ae38ac8a2
|
||||
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/Deformation/Resources/Skinning.hlsl
|
||||
uploadId: 897522
|
||||
+162
@@ -0,0 +1,162 @@
|
||||
using Unity.Burst;
|
||||
using Unity.Collections.LowLevel.Unsafe;
|
||||
using Unity.Entities;
|
||||
using Unity.Jobs;
|
||||
using Unity.Rendering;
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
namespace Rukhanka
|
||||
{
|
||||
|
||||
[WorldSystemFilter(WorldSystemFilterFlags.Default | WorldSystemFilterFlags.Editor)]
|
||||
[UpdateInGroup(typeof(RukhankaDeformationSystemGroup))]
|
||||
[CreateAfter(typeof(RegisterMaterialsAndMeshesSystem))]
|
||||
public partial struct SkinnedMeshPreparationSystem: ISystem
|
||||
{
|
||||
SharedComponentTypeHandle<RenderMeshArray> renderMeshArrayTypeHandle;
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
public void OnCreate(ref SystemState ss)
|
||||
{
|
||||
#if !HYBRID_RENDERER_DISABLED
|
||||
if (!EntitiesGraphicsUtils.IsEntitiesGraphicsSupportedOnSystem())
|
||||
#endif
|
||||
{
|
||||
ss.Enabled = false;
|
||||
return;
|
||||
}
|
||||
|
||||
var deformationRuntimeData = DeformationRuntimeData.Construct(ref ss);
|
||||
ss.EntityManager.CreateSingleton(deformationRuntimeData, "Rukhanka Deformation Runtime Data");
|
||||
|
||||
renderMeshArrayTypeHandle = ss.GetSharedComponentTypeHandle<RenderMeshArray>();
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
public void OnDestroy(ref SystemState ss)
|
||||
{
|
||||
if (SystemAPI.TryGetSingletonRW<DeformationRuntimeData>(out var deformationRuntimeData))
|
||||
deformationRuntimeData.ValueRW.Dispose();
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
[BurstCompile]
|
||||
public void OnUpdate(ref SystemState ss)
|
||||
{
|
||||
renderMeshArrayTypeHandle.Update(ref ss);
|
||||
ref var deformationRuntimeData = ref SystemAPI.GetSingletonRW<DeformationRuntimeData>().ValueRW;
|
||||
|
||||
// Reset data used in current frame
|
||||
var resetFrameDataJH = ResetNewFrameData(ref ss, ref deformationRuntimeData, ss.Dependency);
|
||||
|
||||
// Gather meshes that new in this frame and absent in previous frames
|
||||
var getNewSkinnedMeshesJH = GatherNewMeshes(ref ss, ref deformationRuntimeData, resetFrameDataJH);
|
||||
|
||||
// Register new meshes in internal skinned mesh database
|
||||
var registerNewSkinnedMeshesJH = RegisterNewMeshes(ref ss, ref deformationRuntimeData, getNewSkinnedMeshesJH);
|
||||
|
||||
// Compute all frame deformed meshes skin matrices offsets in global GPU buffer
|
||||
var computeFrameSkinMatrixDataJH = ComputeFrameSkinnedMeshData(ref ss, ref deformationRuntimeData, resetFrameDataJH);
|
||||
|
||||
var combinedJobHandle = JobHandle.CombineDependencies(computeFrameSkinMatrixDataJH, registerNewSkinnedMeshesJH);
|
||||
ss.Dependency = combinedJobHandle;
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
unsafe JobHandle ResetNewFrameData(ref SystemState ss, ref DeformationRuntimeData drd, JobHandle dependsOn)
|
||||
{
|
||||
var frameSkinnedMeshesQuery = SystemAPI.QueryBuilder()
|
||||
.WithAny<Rukhanka.SkinMatrix, Rukhanka.BlendShapeWeight>()
|
||||
.Build();
|
||||
|
||||
var resetFrameDataJob = new ResetFrameDataJob()
|
||||
{
|
||||
frameSkinnedMeshesCount = frameSkinnedMeshesQuery.CalculateEntityCount(),
|
||||
frameSkinMatrixCounter = new UnsafeAtomicCounter32(UnsafeUtility.AddressOf(ref drd.frameSkinMatrixCount)),
|
||||
frameBlendShapeWeightCounter = new UnsafeAtomicCounter32(UnsafeUtility.AddressOf(ref drd.frameBlendShapeWeightsCount)),
|
||||
newSkinnedMeshesToRegister = drd.newSkinnedMeshesToRegister,
|
||||
entityToSMRFrameDataMap = drd.entityToSMRFrameDataMap,
|
||||
frameDeformedVertexCount = new UnsafeAtomicCounter32(UnsafeUtility.AddressOf(ref drd.frameDeformedVerticesCount)),
|
||||
};
|
||||
|
||||
var resetFrameDataJH = resetFrameDataJob.Schedule(dependsOn);
|
||||
return resetFrameDataJH;
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
JobHandle GatherNewMeshes(ref SystemState ss, ref DeformationRuntimeData drd, JobHandle dependsOn)
|
||||
{
|
||||
var deformedSubMeshQuery = SystemAPI.QueryBuilder()
|
||||
.WithAll<MaterialMeshInfo, DeformedMeshIndex, SkinnedMeshRendererComponent>()
|
||||
.Build();
|
||||
|
||||
var getNewSkinnedMeshesJob = new GetFrameNewSkinnedMeshesJob()
|
||||
{
|
||||
existingSkinnedMeshes = drd.registeredSkinnedMeshesMap,
|
||||
newSkinnedMeshes = drd.newSkinnedMeshesToRegister.AsParallelWriter(),
|
||||
renderMeshArrays = drd.renderMeshArrays,
|
||||
materialMeshInfoTypeHandle = SystemAPI.GetComponentTypeHandle<MaterialMeshInfo>(true),
|
||||
renderMeshArrayTypeHandle = renderMeshArrayTypeHandle,
|
||||
animatedSkinnedMeshTypeHandle = SystemAPI.GetComponentTypeHandle<SkinnedMeshRendererComponent>(true),
|
||||
};
|
||||
|
||||
var getNewSkinnedMeshesJH = getNewSkinnedMeshesJob.ScheduleParallel(deformedSubMeshQuery, dependsOn);
|
||||
return getNewSkinnedMeshesJH;
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
unsafe JobHandle RegisterNewMeshes(ref SystemState ss, ref DeformationRuntimeData drd, JobHandle dependsOn)
|
||||
{
|
||||
var registerNewSkinnedMeshesJob = new RegisterNewSkinnedMeshesJob()
|
||||
{
|
||||
existingSkinnedMeshes = drd.registeredSkinnedMeshesMap,
|
||||
newSkinnedMeshes = drd.newSkinnedMeshesToRegister,
|
||||
totalSkinnedVerticesCount = new UnsafeAtomicCounter32(UnsafeUtility.AddressOf(ref drd.totalSkinnedVerticesCount)),
|
||||
totalBoneWeightsCount = new UnsafeAtomicCounter32(UnsafeUtility.AddressOf(ref drd.totalBoneWeightsCount)),
|
||||
totalBlendShapeVerticesCount = new UnsafeAtomicCounter32(UnsafeUtility.AddressOf(ref drd.totalBlendShapeVerticesCount)),
|
||||
maximumVerticesAcrossAllRegisteredMeshes = new UnsafeAtomicCounter32(UnsafeUtility.AddressOf(ref drd.maximumVerticesAcrossAllRegisteredMeshes)),
|
||||
maximumSkinMatrixCountAcrossAllRegisteredMeshes = new UnsafeAtomicCounter32(UnsafeUtility.AddressOf(ref drd.maximumSkinMatrixCountAcrossAllRegisteredMeshes)),
|
||||
};
|
||||
|
||||
var registerNewSkinnedMeshesJH = registerNewSkinnedMeshesJob.Schedule(dependsOn);
|
||||
return registerNewSkinnedMeshesJH;
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
unsafe JobHandle ComputeFrameSkinnedMeshData(ref SystemState ss, ref DeformationRuntimeData drd, JobHandle dependsOn)
|
||||
{
|
||||
// If culling context is present then skin only meshes in visible LOD level
|
||||
SystemAPI.TryGetSingleton<AnimationCullingContext>(out var animationCullingContext);
|
||||
|
||||
var computeFrameSkinnedMeshesJob = new ComputeFrameSkinnedMeshesJob()
|
||||
{
|
||||
skinMatrixOffsetCounter = new UnsafeAtomicCounter32(UnsafeUtility.AddressOf(ref drd.frameSkinMatrixCount)),
|
||||
blendShapeWeightOffsetCounter = new UnsafeAtomicCounter32(UnsafeUtility.AddressOf(ref drd.frameBlendShapeWeightsCount)),
|
||||
frameDeformedVerticesCounter = new UnsafeAtomicCounter32(UnsafeUtility.AddressOf(ref drd.frameDeformedVerticesCount)),
|
||||
cullAnimationsTagLookup = SystemAPI.GetComponentLookup<CullAnimationsTag>(true),
|
||||
entityToSMRFrameData = drd.entityToSMRFrameDataMap.AsParallelWriter(),
|
||||
skinMatrixBufferLookup = SystemAPI.GetBufferLookup<Rukhanka.SkinMatrix>(true),
|
||||
blendShapeWeightBufferLookup = SystemAPI.GetBufferLookup<Rukhanka.BlendShapeWeight>(true),
|
||||
lodRangeLookup = SystemAPI.GetComponentLookup<LODRange>(true),
|
||||
lodWorldRefPointLookup = SystemAPI.GetComponentLookup<LODWorldReferencePoint>(true),
|
||||
lodAffectors = animationCullingContext.lodAffectors,
|
||||
|
||||
// Disable culling in editor world
|
||||
#if UNITY_EDITOR
|
||||
isEditorWorld = ss.WorldUnmanaged.Flags == WorldFlags.Editor
|
||||
#endif
|
||||
};
|
||||
dependsOn = computeFrameSkinnedMeshesJob.ScheduleParallel(dependsOn);
|
||||
|
||||
return dependsOn;
|
||||
}
|
||||
}
|
||||
}
|
||||
+18
@@ -0,0 +1,18 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 719f458d822bef44b8c2e55cd4c6b01e
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
AssetOrigin:
|
||||
serializedVersion: 1
|
||||
productId: 298480
|
||||
packageName: Rukhanka Animation System 2
|
||||
packageVersion: 2.9.0
|
||||
assetPath: Packages/com.rukhanka.animation/Rukhanka.Runtime/Deformation/SkinnedMeshPreparationSystem.cs
|
||||
uploadId: 897522
|
||||
+259
@@ -0,0 +1,259 @@
|
||||
using System;
|
||||
using Unity.Burst;
|
||||
using Unity.Burst.Intrinsics;
|
||||
using Unity.Collections;
|
||||
using Unity.Collections.LowLevel.Unsafe;
|
||||
using Unity.Entities;
|
||||
using Unity.Jobs;
|
||||
using Unity.Mathematics;
|
||||
using Unity.Rendering;
|
||||
using UnityEngine;
|
||||
using UnityEngine.Rendering;
|
||||
using Hash128 = Unity.Entities.Hash128;
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
namespace Rukhanka
|
||||
{
|
||||
public partial struct SkinnedMeshPreparationSystem
|
||||
{
|
||||
|
||||
//-----------------------------------------------------------------------------------------------------------------//
|
||||
|
||||
[BurstCompile]
|
||||
struct GetFrameNewSkinnedMeshesJob: IJobChunk
|
||||
{
|
||||
[ReadOnly]
|
||||
public NativeParallelHashMap<int, BRGRenderMeshArray> renderMeshArrays;
|
||||
[ReadOnly]
|
||||
public SharedComponentTypeHandle<RenderMeshArray> renderMeshArrayTypeHandle;
|
||||
[ReadOnly]
|
||||
public ComponentTypeHandle<MaterialMeshInfo> materialMeshInfoTypeHandle;
|
||||
[ReadOnly]
|
||||
public ComponentTypeHandle<SkinnedMeshRendererComponent> animatedSkinnedMeshTypeHandle;
|
||||
|
||||
[ReadOnly]
|
||||
public NativeParallelHashMap<Hash128, SkinnedMeshDescription> existingSkinnedMeshes;
|
||||
public NativeParallelHashMap<BatchMeshID, BlobAssetReference<SkinnedMeshInfoBlob>>.ParallelWriter newSkinnedMeshes;
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
public void Execute(in ArchetypeChunk chunk, int unfilteredChunkIndex, bool useEnabledMask, in v128 chunkEnabledMask)
|
||||
{
|
||||
if (!renderMeshArrays.IsCreated)
|
||||
return;
|
||||
|
||||
int renderMeshArrayIndex = chunk.GetSharedComponentIndex(renderMeshArrayTypeHandle);
|
||||
BRGRenderMeshArray chunkRenderMeshArray = default;
|
||||
if (renderMeshArrayIndex >= 0)
|
||||
renderMeshArrays.TryGetValue(renderMeshArrayIndex, out chunkRenderMeshArray);
|
||||
|
||||
var materialMeshInfos = chunk.GetNativeArray(ref materialMeshInfoTypeHandle);
|
||||
var animatedSkinnedMeshInfos = chunk.GetNativeArray(ref animatedSkinnedMeshTypeHandle);
|
||||
|
||||
var cee = new ChunkEntityEnumerator(useEnabledMask, chunkEnabledMask, chunk.Count);
|
||||
while (cee.NextEntityIndex(out var i))
|
||||
{
|
||||
var mmi = materialMeshInfos[i];
|
||||
var asm = animatedSkinnedMeshInfos[i];
|
||||
var meshID = chunkRenderMeshArray.GetMeshID(mmi);
|
||||
|
||||
if (!existingSkinnedMeshes.ContainsKey(asm.smrInfoBlob.Value.hash))
|
||||
{
|
||||
newSkinnedMeshes.TryAdd(meshID, asm.smrInfoBlob);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------------------------------------------//
|
||||
|
||||
[BurstCompile]
|
||||
struct RegisterNewSkinnedMeshesJob: IJob
|
||||
{
|
||||
public NativeParallelHashMap<BatchMeshID, BlobAssetReference<SkinnedMeshInfoBlob>> newSkinnedMeshes;
|
||||
public NativeParallelHashMap<Hash128, SkinnedMeshDescription> existingSkinnedMeshes;
|
||||
[NativeDisableUnsafePtrRestriction]
|
||||
public UnsafeAtomicCounter32 totalSkinnedVerticesCount;
|
||||
[NativeDisableUnsafePtrRestriction]
|
||||
public UnsafeAtomicCounter32 totalBoneWeightsCount;
|
||||
[NativeDisableUnsafePtrRestriction]
|
||||
public UnsafeAtomicCounter32 totalBlendShapeVerticesCount;
|
||||
[NativeDisableUnsafePtrRestriction]
|
||||
public UnsafeAtomicCounter32 maximumVerticesAcrossAllRegisteredMeshes;
|
||||
[NativeDisableUnsafePtrRestriction]
|
||||
public UnsafeAtomicCounter32 maximumSkinMatrixCountAcrossAllRegisteredMeshes;
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
public unsafe void Execute()
|
||||
{
|
||||
var baseVertex = *totalSkinnedVerticesCount.Counter;
|
||||
var baseBoneWeightIndex = *totalBoneWeightsCount.Counter;
|
||||
var baseBlendShapeIndex = *totalBlendShapeVerticesCount.Counter;
|
||||
foreach (var sm in newSkinnedMeshes)
|
||||
{
|
||||
var smd = new SkinnedMeshDescription();
|
||||
ref var skinnedMeshBlob = ref sm.Value.Value;
|
||||
|
||||
var numMeshVertices = skinnedMeshBlob.meshVerticesCount;
|
||||
smd.baseVertex = baseVertex;
|
||||
baseVertex += numMeshVertices;
|
||||
smd.vertexCount = numMeshVertices;
|
||||
|
||||
var numBoneWeightIndicesCount = skinnedMeshBlob.meshBoneWeightsCount;
|
||||
smd.baseBoneWeightIndex = baseBoneWeightIndex;
|
||||
baseBoneWeightIndex += numBoneWeightIndicesCount;
|
||||
|
||||
var blendShapesDataSize = skinnedMeshBlob.meshBlendShapesCount * numMeshVertices;
|
||||
smd.baseBlendShapeIndex = baseBlendShapeIndex;
|
||||
baseBlendShapeIndex += blendShapesDataSize;
|
||||
|
||||
maximumVerticesAcrossAllRegisteredMeshes.Reset(math.max(skinnedMeshBlob.boneWeightsIndices.Length, *maximumVerticesAcrossAllRegisteredMeshes.Counter));
|
||||
maximumSkinMatrixCountAcrossAllRegisteredMeshes.Reset(math.max(skinnedMeshBlob.bones.Length, *maximumSkinMatrixCountAcrossAllRegisteredMeshes.Counter));
|
||||
|
||||
existingSkinnedMeshes.Add(skinnedMeshBlob.hash, smd);
|
||||
}
|
||||
totalSkinnedVerticesCount.Reset(baseVertex);
|
||||
totalBoneWeightsCount.Reset(baseBoneWeightIndex);
|
||||
totalBlendShapeVerticesCount.Reset(baseBlendShapeIndex);
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------------------------------------------//
|
||||
|
||||
[BurstCompile]
|
||||
struct ResetFrameDataJob: IJob
|
||||
{
|
||||
public NativeParallelHashMap<BatchMeshID, BlobAssetReference<SkinnedMeshInfoBlob>> newSkinnedMeshesToRegister;
|
||||
public NativeParallelHashMap<Entity, SkinnedMeshRendererFrameDeformationData> entityToSMRFrameDataMap;
|
||||
[NativeDisableUnsafePtrRestriction]
|
||||
public UnsafeAtomicCounter32 frameSkinMatrixCounter;
|
||||
[NativeDisableUnsafePtrRestriction]
|
||||
public UnsafeAtomicCounter32 frameBlendShapeWeightCounter;
|
||||
[NativeDisableUnsafePtrRestriction]
|
||||
public UnsafeAtomicCounter32 frameDeformedVertexCount;
|
||||
public int frameSkinnedMeshesCount;
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
public void Execute()
|
||||
{
|
||||
newSkinnedMeshesToRegister.Clear();
|
||||
entityToSMRFrameDataMap.Clear();
|
||||
entityToSMRFrameDataMap.Capacity = math.max(frameSkinnedMeshesCount, entityToSMRFrameDataMap.Capacity);
|
||||
frameSkinMatrixCounter.Reset(0);
|
||||
frameBlendShapeWeightCounter.Reset(0);
|
||||
|
||||
#if RUKHANKA_INPLACE_SKINNING
|
||||
// In case of in-place skinning frameDeformedVertexCount indexes meshes and not vertices, so reset it to zero here
|
||||
var deformedVertexCountResetValue = 0;
|
||||
#else
|
||||
// Zero index is considered 'uninitialized' in 'ApplyPreviousFrameDeformedVertexPosition' function in deformed shader code
|
||||
// Default value starts from one
|
||||
var deformedVertexCountResetValue = 1;
|
||||
#endif
|
||||
frameDeformedVertexCount.Reset(deformedVertexCountResetValue);
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------------------------------------------//
|
||||
|
||||
[BurstCompile]
|
||||
partial struct ComputeFrameSkinnedMeshesJob: IJobEntity
|
||||
{
|
||||
[NativeDisableUnsafePtrRestriction]
|
||||
public UnsafeAtomicCounter32 skinMatrixOffsetCounter;
|
||||
[NativeDisableUnsafePtrRestriction]
|
||||
public UnsafeAtomicCounter32 blendShapeWeightOffsetCounter;
|
||||
[NativeDisableUnsafePtrRestriction]
|
||||
public UnsafeAtomicCounter32 frameDeformedVerticesCounter;
|
||||
[ReadOnly]
|
||||
public ComponentLookup<CullAnimationsTag> cullAnimationsTagLookup;
|
||||
[ReadOnly]
|
||||
public BufferLookup<Rukhanka.SkinMatrix> skinMatrixBufferLookup;
|
||||
[ReadOnly]
|
||||
public BufferLookup<Rukhanka.BlendShapeWeight> blendShapeWeightBufferLookup;
|
||||
[ReadOnly]
|
||||
[NativeDisableContainerSafetyRestriction]
|
||||
public NativeList<LODGroupExtensions.LODParams> lodAffectors;
|
||||
[ReadOnly]
|
||||
public ComponentLookup<LODRange> lodRangeLookup;
|
||||
[ReadOnly]
|
||||
public ComponentLookup<LODWorldReferencePoint> lodWorldRefPointLookup;
|
||||
|
||||
public NativeParallelHashMap<Entity, SkinnedMeshRendererFrameDeformationData>.ParallelWriter entityToSMRFrameData;
|
||||
|
||||
#if UNITY_EDITOR
|
||||
public bool isEditorWorld;
|
||||
#endif
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void Execute(Entity e, in SkinnedMeshRendererComponent asm)
|
||||
{
|
||||
#if UNITY_EDITOR
|
||||
if (!isEditorWorld)
|
||||
#endif
|
||||
if (cullAnimationsTagLookup.HasComponent(asm.animatedRigEntity) && cullAnimationsTagLookup.IsComponentEnabled(asm.animatedRigEntity))
|
||||
return;
|
||||
|
||||
if (!IsLODActive(e))
|
||||
return;
|
||||
|
||||
var smrdd = SkinnedMeshRendererFrameDeformationData.MakeDefault();
|
||||
|
||||
#if RUKHANKA_INPLACE_SKINNING
|
||||
var currentDeformedMeshIndex = frameDeformedVerticesCounter.Add(1);
|
||||
smrdd.deformedVertexIndex = currentDeformedMeshIndex;
|
||||
#else
|
||||
var currentDeformedVertexIndex = frameDeformedVerticesCounter.Add(asm.smrInfoBlob.Value.meshVerticesCount);
|
||||
smrdd.deformedVertexIndex = currentDeformedVertexIndex;
|
||||
#endif
|
||||
|
||||
if (skinMatrixBufferLookup.TryGetBuffer(e, out var smb))
|
||||
{
|
||||
var currentSkinMatrixBufferOffset = skinMatrixOffsetCounter.Add(smb.Length);
|
||||
smrdd.skinMatrixIndex = currentSkinMatrixBufferOffset;
|
||||
}
|
||||
|
||||
if (blendShapeWeightBufferLookup.TryGetBuffer(e, out var blendShapeWeights))
|
||||
{
|
||||
var currentBlendShapeWeightsBufferOffset = blendShapeWeightOffsetCounter.Add(blendShapeWeights.Length);
|
||||
smrdd.blendShapeWeightIndex = currentBlendShapeWeightsBufferOffset;
|
||||
}
|
||||
|
||||
entityToSMRFrameData.TryAdd(e, smrdd);
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
float CalculateLODDistance(in LODRange lodRange, in LODWorldReferencePoint lodRefPoint, in LODGroupExtensions.LODParams lodParams)
|
||||
{
|
||||
float rv = lodParams.distanceScale;
|
||||
if (!lodParams.isOrtho)
|
||||
rv *= math.length(lodParams.cameraPos - lodRefPoint.Value);
|
||||
return rv;
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
bool IsLODActive(Entity e)
|
||||
{
|
||||
if (!lodAffectors.IsCreated || !lodRangeLookup.TryGetComponent(e, out var lodRange) || !lodWorldRefPointLookup.TryGetComponent(e, out var lodRefPoint))
|
||||
return true;
|
||||
|
||||
for (var i = 0; i < lodAffectors.Length; ++i)
|
||||
{
|
||||
var la = lodAffectors[i];
|
||||
var d = CalculateLODDistance(lodRange, lodRefPoint, la);
|
||||
var isLodActive = d < lodRange.MaxDist && d >= lodRange.MinDist;
|
||||
if (isLodActive)
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
+18
@@ -0,0 +1,18 @@
|
||||
fileFormatVersion: 2
|
||||
guid: d9c7705a36a0cb4429caa4d2e27e59b7
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
AssetOrigin:
|
||||
serializedVersion: 1
|
||||
productId: 298480
|
||||
packageName: Rukhanka Animation System 2
|
||||
packageVersion: 2.9.0
|
||||
assetPath: Packages/com.rukhanka.animation/Rukhanka.Runtime/Deformation/SkinnedMeshPreparationSystem_Jobs.cs
|
||||
uploadId: 897522
|
||||
Reference in New Issue
Block a user