Merge pull request #823 from aws-lumberyard-dev/Atom/jiaweig/ATOM-15125_UV_Tangent
ATOM-15125 Support Reorder of Tangent Streams
This commit is contained in:
@@ -169,7 +169,7 @@ namespace AZ
|
||||
const AZ::Data::Asset<ShaderResourceGroupAsset>& drawSrgAsset = shader->GetAsset()->GetDrawSrgAsset();
|
||||
|
||||
// Set all unspecified shader options to default values, so that we get the most specialized variant possible.
|
||||
// (because FindVariantStableId treats unspecified options as a request specificlly for a variant that doesn't specify those options)
|
||||
// (because FindVariantStableId treats unspecified options as a request specifically for a variant that doesn't specify those options)
|
||||
// [GFX TODO][ATOM-3883] We should consider updating the FindVariantStableId algorithm to handle default values for us, and remove this step here.
|
||||
RPI::ShaderOptionGroup shaderOptions = *shaderItem.GetShaderOptions();
|
||||
shaderOptions.SetUnspecifiedToDefaultValues();
|
||||
@@ -198,6 +198,31 @@ namespace AZ
|
||||
const ShaderVariantId finalVariantId = shaderOptions.GetShaderVariantId();
|
||||
const ShaderVariant& variant = r_forceRootShaderVariantUsage ? shader->GetRootVariant() : shader->GetVariant(finalVariantId);
|
||||
|
||||
RHI::PipelineStateDescriptorForDraw pipelineStateDescriptor;
|
||||
variant.ConfigurePipelineState(pipelineStateDescriptor);
|
||||
|
||||
// Render states need to merge the runtime variation.
|
||||
// This allows materials to customize the render states that the shader uses.
|
||||
const RHI::RenderStates& renderStatesOverlay = *shaderItem.GetRenderStatesOverlay();
|
||||
RHI::MergeStateInto(renderStatesOverlay, pipelineStateDescriptor.m_renderStates);
|
||||
|
||||
streamBufferViewsPerShader.push_back();
|
||||
auto& streamBufferViews = streamBufferViewsPerShader.back();
|
||||
|
||||
UvStreamTangentBitmask uvStreamTangentBitmask;
|
||||
|
||||
if (!m_modelLod->GetStreamsForMesh(
|
||||
pipelineStateDescriptor.m_inputStreamLayout,
|
||||
streamBufferViews,
|
||||
&uvStreamTangentBitmask,
|
||||
variant.GetInputContract(),
|
||||
m_modelLodMeshIndex,
|
||||
m_materialModelUvMap,
|
||||
m_material->GetAsset()->GetMaterialTypeAsset()->GetUvNameMap()))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
Data::Instance<ShaderResourceGroup> drawSrg;
|
||||
if (drawSrgAsset)
|
||||
{
|
||||
@@ -210,31 +235,20 @@ namespace AZ
|
||||
drawSrg->SetShaderVariantKeyFallbackValue(shaderOptions.GetShaderVariantKeyFallbackValue());
|
||||
}
|
||||
|
||||
// Pass UvStreamTangentBitmask to the shader if the draw SRG has it.
|
||||
{
|
||||
AZ::Name shaderUvStreamTangentBitmask = AZ::Name(UvStreamTangentBitmask::SrgName);
|
||||
auto index = drawSrg->FindShaderInputConstantIndex(shaderUvStreamTangentBitmask);
|
||||
|
||||
if (index.IsValid())
|
||||
{
|
||||
drawSrg->SetConstant(index, uvStreamTangentBitmask.GetFullTangentBitmask());
|
||||
}
|
||||
}
|
||||
|
||||
drawSrg->Compile();
|
||||
}
|
||||
|
||||
RHI::PipelineStateDescriptorForDraw pipelineStateDescriptor;
|
||||
variant.ConfigurePipelineState(pipelineStateDescriptor);
|
||||
|
||||
// Render states need to merge the runtime variation.
|
||||
// This allows materials to customize the render states that the shader uses.
|
||||
const RHI::RenderStates& renderStatesOverlay = *shaderItem.GetRenderStatesOverlay();
|
||||
RHI::MergeStateInto(renderStatesOverlay, pipelineStateDescriptor.m_renderStates);
|
||||
|
||||
streamBufferViewsPerShader.push_back();
|
||||
auto& streamBufferViews = streamBufferViewsPerShader.back();
|
||||
|
||||
if (!m_modelLod->GetStreamsForMesh(
|
||||
pipelineStateDescriptor.m_inputStreamLayout,
|
||||
streamBufferViews,
|
||||
variant.GetInputContract(),
|
||||
m_modelLodMeshIndex,
|
||||
m_materialModelUvMap,
|
||||
m_material->GetAsset()->GetMaterialTypeAsset()->GetUvNameMap()))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// Use the default draw list tag from the shader variant.
|
||||
RHI::DrawListTag drawListTag = shader->GetDrawListTag();
|
||||
|
||||
|
||||
@@ -117,6 +117,17 @@ namespace AZ
|
||||
return RHI::ResultCode::Success;
|
||||
}
|
||||
|
||||
ModelLod::StreamInfoList::const_iterator ModelLod::FindFirstUvStreamFromMesh(size_t meshIndex) const
|
||||
{
|
||||
const Mesh& mesh = m_meshes[meshIndex];
|
||||
|
||||
auto firstUv = AZStd::find_if(mesh.m_streamInfo.begin(), mesh.m_streamInfo.end(), [](const StreamBufferInfo& info) {
|
||||
return info.m_semantic.m_name.GetStringView().starts_with(RHI::ShaderSemantic::UvStreamSemantic);
|
||||
});
|
||||
|
||||
return firstUv;
|
||||
}
|
||||
|
||||
ModelLod::StreamInfoList::const_iterator ModelLod::FindDefaultUvStream(size_t meshIndex, const MaterialUvNameMap& materialUvNameMap) const
|
||||
{
|
||||
const Mesh& mesh = m_meshes[meshIndex];
|
||||
@@ -160,7 +171,9 @@ namespace AZ
|
||||
const MaterialModelUvOverrideMap& materialModelUvMap,
|
||||
const MaterialUvNameMap& materialUvNameMap,
|
||||
const ShaderInputContract::StreamChannelInfo& contractStreamChannel,
|
||||
StreamInfoList::const_iterator defaultUv) const
|
||||
StreamInfoList::const_iterator defaultUv,
|
||||
StreamInfoList::const_iterator firstUv,
|
||||
UvStreamTangentBitmask* uvStreamTangentBitmaskOut) const
|
||||
{
|
||||
const Mesh& mesh = m_meshes[meshIndex];
|
||||
auto iter = mesh.m_streamInfo.end();
|
||||
@@ -184,8 +197,8 @@ namespace AZ
|
||||
// Cost of linear search UV names is low because the size is extremely limited.
|
||||
return uvNamePair.m_shaderInput == contractStreamChannel.m_semantic;
|
||||
});
|
||||
const bool IsUv = materialUvIter != materialUvNameMap.end();
|
||||
if (IsUv)
|
||||
const bool isUv = materialUvIter != materialUvNameMap.end();
|
||||
if (isUv)
|
||||
{
|
||||
const AZ::Name& materialUvName = materialUvIter->m_uvName;
|
||||
auto modelUvMapIter = materialModelUvMap.find(materialUvIter->m_shaderInput);
|
||||
@@ -224,17 +237,23 @@ namespace AZ
|
||||
});
|
||||
}
|
||||
|
||||
if (iter == mesh.m_streamInfo.end() && IsUv)
|
||||
if (iter == mesh.m_streamInfo.end() && isUv)
|
||||
{
|
||||
iter = defaultUv;
|
||||
}
|
||||
|
||||
if (isUv && uvStreamTangentBitmaskOut)
|
||||
{
|
||||
uvStreamTangentBitmaskOut->ApplyTangent(iter == firstUv ? 0 : UvStreamTangentBitmask::UnassignedTangent);
|
||||
}
|
||||
|
||||
return iter;
|
||||
}
|
||||
|
||||
bool ModelLod::GetStreamsForMesh(
|
||||
RHI::InputStreamLayout& layoutOut,
|
||||
StreamBufferViewList& streamBufferViewsOut,
|
||||
UvStreamTangentBitmask* uvStreamTangentBitmaskOut,
|
||||
const ShaderInputContract& contract,
|
||||
size_t meshIndex,
|
||||
const MaterialModelUvOverrideMap& materialModelUvMap,
|
||||
@@ -250,11 +269,17 @@ namespace AZ
|
||||
|
||||
bool success = true;
|
||||
|
||||
// Searching for the first UV in the mesh, so it can be used to paired with tangent/bitangent stream
|
||||
auto firstUv = FindFirstUvStreamFromMesh(meshIndex);
|
||||
auto defaultUv = FindDefaultUvStream(meshIndex, materialUvNameMap);
|
||||
if (uvStreamTangentBitmaskOut)
|
||||
{
|
||||
uvStreamTangentBitmaskOut->Reset();
|
||||
}
|
||||
|
||||
for (auto& contractStreamChannel : contract.m_streamChannels)
|
||||
{
|
||||
auto iter = FindMatchingStream(meshIndex, materialModelUvMap, materialUvNameMap, contractStreamChannel, defaultUv);
|
||||
auto iter = FindMatchingStream(meshIndex, materialModelUvMap, materialUvNameMap, contractStreamChannel, defaultUv, firstUv, uvStreamTangentBitmaskOut);
|
||||
|
||||
if (iter == mesh.m_streamInfo.end())
|
||||
{
|
||||
@@ -340,6 +365,7 @@ namespace AZ
|
||||
const Mesh& mesh = m_meshes[meshIndex];
|
||||
|
||||
auto defaultUv = FindDefaultUvStream(meshIndex, materialUvNameMap);
|
||||
auto firstUv = FindFirstUvStreamFromMesh(meshIndex);
|
||||
|
||||
for (auto& contractStreamChannel : contract.m_streamChannels)
|
||||
{
|
||||
@@ -350,7 +376,7 @@ namespace AZ
|
||||
|
||||
AZ_Assert(contractStreamChannel.m_streamBoundIndicatorIndex.IsValid(), "m_streamBoundIndicatorIndex was invalid for an optional shader input stream");
|
||||
|
||||
auto iter = FindMatchingStream(meshIndex, materialModelUvMap, materialUvNameMap, contractStreamChannel, defaultUv);
|
||||
auto iter = FindMatchingStream(meshIndex, materialModelUvMap, materialUvNameMap, contractStreamChannel, defaultUv, firstUv, nullptr);
|
||||
|
||||
ShaderOptionValue isStreamBound = (iter == mesh.m_streamInfo.end()) ? ShaderOptionValue{0} : ShaderOptionValue{1};
|
||||
shaderOptions.SetValue(contractStreamChannel.m_streamBoundIndicatorIndex, isStreamBound);
|
||||
|
||||
@@ -0,0 +1,71 @@
|
||||
/*
|
||||
* 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 <Atom/RPI.Public/Model/UvStreamTangentBitmask.h>
|
||||
#include <AzCore/Debug/Trace.h>
|
||||
|
||||
namespace AZ
|
||||
{
|
||||
namespace RPI
|
||||
{
|
||||
uint32_t UvStreamTangentBitmask::GetFullTangentBitmask() const
|
||||
{
|
||||
return m_mask;
|
||||
}
|
||||
|
||||
uint32_t UvStreamTangentBitmask::GetUvStreamCount() const
|
||||
{
|
||||
return m_mask >> (sizeof(m_mask) * CHAR_BIT - BitsForUvIndex);
|
||||
}
|
||||
|
||||
uint32_t UvStreamTangentBitmask::GetTangentAtUv(uint32_t uvIndex) const
|
||||
{
|
||||
return (m_mask >> (BitsPerTangent * uvIndex)) & 0b1111u;
|
||||
}
|
||||
|
||||
void UvStreamTangentBitmask::ApplyTangent(uint32_t tangentIndex)
|
||||
{
|
||||
uint32_t currentSlot = GetUvStreamCount();
|
||||
if (currentSlot >= MaxUvSlots)
|
||||
{
|
||||
AZ_Error("UV Stream", false, "Reaching the max of avaiblable stream slots.");
|
||||
return;
|
||||
}
|
||||
|
||||
if (tangentIndex > UnassignedTangent)
|
||||
{
|
||||
AZ_Warning(
|
||||
"UV Stream", false,
|
||||
"Tangent index must use %d bits as defined in UvStreamTangentIndex::m_flag. Unassigned index will be applied.",
|
||||
BitsPerTangent);
|
||||
tangentIndex = UnassignedTangent;
|
||||
}
|
||||
|
||||
uint32_t clearMask = 0b1111u << (BitsPerTangent * currentSlot);
|
||||
clearMask = ~clearMask;
|
||||
|
||||
// Clear the writing bits in case
|
||||
m_mask &= clearMask;
|
||||
|
||||
// Write the bits to the slot
|
||||
m_mask |= (tangentIndex << (BitsPerTangent * currentSlot));
|
||||
|
||||
// Increase the index
|
||||
m_mask += (1u << (sizeof(m_mask) * CHAR_BIT - BitsForUvIndex));
|
||||
}
|
||||
|
||||
void UvStreamTangentBitmask::Reset()
|
||||
{
|
||||
m_mask = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user