Skip to content

Commit

Permalink
Refactor SkinnedMeshFeatureProcessor (DCO fixed) (#9171)
Browse files Browse the repository at this point in the history
* Squash skinned mesh dispatch changes (#299)

Squashing several changes from a staging branch into a single commit to get rid of some bad history.
Each of these changes was individually reviewed:

One skinning dispatch per mesh: Part 1
aws-lumberyard-dev#286

Removing support for morph targets that modify vertex colors
aws-lumberyard-dev#288

One SkinnedMesh Dispatch Per Mesh Part 2: Morph targets
aws-lumberyard-dev#294

Support for more or less than 4 influences per vertex
aws-lumberyard-dev#296

Skip skinning cloth meshes
aws-lumberyard-dev#297

Support varying influence counts per mesh
aws-lumberyard-dev#298

* WIP use oned dispatch per mesh instead of per lod for skinning. Need to update Actor.cpp to account for the new padding in the bone Id's

Signed-off-by: Tommy Walton <waltont@amazon.com>

* Attempt to fix JointId buffer

Signed-off-by: Tommy Walton <waltont@amazon.com>

* WIP use oned dispatch per mesh instead of per lod for skinning. Need to update Actor.cpp to account for the new padding in the bone Id's

Signed-off-by: Tommy Walton <waltont@amazon.com>

* Attempt to fix JointId buffer

Signed-off-by: Tommy Walton <waltont@amazon.com>

* Fix compile errors

Signed-off-by: Tommy Walton <waltont@amazon.com>

* Fix Material->MaterialAsset name mixup

Signed-off-by: Tommy Walton <waltont@amazon.com>

* Fix 3-component buffer views to work with metal

Signed-off-by: Tommy Walton <waltont@amazon.com>

* Fixing position history writing to the incorrect offset

Signed-off-by: Tommy Walton <waltont@amazon.com>

* Fix JointId alignment issue

Signed-off-by: Tommy Walton <waltont@amazon.com>

* Moved jointId padding logic into a separate file that can be shared between EMFX and the ModelAssetBuilderComponent. Also simplified the loop for doing the padding in EMFX.

Signed-off-by: Tommy Walton <waltont@amazon.com>

* Fix incorrect variable name after merge

Signed-off-by: Tommy Walton <waltont@amazon.com>

* Minor cleanup

Signed-off-by: Tommy Walton <waltont@amazon.com>

* More minor cleanup

Signed-off-by: Tommy Walton <waltont@amazon.com>

* Comment updates

Signed-off-by: Tommy Walton <waltont@amazon.com>

* Split giant CreateFromModel function into smaller functions that should be easier to follow.

Signed-off-by: Tommy Walton <waltont@amazon.com>

* More minor cleanup/re-naming

Signed-off-by: Tommy Walton <waltont@amazon.com>

* Switch from AZ::RoundUpToMultiple to AZ::SizeAlignUp since the alignment is a power of two

Signed-off-by: Tommy Walton <waltont@amazon.com>

* Minor PR feedback

Signed-off-by: Tommy Walton <waltont@amazon.com>

* Switch from size_t to uint32_t

Signed-off-by: Tommy Walton <waltont@amazon.com>

* Fixing a few integer conversion related failures on non-windows platforms

Signed-off-by: Tommy Walton <waltont@amazon.com>

* Removing support for morph targets that modify vertex colors

Signed-off-by: Tommy Walton <waltont@amazon.com>

* One SkinnedMesh Dispatch Per Mesh Part 2: Morph targets (#294)

* Update morph targets to work with per-mesh dispatches

Signed-off-by: Tommy Walton <waltont@amazon.com>

* Moving some things around to make the updated render proxy logic easier to follow

Signed-off-by: Tommy Walton <waltont@amazon.com>

* Store morph targets in the order they were created instead of on individual meshes

Signed-off-by: Tommy Walton <waltont@amazon.com>

* Minor PR feedback

Signed-off-by: Tommy Walton <waltont@amazon.com>

* Support for more or less than 4 influences per vertex (#296)

* Initial support for more than 4 influences per vertex

Signed-off-by: Tommy Walton <waltont@amazon.com>

* Fix shader compile error

Signed-off-by: Tommy Walton <waltont@amazon.com>

* Add a settings registry setting to modify the default max influences per vertex

Signed-off-by: Tommy Walton <waltont@amazon.com>

* Add a comment explaining the jointId offset

Signed-off-by: Tommy Walton <waltont@amazon.com>

* PR Feedback

Signed-off-by: Tommy Walton <waltont@amazon.com>

* Support varying influence counts per mesh (#298)

* Modify ModelAssetBuilder to allow for meshes to have different per-vertex influence counts

Signed-off-by: Tommy Walton <waltont@amazon.com>

* Fix merge error.

Signed-off-by: Tommy Walton <waltont@amazon.com>

* Update EMFX::Mesh to work with sub-meshes that have varying influence counts

Signed-off-by: Tommy Walton <waltont@amazon.com>

* Use the max influence count across all meshes to pre-allocate memory for the EMFX skin layer

Signed-off-by: Tommy Walton <waltont@amazon.com>

* Get rid of local vector in ProcessSkinInfluences to improve performance during level load

Signed-off-by: Tommy Walton <waltont@amazon.com>

* Fix an incorrect comment

Signed-off-by: Tommy Walton <waltont@amazon.com>

* PR feedback

Signed-off-by: Tommy Walton <waltont@amazon.com>

* Skip skinning cloth meshes (#297)

* Skip skinning dispatch entirely for certain meshes(like those with cloth) instead of modifying the blendweights to all be 0

Signed-off-by: Tommy Walton <waltont@amazon.com>

* Working but somewhat hacky attempt to push the skip skinning logic to the component

Signed-off-by: Tommy Walton <waltont@amazon.com>

* Disable via ebus instead

Signed-off-by: amzn-tommy <waltont@amazon.com>

* Rename shouldSkipSkinning to isSkinningEnabled which is easier to follow with set/get methods

Signed-off-by: amzn-tommy <waltont@amazon.com>

* Add SkinnedMeshOverrideBus, which was missing from an earlier commit

Signed-off-by: amzn-tommy <waltont@amazon.com>

* Update FillSkinnedMeshInstanceBuffers to only fill buffers for meshes that won't be skinned.

Signed-off-by: amzn-tommy <waltont@amazon.com>

* Allow cloth to tell skinning to be enabled/disabled at any time instead of requesting it from cloth at a particular point of initialization

Signed-off-by: Tommy Walton <waltont@amazon.com>

* Remove function for filling buffers, since now they are either filled by simulation or filled by skinning

Signed-off-by: Tommy Walton <waltont@amazon.com>

* Minor PR feedback

Signed-off-by: Tommy Walton <waltont@amazon.com>

* Support varying influence counts per mesh (#298)

* Modify ModelAssetBuilder to allow for meshes to have different per-vertex influence counts

Signed-off-by: Tommy Walton <waltont@amazon.com>

* Fix merge error.

Signed-off-by: Tommy Walton <waltont@amazon.com>

* Update EMFX::Mesh to work with sub-meshes that have varying influence counts

Signed-off-by: Tommy Walton <waltont@amazon.com>

* Use the max influence count across all meshes to pre-allocate memory for the EMFX skin layer

Signed-off-by: Tommy Walton <waltont@amazon.com>

* Get rid of local vector in ProcessSkinInfluences to improve performance during level load

Signed-off-by: Tommy Walton <waltont@amazon.com>

* Fix an incorrect comment

Signed-off-by: Tommy Walton <waltont@amazon.com>

* PR feedback

Signed-off-by: Tommy Walton <waltont@amazon.com>

Co-authored-by: Jon B <jonbold@amazon.com>
Signed-off-by: Tommy Walton <waltont@amazon.com>

* Redcode old SkinnedMesh interfaces (#301)

* Redcode

Signed-off-by: Tommy Walton <waltont@amazon.com>

* More redcode

Signed-off-by: Tommy Walton <waltont@amazon.com>

* Even more redcode

Signed-off-by: Tommy Walton <waltont@amazon.com>

* Still more redcode

Signed-off-by: Tommy Walton <waltont@amazon.com>

* Modified the handle to be opaque to the underlying implemention, and have operations on the handle done through the feature processor interface instead of directly via the handle (#302)

Signed-off-by: Tommy Walton <waltont@amazon.com>

* Fix cloth skinning for assets that have different influence counts for each sub-mesh (#313)

* Fix cloth skinning for assets that have different influence counts for each sub-mesh

Signed-off-by: Tommy Walton <waltont@amazon.com>

* Removed check for invalid jointId, which no longer occurs and should be handled by the higher level actor initialization. Also renamed a few variables based on PR feedback.

Signed-off-by: Tommy Walton <waltont@amazon.com>

* Fixed a miss-spelling of the word skinning

Signed-off-by: Tommy Walton <waltont@amazon.com>

* Fixing a couple print statements using %zu for a variable that was changed to uint32_t

Signed-off-by: Tommy Walton <waltont@amazon.com>

* Fix missing commits for unity build and added spaces around PRIu32

Signed-off-by: Tommy Walton <waltont@amazon.com>

* Made other uses of PRIu32 have spaces as well for consistency

Signed-off-by: Tommy Walton <waltont@amazon.com>

* Minor build fixes: A type mis-match between AZ::u64 and uint64_t, an unnecessary call to reserve on a fixed_vector, a missing namespace in a unit test, and an unused variable.

Signed-off-by: Tommy Walton <waltont@amazon.com>

* Remove unused variable

Signed-off-by: Tommy Walton <waltont@amazon.com>

Co-authored-by: Jon B <jonbold@amazon.com>
  • Loading branch information
amzn-tommy and Jon B committed Apr 27, 2022
1 parent e125689 commit 3ff2f29
Show file tree
Hide file tree
Showing 58 changed files with 1,659 additions and 1,576 deletions.
31 changes: 31 additions & 0 deletions Code/Tools/SceneAPI/SceneCore/DataTypes/Rules/ISkinRule.h
Expand Up @@ -9,6 +9,7 @@
*/

#include <AzCore/RTTI/RTTI.h>
#include <AzCore/Settings/SettingsRegistry.h>
#include <SceneAPI/SceneCore/DataTypes/Rules/IRule.h>

namespace AZ
Expand All @@ -17,6 +18,36 @@ namespace AZ
{
namespace DataTypes
{
inline static constexpr AZStd::string_view DefaultMaxSkinInfluencesPerVertexKey{ "/O3DE/SceneAPI/SkinRule/DefaultMaxSkinInfluencesPerVertex" };
inline static constexpr AZStd::string_view DefaultWeightThresholdKey{ "/O3DE/SceneAPI/SkinRule/DefaultWeightThreshold" };

struct SkinRuleSettings
{
AZ::u32 m_maxInfluencesPerVertex = 8;
float m_weightThreshold = 0.001;
};

inline SkinRuleSettings GetDefaultSkinRuleSettings()
{
SkinRuleSettings defaultSettings;
// Get the project wide default settings for the skin rule
if (auto settingsRegistry = AZ::SettingsRegistry::Get(); settingsRegistry != nullptr)
{
AZ::u64 defaultMaxSkinInfluences = 0;
if (settingsRegistry->Get(defaultMaxSkinInfluences, SceneAPI::DataTypes::DefaultMaxSkinInfluencesPerVertexKey))
{
defaultSettings.m_maxInfluencesPerVertex = aznumeric_caster(defaultMaxSkinInfluences);
}

double defaultWeightThreshold = 0.0f;
if (settingsRegistry->Get(defaultWeightThreshold, SceneAPI::DataTypes::DefaultWeightThresholdKey))
{
defaultSettings.m_weightThreshold = aznumeric_caster(defaultWeightThreshold);
}
}
return defaultSettings;
}

class ISkinRule
: public IRule
{
Expand Down
6 changes: 4 additions & 2 deletions Code/Tools/SceneAPI/SceneData/Rules/SkinRule.cpp
Expand Up @@ -21,10 +21,12 @@ namespace AZ
AZ_CLASS_ALLOCATOR_IMPL(SkinRule, AZ::SystemAllocator, 0)

SkinRule::SkinRule()
: m_maxWeightsPerVertex(4)
, m_weightThreshold(0.001f)
{
DataTypes::SkinRuleSettings defaultSettings = DataTypes::GetDefaultSkinRuleSettings();
m_maxWeightsPerVertex = defaultSettings.m_maxInfluencesPerVertex;
m_weightThreshold = defaultSettings.m_weightThreshold;
}

AZ::u32 SkinRule::GetMaxWeightsPerVertex() const
{
return m_maxWeightsPerVertex;
Expand Down
Expand Up @@ -17,9 +17,6 @@ rootconstant uint s_targetPositionOffset;
rootconstant uint s_targetNormalOffset;
rootconstant uint s_targetTangentOffset;
rootconstant uint s_targetBitangentOffset;
rootconstant uint s_targetColorOffset;

option bool o_hasColorDeltas = false;

void WriteDeltaToAccumulationBuffer(float3 delta, uint offset, uint morphedVertexIndex)
{
Expand Down Expand Up @@ -87,18 +84,5 @@ void MainCS(uint3 thread_id: SV_DispatchThreadID)
// Now that we have the compressed bitangents, unpack them and write them to the accumulation buffer
float3 bitangentDelta = DecodeTBNDelta(compressedBitangentDelta) * s_weight;
WriteDeltaToAccumulationBuffer(bitangentDelta, s_targetBitangentOffset, morphedVertexIndex);

if (o_hasColorDeltas)
{
uint4 compressedColorDelta;
// Colors are in the least significant 24 bits (8 bits per channel)
compressedColorDelta.r = (delta.m_compressedColorDeltaRGBA >> 24) & 0x000000FF;
compressedColorDelta.g = (delta.m_compressedColorDeltaRGBA >> 16) & 0x000000FF;
compressedColorDelta.b = (delta.m_compressedColorDeltaRGBA >> 8) & 0x000000FF;
compressedColorDelta.a = delta.m_compressedColorDeltaRGBA & 0x000000FF;

float4 colorDelta = DecodeColorDelta(compressedColorDelta) * s_weight;
WriteDeltaToAccumulationBuffer(colorDelta, s_targetColorOffset, morphedVertexIndex);
}
}
}
Expand Up @@ -32,10 +32,8 @@ struct MorphTargetDelta
uint m_compressedNormalDeltaZTangentDelta;
// 8 bit padding plus 8 bits per component for bitangent deltas
uint m_compressedPadBitangentDeltaXYZ;
// 8 bits per component for color delta
uint m_compressedColorDeltaRGBA;
// Extra padding so the struct is 16 byte aligned for structured buffers
uint2 m_pad;
uint3 m_pad;
};

// Input to the morph target compute shader
Expand Down
Expand Up @@ -13,7 +13,6 @@

option enum class SkinningMethod { LinearSkinning, DualQuaternion } o_skinningMethod = SkinningMethod::LinearSkinning;
option bool o_applyMorphTargets = false;
option bool o_applyColorMorphTargets = false;

float3 ReadFloat3FromFloatBuffer(Buffer<float> buffer, uint index)
{
Expand Down Expand Up @@ -92,14 +91,37 @@ void SkinTBN(float3x3 skinToWorldMatrix, inout float3 normal, inout float4 tange

////////////////////////////////////////////////////////////////////////////////////////////////////
// Skinning support
void SkinVertexLinear(int4 indices, float4 weights, inout float3 position, inout float3 normal, inout float4 tangent, inout float3 bitangent)

// Get two weights and two joint ids
void GetInfluences(in uint weightStartOffsetForVertex, in uint jointIdStartOffsetForVertex, in uint influenceIndex, out float2 weights, out uint2 jointIds)
{
weights.x = InstanceSrg::m_sourceBlendWeights[weightStartOffsetForVertex + influenceIndex];
weights.y = InstanceSrg::m_sourceBlendWeights[weightStartOffsetForVertex + influenceIndex + 1];

// Two indices, 16-bits each, stored in a 32-bit uint
uint rawIndex = InstanceSrg::m_sourceBlendIndices.Load(jointIdStartOffsetForVertex + influenceIndex);

// The first index in each 32-bit pair is in the most significant bits in the buffer
jointIds.x = rawIndex >> 16 & 0x0000FFFF;
jointIds.y = rawIndex & 0x0000FFFF;
}

void SkinVertexLinear(uint vertexIndex, inout float3 position, inout float3 normal, inout float4 tangent, inout float3 bitangent)
{
float3x4 skinToWorldMatrix = (float3x4)0;

[unroll]
for(uint i = 0; i < 4; ++i)
uint weightStartOffsetForVertex = vertexIndex * InstanceSrg::m_numInfluencesPerVertex;
// Multiply by two here since the jointId offset is in bytes, and there are two bytes per 16-bit jointId
uint jointIdStartOffsetForVertex = vertexIndex * InstanceSrg::m_numInfluencesPerVertex * 2;
[loop]
for(uint i = 0; i < InstanceSrg::m_numInfluencesPerVertex; i+=2)
{
skinToWorldMatrix += InstanceSrg::m_boneTransformsLinear[ indices[i] ] * weights[i];
float2 weights;
float2 jointIds;
GetInfluences(weightStartOffsetForVertex, jointIdStartOffsetForVertex, i, weights, jointIds);

skinToWorldMatrix += InstanceSrg::m_boneTransformsLinear[ jointIds.x ] * weights.x;
skinToWorldMatrix += InstanceSrg::m_boneTransformsLinear[ jointIds.y ] * weights.y;
}

position = mul(skinToWorldMatrix, float4(position, 1.0));
Expand All @@ -120,14 +142,22 @@ void NormalizeDualQuaternion(inout float2x4 dualQuaternion)
dualQuaternion *= invLength;
}

void SkinVertexDualQuaternion(int4 indices, float4 weights, inout float3 position, inout float3 normal, inout float4 tangent, inout float3 bitangent)
void SkinVertexDualQuaternion(uint vertexIndex, inout float3 position, inout float3 normal, inout float4 tangent, inout float3 bitangent)
{
float2x4 skinToWorldDualQuaternion = (float2x4)0;

[unroll]
for(uint i = 0; i < 4; ++i)
{
AddWeightedDualQuaternion(skinToWorldDualQuaternion, InstanceSrg::m_boneTransformsDualQuaternion[ indices[i] ], weights[i]);
uint weightStartOffsetForVertex = vertexIndex * InstanceSrg::m_numInfluencesPerVertex;
// Multiply by two here since the jointId offset is in bytes, and there are two bytes per 16-bit jointId
uint jointIdStartOffsetForVertex = vertexIndex * InstanceSrg::m_numInfluencesPerVertex * 2;
[loop]
for(uint i = 0; i < InstanceSrg::m_numInfluencesPerVertex; i+=2)
{
float2 weights;
float2 jointIds;
GetInfluences(weightStartOffsetForVertex, jointIdStartOffsetForVertex, i, weights, jointIds);

AddWeightedDualQuaternion(skinToWorldDualQuaternion, InstanceSrg::m_boneTransformsDualQuaternion[ jointIds.x ], weights.x);
AddWeightedDualQuaternion(skinToWorldDualQuaternion, InstanceSrg::m_boneTransformsDualQuaternion[ jointIds.y ], weights.y);
}

NormalizeDualQuaternion(skinToWorldDualQuaternion);
Expand All @@ -154,46 +184,15 @@ void MainCS(uint3 thread_id: SV_DispatchThreadID)
if(i < InstanceSrg::m_numVertices)
{
// Moving current vertex position updated last frame to a predefined location to maintain a vertex history between two frames
PassSrg::m_skinnedMeshOutputStream[InstanceSrg::m_targetPositions + (InstanceSrg::m_numVertices + i) * 3] = PassSrg::m_skinnedMeshOutputStream[InstanceSrg::m_targetPositions + i * 3];
PassSrg::m_skinnedMeshOutputStream[InstanceSrg::m_targetPositions + (InstanceSrg::m_numVertices + i) * 3 + 1] = PassSrg::m_skinnedMeshOutputStream[InstanceSrg::m_targetPositions + i * 3 + 1];
PassSrg::m_skinnedMeshOutputStream[InstanceSrg::m_targetPositions + (InstanceSrg::m_numVertices + i) * 3 + 2] = PassSrg::m_skinnedMeshOutputStream[InstanceSrg::m_targetPositions + i * 3 + 2];

float4 blendWeights;
blendWeights.x = InstanceSrg::m_sourceBlendWeights[i * 4];
blendWeights.y = InstanceSrg::m_sourceBlendWeights[i * 4 + 1];
blendWeights.z = InstanceSrg::m_sourceBlendWeights[i * 4 + 2];
blendWeights.w = InstanceSrg::m_sourceBlendWeights[i * 4 + 3];

// [TODO ATOM-15288]
// Temporary workaround. When all the blend weights of a vertex are zero it means its data is set by the CPU directly
// and skinning must be skipped to not overwrite it (e.g. cloth simulation).
if(!any(blendWeights))
{
return;
}
PassSrg::m_skinnedMeshOutputStream[InstanceSrg::m_targetPositionHistory + i * 3] = PassSrg::m_skinnedMeshOutputStream[InstanceSrg::m_targetPositions + i * 3];
PassSrg::m_skinnedMeshOutputStream[InstanceSrg::m_targetPositionHistory + i * 3 + 1] = PassSrg::m_skinnedMeshOutputStream[InstanceSrg::m_targetPositions + i * 3 + 1];
PassSrg::m_skinnedMeshOutputStream[InstanceSrg::m_targetPositionHistory + i * 3 + 2] = PassSrg::m_skinnedMeshOutputStream[InstanceSrg::m_targetPositions + i * 3 + 2];

float3 position = ReadFloat3FromFloatBuffer(InstanceSrg::m_sourcePositions, i);
float3 normal = ReadFloat3FromFloatBuffer(InstanceSrg::m_sourceNormals, i);
float4 tangent = InstanceSrg::m_sourceTangents[i];
float3 bitangent = ReadFloat3FromFloatBuffer(InstanceSrg::m_sourceBiTangents, i);

// Four indices, 16-bits each, stored in 2 32-bit uints
uint2 rawIndices = InstanceSrg::m_sourceBlendIndices.Load2(i * 8);

uint4 blendIndices;
// Although the first index in each 32-bit pair is in the most significant bits in the cpu buffer,
// the indices get swapped within the 32-bit uint when they are loaded so we treat them
// as if the first index is in the least significant bits
blendIndices.x = rawIndices.x >> 16;
blendIndices.y = rawIndices.x & 0x0000FFFF;
blendIndices.z = rawIndices.y >> 16;
blendIndices.w = rawIndices.y & 0x0000FFFF;


// Moving current vertex position updated last frame to a predefined location to maintain a vertex history between two frames
PassSrg::m_skinnedMeshOutputStream[InstanceSrg::m_targetPositions + (InstanceSrg::m_numVertices + i) * 3] = PassSrg::m_skinnedMeshOutputStream[InstanceSrg::m_targetPositions + i * 3];
PassSrg::m_skinnedMeshOutputStream[InstanceSrg::m_targetPositions + (InstanceSrg::m_numVertices + i) * 3 + 1] = PassSrg::m_skinnedMeshOutputStream[InstanceSrg::m_targetPositions + i * 3 + 1];
PassSrg::m_skinnedMeshOutputStream[InstanceSrg::m_targetPositions + (InstanceSrg::m_numVertices + i) * 3 + 2] = PassSrg::m_skinnedMeshOutputStream[InstanceSrg::m_targetPositions + i * 3 + 2];

if(o_applyMorphTargets)
{
Expand All @@ -202,24 +201,14 @@ void MainCS(uint3 thread_id: SV_DispatchThreadID)
ApplyMorphTargetDelta(InstanceSrg::m_morphTargetTangentDeltaOffset, i, tangent.xyz);
ApplyMorphTargetDelta(InstanceSrg::m_morphTargetBitangentDeltaOffset, i, bitangent);
}

if (o_applyColorMorphTargets)
{
float4 color = InstanceSrg::m_sourceColors[i];
ApplyMorphTargetDelta(InstanceSrg::m_morphTargetColorDeltaOffset, i, color);
PassSrg::m_skinnedMeshOutputStream[InstanceSrg::m_targetColors + i * 4] = color.r;
PassSrg::m_skinnedMeshOutputStream[InstanceSrg::m_targetColors + i * 4 + 1] = color.g;
PassSrg::m_skinnedMeshOutputStream[InstanceSrg::m_targetColors + i * 4 + 2] = color.b;
PassSrg::m_skinnedMeshOutputStream[InstanceSrg::m_targetColors + i * 4 + 3] = color.a;
}

switch(o_skinningMethod)
{
case SkinningMethod::LinearSkinning:
SkinVertexLinear(blendIndices, blendWeights, position, normal, tangent, bitangent);
SkinVertexLinear(i, position, normal, tangent, bitangent);
break;
case SkinningMethod::DualQuaternion:
SkinVertexDualQuaternion(blendIndices, blendWeights, position, normal, tangent, bitangent);
SkinVertexDualQuaternion(i, position, normal, tangent, bitangent);
break;
}

Expand Down
Expand Up @@ -18,6 +18,7 @@ ShaderResourceGroup PassSrg : SRG_PerPass
ShaderResourceGroup InstanceSrg : SRG_PerDraw
{
uint m_numVertices;
uint m_numInfluencesPerVertex;
uint m_totalNumberOfThreadsX;

// Per-model input
Expand Down Expand Up @@ -62,6 +63,10 @@ ShaderResourceGroup InstanceSrg : SRG_PerDraw
uint m_targetTangents;
uint m_targetBiTangents;

// Offset to the location in the output stream with the start of the position history
// for the particular mesh the dispatch is operating on
uint m_targetPositionHistory;

// Optional color output, if colors are being morphed by morph targets
uint m_targetColors;
}
Expand Up @@ -52,15 +52,17 @@ namespace AZ
Data::Instance<RPI::Buffer> m_vertexDeltaBuffer;
};

struct MorphTargetMetaData
struct MorphTargetComputeMetaData
{
float m_minWeight;
float m_maxWeight;
float m_minDelta;
float m_maxDelta;
uint32_t m_vertexCount;
uint32_t m_positionOffset;
bool m_hasColorDeltas;
// Each morph target dispatch is associated with a single mesh. We need to keep track of which mesh
// so that we can calculate the maximum range a given mesh might be morphed if all of the morph targets
// associated with it were active at once.
uint32_t m_meshIndex;
};

namespace MorphTargetConstants
Expand All @@ -80,7 +82,6 @@ namespace AZ
uint32_t m_accumulatedNormalDeltaOffsetInBytes;
uint32_t m_accumulatedTangentDeltaOffsetInBytes;
uint32_t m_accumulatedBitangentDeltaOffsetInBytes;
uint32_t m_accumulatedColorDeltaOffsetInBytes;
};

}// Render
Expand Down
Expand Up @@ -7,7 +7,6 @@
*/
#pragma once

#include <Atom/Feature/SkinnedMesh/SkinnedMeshRenderProxyInterface.h>
#include <Atom/Feature/SkinnedMesh/SkinnedMeshInstance.h>
#include <Atom/Feature/SkinnedMesh/SkinnedMeshShaderOptions.h>
#include <Atom/Feature/Mesh/MeshFeatureProcessorInterface.h>
Expand All @@ -19,6 +18,7 @@ namespace AZ
namespace Render
{
class SkinnedMeshInputBuffers;
class SkinnedMeshRenderProxy;

//! SkinnedMeshFeatureProcessorInterface provides an interface to acquire and release a SkinnedMeshRenderProxy from the underlying SkinnedMeshFeatureProcessor
class SkinnedMeshFeatureProcessorInterface
Expand All @@ -27,16 +27,30 @@ namespace AZ
public:
AZ_RTTI(AZ::Render::SkinnedMeshFeatureProcessorInterface, "{6BE6D9D7-FFD7-4C35-9A84-4EFDE730F06B}");

struct SkinnedMeshRenderProxyDesc
using SkinnedMeshHandle = StableDynamicArrayHandle<SkinnedMeshRenderProxy>;

struct SkinnedMeshHandleDescriptor
{
Data::Instance<SkinnedMeshInputBuffers> m_inputBuffers;
AZStd::intrusive_ptr<SkinnedMeshInstance> m_instance;
AZStd::shared_ptr<MeshFeatureProcessorInterface::MeshHandle> m_meshHandle;
Data::Instance<RPI::Buffer> m_boneTransforms;
SkinnedMeshShaderOptions m_shaderOptions;
};
virtual SkinnedMeshRenderProxyInterfaceHandle AcquireRenderProxyInterface(const SkinnedMeshRenderProxyDesc& desc) = 0;
virtual bool ReleaseRenderProxyInterface(SkinnedMeshRenderProxyInterfaceHandle& handle) = 0;

//! Given a descriptor of the input and output for skinning, acquire a handle to the instance that will be skinned
virtual SkinnedMeshHandle AcquireSkinnedMesh(const SkinnedMeshHandleDescriptor& desc) = 0;
//! Releases the skinned mesh handle
virtual bool ReleaseSkinnedMesh(SkinnedMeshHandle& handle) = 0;
//! Updates the data for the skinning transforms of a given skinned mesh handle
virtual void SetSkinningMatrices(const SkinnedMeshHandle& handle, const AZStd::vector<float>& data) = 0;
//! Updates the morph target weights for all meshes of a given lod of a skinned mesh handle
//! The weights should be in the order that the morph targets were initially added to the SkinnedMeshInputBuffers for the handle
virtual void SetMorphTargetWeights(const SkinnedMeshHandle& handle, uint32_t lodIndex, const AZStd::vector<float>& weights) = 0;
//! Enable skinning for a given mesh and lod of a skinned mesh handle
virtual void EnableSkinning(const SkinnedMeshHandle& handle, uint32_t lodIndex, uint32_t meshIndex) = 0;
//! Disable skinning for a given mesh and lod of a skinned mesh handle
virtual void DisableSkinning(const SkinnedMeshHandle& handle, uint32_t lodIndex, uint32_t meshIndex) = 0;
};
} // namespace Render
} // namespace AZ

0 comments on commit 3ff2f29

Please sign in to comment.