Files
o3de/Gems/Atom/Feature/Common/Code/Source/SkinnedMesh/SkinnedMeshRenderProxy.cpp
T
Aaron Ruiz Mora 7781307afe Fixed cloth automated tests. (#1400)
Bone transforms buffer is not valid when using Null renderer, which caused the test to fail since it reported an error and ultimately crashing as well. For now it's been worked around by checking the pointer is valid and not printing the error when null renderer is used, a task for the Atom team has been created to fix this properly in the future (ATOM-15807).
2021-06-17 19:23:12 +01:00

161 lines
7.0 KiB
C++

/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
#include <SkinnedMesh/SkinnedMeshRenderProxy.h>
#include <SkinnedMesh/SkinnedMeshFeatureProcessor.h>
#include <SkinnedMesh/SkinnedMeshComputePass.h>
#include <MorphTargets/MorphTargetComputePass.h>
#include <Atom/Feature/Mesh/MeshFeatureProcessor.h>
#include <Atom/RPI.Public/Model/Model.h>
#include <Atom/RPI.Public/Scene.h>
#include <Atom/RPI.Public/Shader/Shader.h>
#include <Atom/Utils/Utils.h>
#include <AzCore/Debug/EventTrace.h>
namespace AZ
{
namespace Render
{
SkinnedMeshRenderProxy::SkinnedMeshRenderProxy(const SkinnedMeshFeatureProcessorInterface::SkinnedMeshRenderProxyDesc& desc)
: m_inputBuffers(desc.m_inputBuffers)
, m_instance(desc.m_instance)
, m_meshHandle(desc.m_meshHandle)
, m_boneTransforms(desc.m_boneTransforms)
, m_shaderOptions(desc.m_shaderOptions)
{
}
bool SkinnedMeshRenderProxy::Init(const RPI::Scene& scene, SkinnedMeshFeatureProcessor* featureProcessor)
{
AZ_TRACE_METHOD();
if(!m_instance->m_model)
{
return false;
}
const size_t modelLodCount = m_instance->m_model->GetLodCount();
m_featureProcessor = featureProcessor;
for (size_t modelLodIndex = 0; modelLodIndex < modelLodCount; ++modelLodIndex)
{
if (!BuildDispatchItem(scene, modelLodIndex, m_shaderOptions))
{
return false;
}
}
return true;
}
bool SkinnedMeshRenderProxy::BuildDispatchItem([[maybe_unused]] const RPI::Scene& scene, size_t modelLodIndex, [[maybe_unused]] const SkinnedMeshShaderOptions& shaderOptions)
{
Data::Instance<RPI::Shader> skinningShader = m_featureProcessor->GetSkinningShader();
if (!skinningShader)
{
AZ_Error("Skinned Mesh Feature Processor", false, "Failed to get skinning shader from skinning pass");
return false;
}
// Get the value needed for encoding/decoding floats as integers when passing them
// from the morph target pass to the skinning pass.
// Integer encoding is used so that AZSL's InterlockedAdd can be used, wich only supports int/uint
const AZStd::vector<MorphTargetMetaData>& morphTargetMetaDatas = m_inputBuffers->GetMorphTargetMetaData(modelLodIndex);
float morphDeltaIntegerEncoding = 0.0f;
if (morphTargetMetaDatas.size() > 0)
{
morphDeltaIntegerEncoding = ComputeMorphTargetIntegerEncoding(morphTargetMetaDatas);
}
m_dispatchItemsByLod.emplace_back(
aznew SkinnedMeshDispatchItem{
m_inputBuffers,
m_instance->m_outputStreamOffsetsInBytes[modelLodIndex],
modelLodIndex, m_boneTransforms,
m_shaderOptions,
m_featureProcessor,
m_instance->m_morphTargetInstanceMetaData[modelLodIndex],
morphDeltaIntegerEncoding });
AZ_Assert(m_dispatchItemsByLod.size() == modelLodIndex + 1, "Skinned Mesh Feature Processor - Mismatch in size between the fixed vector of dispatch items and the lod being initialized");
if (!m_dispatchItemsByLod[modelLodIndex]->Init())
{
return false;
}
// Get the data needed to create a morph target dispatch item
Data::Instance<RPI::Shader> morphTargetShader = m_featureProcessor->GetMorphTargetShader();
const AZStd::vector<AZStd::intrusive_ptr<MorphTargetInputBuffers>>& morphTargetInputBuffersVector = m_inputBuffers->GetMorphTargetInputBuffers(modelLodIndex);
AZ_Assert(morphTargetMetaDatas.size() == morphTargetInputBuffersVector.size(), "Skinned Mesh Feature Processor - Mismatch in morph target metadata count and morph target input buffer count");
if (!morphTargetShader && morphTargetMetaDatas.size() > 0)
{
AZ_Error("Skinned Mesh Feature Processor", false, "Failed to get morph target shader from morph target pass");
return false;
}
// Create one dispatch item per morph target
m_morphTargetDispatchItemsByLod.emplace_back(AZStd::vector<AZStd::unique_ptr<MorphTargetDispatchItem>>());
for (size_t morphTargetIndex = 0; morphTargetIndex < morphTargetMetaDatas.size(); ++morphTargetIndex)
{
m_morphTargetDispatchItemsByLod[modelLodIndex].emplace_back(
aznew MorphTargetDispatchItem{
morphTargetInputBuffersVector[morphTargetIndex],
morphTargetMetaDatas[morphTargetIndex],
m_featureProcessor,
m_instance->m_morphTargetInstanceMetaData[modelLodIndex],
morphDeltaIntegerEncoding });
// Initialize the MorphTargetDispatchItem we just created
if (!m_morphTargetDispatchItemsByLod[modelLodIndex].back()->Init())
{
return false;
}
}
return true;
}
void SkinnedMeshRenderProxy::SetTransform(const AZ::Transform& transform)
{
// Set the position to be used for determining lod
m_position = transform.GetTranslation();
}
void SkinnedMeshRenderProxy::SetSkinningMatrices(const AZStd::vector<float>& data)
{
if (m_boneTransforms)
{
WriteToBuffer(m_boneTransforms->GetRHIBuffer(), data);
}
}
void SkinnedMeshRenderProxy::SetMorphTargetWeights(uint32_t lodIndex, const AZStd::vector<float>& weights)
{
auto& morphTargetDispatchItems = m_morphTargetDispatchItemsByLod[lodIndex];
AZ_Assert(morphTargetDispatchItems.size() == weights.size(), "Skinned Mesh Feature Processor - Morph target weights passed into SetMorphTargetWeight don't align with morph target dispatch items.");
for (size_t morphIndex = 0; morphIndex < weights.size(); ++morphIndex)
{
morphTargetDispatchItems[morphIndex]->SetWeight(weights[morphIndex]);
}
}
AZStd::array_view<AZStd::unique_ptr<SkinnedMeshDispatchItem>> SkinnedMeshRenderProxy::GetDispatchItems() const
{
return m_dispatchItemsByLod;
}
} // namespace Render
} // namespace AZ