Addressed review comments.

main
jiaweig 5 years ago
parent f8608ff351
commit c3794ca96c

@ -77,12 +77,6 @@ PSDepthOutput MainPS(VSDepthOutput IN, bool isFrontFace : SV_IsFrontFace)
if(ShouldHandleParallaxInDepthShaders())
{
// We support two UV streams, but only a single stream of tangent/bitangent.
// By default, the first UV stream is applied and the default tangent/bitangent are used.
// If anything uses the second UV stream, and it is not a duplication of the first stream,
// generated tangent/bitangent will be applied.
// (As it implies, cases may occur where all/none of the UV steams use the default TB.)
// Whether a UV stream can use the tangent/bitangent are encoded in DrawSrg.
float3 tangents[UvSetCount] = { IN.m_tangent.xyz, IN.m_tangent.xyz };
float3 bitangents[UvSetCount] = { IN.m_bitangent.xyz, IN.m_bitangent.xyz };
PrepareGeneratedTangent(IN.m_normal, IN.m_worldPosition, isFrontFace, IN.m_uv, UvSetCount, tangents, bitangents);

@ -117,20 +117,10 @@ VSOutput EnhancedPbr_ForwardPassVS(VSInput IN)
PbrLightingOutput ForwardPassPS_Common(VSOutput IN, bool isFrontFace, out float depth)
{
// ------- Tangents & Bitangets -------
// We support two UV streams, but only a single stream of tangent/bitangent.
// By default, the first UV stream is applied and the default tangent/bitangent are used.
// If anything uses the second UV stream, and it is not a duplication of the first stream,
// generated tangent/bitangent will be applied.
// (As it implies, cases may occur where all/none of the UV steams use the default TB.)
// Whether a UV stream can use the tangent/bitangent are encoded in DrawSrg.
float3 tangents[UvSetCount] = { IN.m_tangent.xyz, IN.m_tangent.xyz };
float3 bitangents[UvSetCount] = { IN.m_bitangent.xyz, IN.m_bitangent.xyz };
if ((o_parallax_feature_enabled && !o_enableSubsurfaceScattering && MaterialSrg::m_parallaxUvIndex != 0)
|| (o_normal_useTexture && MaterialSrg::m_normalMapUvIndex != 0)
|| (o_clearCoat_enabled && o_clearCoat_normal_useTexture && MaterialSrg::m_clearCoatNormalMapUvIndex != 0)
|| (o_detail_normal_useTexture && MaterialSrg::m_detail_allMapsUvIndex != 0))
if ((o_parallax_feature_enabled && !o_enableSubsurfaceScattering) || o_normal_useTexture || (o_clearCoat_enabled && o_clearCoat_normal_useTexture) || o_detail_normal_useTexture)
{
PrepareGeneratedTangent(IN.m_normal, IN.m_worldPosition, isFrontFace, IN.m_uv, UvSetCount, tangents, bitangents);
}

@ -80,12 +80,6 @@ PSDepthOutput MainPS(VertexOutput IN, bool isFrontFace : SV_IsFrontFace)
{
static const float ShadowMapDepthBias = 0.000001;
// We support two UV streams, but only a single stream of tangent/bitangent.
// By default, the first UV stream is applied and the default tangent/bitangent are used.
// If anything uses the second UV stream, and it is not a duplication of the first stream,
// generated tangent/bitangent will be applied.
// (As it implies, cases may occur where all/none of the UV steams use the default TB.)
// Whether a UV stream can use the tangent/bitangent are encoded in DrawSrg.
float3 tangents[UvSetCount] = { IN.m_tangent.xyz, IN.m_tangent.xyz };
float3 bitangents[UvSetCount] = { IN.m_bitangent.xyz, IN.m_bitangent.xyz };

@ -180,18 +180,10 @@ PbrLightingOutput SkinPS_Common(VSOutput IN)
float3x3 uvMatrix = CreateIdentity3x3();
// ------- Tangents & Bitangets -------
// We support two UV streams, but only a single stream of tangent/bitangent.
// By default, the first UV stream is applied and the default tangent/bitangent are used.
// If anything uses the second UV stream, and it is not a duplication of the first stream,
// generated tangent/bitangent will be applied.
// (As it implies, cases may occur where all/none of the UV steams use the default TB.)
// Whether a UV stream can use the tangent/bitangent are encoded in DrawSrg.
float3 tangents[UvSetCount] = { IN.m_tangent.xyz, IN.m_tangent.xyz };
float3 bitangents[UvSetCount] = { IN.m_bitangent.xyz, IN.m_bitangent.xyz };
if ( (o_normal_useTexture && MaterialSrg::m_normalMapUvIndex != 0) ||
(o_detail_normal_useTexture && MaterialSrg::m_detail_allMapsUvIndex != 0))
if (o_normal_useTexture || o_detail_normal_useTexture)
{
PrepareGeneratedTangent(IN.m_normal, IN.m_worldPosition, isFrontFace, IN.m_uv, UvSetCount, tangents, bitangents);
}

@ -14,7 +14,6 @@
#include <Atom/Features/SrgSemantics.azsli>
#include <viewsrg.srgi>
#include <Atom/RPI/ShaderResourceGroups/DefaultDrawSrg.azsli>
#include "MaterialInputs/BaseColorInput.azsli"
#include "MaterialInputs/RoughnessInput.azsli"

@ -103,12 +103,6 @@ PSDepthOutput MainPS(VSDepthOutput IN, bool isFrontFace : SV_IsFrontFace)
if(ShouldHandleParallaxInDepthShaders())
{
// We support two UV streams, but only a single stream of tangent/bitangent.
// By default, the first UV stream is applied and the default tangent/bitangent are used.
// If anything uses the second UV stream, and it is not a duplication of the first stream,
// generated tangent/bitangent will be applied.
// (As it implies, cases may occur where all/none of the UV steams use the default TB.)
// Whether a UV stream can use the tangent/bitangent are encoded in DrawSrg.
float3 tangents[UvSetCount] = { IN.m_tangent.xyz, IN.m_tangent.xyz };
float3 bitangents[UvSetCount] = { IN.m_bitangent.xyz, IN.m_bitangent.xyz };

@ -135,23 +135,16 @@ PbrLightingOutput ForwardPassPS_Common(VSOutput IN, bool isFrontFace, out float
depthNDC = IN.m_position.z;
// ------- Tangents & Bitangets -------
// We support two UV streams, but only a single stream of tangent/bitangent.
// By default, the first UV stream is applied and the default tangent/bitangent are used.
// If anything uses the second UV stream, and it is not a duplication of the first stream,
// generated tangent/bitangent will be applied.
// (As it implies, cases may occur where all/none of the UV steams use the default TB.)
// Whether a UV stream can use the tangent/bitangent are encoded in DrawSrg.
float3 tangents[UvSetCount] = { IN.m_tangent.xyz, IN.m_tangent.xyz };
float3 bitangents[UvSetCount] = { IN.m_bitangent.xyz, IN.m_bitangent.xyz };
if ((o_parallax_feature_enabled && !o_enableSubsurfaceScattering && MaterialSrg::m_parallaxUvIndex != 0)
|| (o_layer1_o_normal_useTexture && MaterialSrg::m_layer1_m_normalMapUvIndex != 0)
|| (o_layer2_o_normal_useTexture && MaterialSrg::m_layer2_m_normalMapUvIndex != 0)
|| (o_layer3_o_normal_useTexture && MaterialSrg::m_layer3_m_normalMapUvIndex != 0)
|| (o_layer1_o_clearCoat_normal_useTexture && MaterialSrg::m_layer1_m_clearCoatNormalMapUvIndex != 0)
|| (o_layer2_o_clearCoat_normal_useTexture && MaterialSrg::m_layer2_m_clearCoatNormalMapUvIndex != 0)
|| (o_layer3_o_clearCoat_normal_useTexture && MaterialSrg::m_layer3_m_clearCoatNormalMapUvIndex != 0)
if ((o_parallax_feature_enabled && !o_enableSubsurfaceScattering)
|| o_layer1_o_normal_useTexture
|| o_layer2_o_normal_useTexture
|| o_layer3_o_normal_useTexture
|| o_layer1_o_clearCoat_normal_useTexture
|| o_layer2_o_clearCoat_normal_useTexture
|| o_layer3_o_clearCoat_normal_useTexture
)
{
PrepareGeneratedTangent(IN.m_normal, IN.m_worldPosition, isFrontFace, IN.m_uv, UvSetCount, tangents, bitangents);

@ -102,12 +102,6 @@ PSDepthOutput MainPS(VertexOutput IN, bool isFrontFace : SV_IsFrontFace)
if(ShouldHandleParallaxInDepthShaders())
{
// We support two UV streams, but only a single stream of tangent/bitangent.
// By default, the first UV stream is applied and the default tangent/bitangent are used.
// If anything uses the second UV stream, and it is not a duplication of the first stream,
// generated tangent/bitangent will be applied.
// (As it implies, cases may occur where all/none of the UV steams use the default TB.)
// Whether a UV stream can use the tangent/bitangent are encoded in DrawSrg.
float3 tangents[UvSetCount] = { IN.m_tangent.xyz, IN.m_tangent.xyz };
float3 bitangents[UvSetCount] = { IN.m_bitangent.xyz, IN.m_bitangent.xyz };

@ -78,12 +78,6 @@ PSDepthOutput MainPS(VSDepthOutput IN, bool isFrontFace : SV_IsFrontFace)
if(ShouldHandleParallaxInDepthShaders())
{
// We support two UV streams, but only a single stream of tangent/bitangent.
// By default, the first UV stream is applied and the default tangent/bitangent are used.
// If anything uses the second UV stream, and it is not a duplication of the first stream,
// generated tangent/bitangent will be applied.
// (As it implies, cases may occur where all/none of the UV steams use the default TB.)
// Whether a UV stream can use the tangent/bitangent are encoded in DrawSrg.
float3 tangents[UvSetCount] = { IN.m_tangent.xyz, IN.m_tangent.xyz };
float3 bitangents[UvSetCount] = { IN.m_bitangent.xyz, IN.m_bitangent.xyz };

@ -108,20 +108,10 @@ VSOutput StandardPbr_ForwardPassVS(VSInput IN)
PbrLightingOutput ForwardPassPS_Common(VSOutput IN, bool isFrontFace, out float depthNDC)
{
// ------- Tangents & Bitangets -------
// We support two UV streams, but only a single stream of tangent/bitangent.
// By default, the first UV stream is applied and the default tangent/bitangent are used.
// If anything uses the second UV stream, and it is not a duplication of the first stream,
// generated tangent/bitangent will be applied.
// (As it implies, cases may occur where all/none of the UV steams use the default TB.)
// Whether a UV stream can use the tangent/bitangent are encoded in DrawSrg.
float3 tangents[UvSetCount] = { IN.m_tangent.xyz, IN.m_tangent.xyz };
float3 bitangents[UvSetCount] = { IN.m_bitangent.xyz, IN.m_bitangent.xyz };
if ((o_parallax_feature_enabled && !o_enableSubsurfaceScattering && MaterialSrg::m_parallaxUvIndex != 0)
|| (o_normal_useTexture && MaterialSrg::m_normalMapUvIndex != 0)
|| (o_clearCoat_enabled && o_clearCoat_normal_useTexture && MaterialSrg::m_clearCoatNormalMapUvIndex != 0)
)
if ((o_parallax_feature_enabled && !o_enableSubsurfaceScattering) || o_normal_useTexture || (o_clearCoat_enabled && o_clearCoat_normal_useTexture))
{
PrepareGeneratedTangent(IN.m_normal, IN.m_worldPosition, isFrontFace, IN.m_uv, UvSetCount, tangents, bitangents);
}

@ -81,12 +81,6 @@ PSDepthOutput MainPS(VertexOutput IN, bool isFrontFace : SV_IsFrontFace)
{
static const float ShadowMapDepthBias = 0.000001;
// We support two UV streams, but only a single stream of tangent/bitangent.
// By default, the first UV stream is applied and the default tangent/bitangent are used.
// If anything uses the second UV stream, and it is not a duplication of the first stream,
// generated tangent/bitangent will be applied.
// (As it implies, cases may occur where all/none of the UV steams use the default TB.)
// Whether a UV stream can use the tangent/bitangent are encoded in DrawSrg.
float3 tangents[UvSetCount] = { IN.m_tangent.xyz, IN.m_tangent.xyz };
float3 bitangents[UvSetCount] = { IN.m_bitangent.xyz, IN.m_bitangent.xyz };
PrepareGeneratedTangent(IN.m_normal, IN.m_worldPosition, isFrontFace, IN.m_uv, UvSetCount, tangents, bitangents);

@ -728,8 +728,7 @@ namespace AZ
// retrieve vertex/index buffers
RPI::ModelLod::StreamBufferViewList streamBufferViews;
AZ::RPI::UvStreamTangentIndex dummyUvStreamTangentIndex;
[[maybe_unused]] bool result = modelLod->GetStreamsForMesh(inputStreamLayout, streamBufferViews, dummyUvStreamTangentIndex, shaderInputContract, meshIndex);
[[maybe_unused]] bool result = modelLod->GetStreamsForMesh(inputStreamLayout, streamBufferViews, nullptr, shaderInputContract, meshIndex);
AZ_Assert(result, "Failed to retrieve mesh stream buffer views");
// note that the element count is the size of the entire buffer, even though this mesh may only

@ -18,5 +18,5 @@ set(LY_BUILD_DEPENDENCIES
# [GFX-TODO] Add macro defintion in OpenImageIO 3rd party find cmake file
set(LY_COMPILE_DEFINITIONS
PRIVATE
OPEN_IMAGE_IO_ENABLED
#OPEN_IMAGE_IO_ENABLED
)

@ -17,12 +17,11 @@
ShaderResourceGroup DrawSrg : SRG_PerDraw
{
// This SRG is unique per draw packet
uint m_uvStreamTangentBitmask;
uint m_uvStreamTangentIndex;
uint GetTangentIndexAtUv(uint uvIndex)
uint GetTangentAtUv(uint uvIndex)
{
return m_uvStreamTangentIndex >> (4 * uvIndex)) & 0xF;
return (m_uvStreamTangentBitmask >> (4 * uvIndex)) & 0xF;
}
}

@ -190,13 +190,19 @@ void SurfaceGradientNormalMapping_GenerateTB(float2 uv, out float3 tangentWS, ou
}
//! Utility macro to nest SGBNM setup processes.
//! We support two UV streams, but only a single stream of tangent/bitangent.
//! By default, the first UV stream is applied and the default tangent/bitangent are used.
//! If anything uses the second UV stream, and it is not a duplication of the first stream,
//! generated tangent/bitangent will be applied.
//! (As it implies, cases may occur where all/none of the UV steams use the default TB.)
//! What tangent/bitangent a UV stream uses is encoded in MaterialDrawSrg.
#define PrepareGeneratedTangent(normal, worldPos, isFrontFace, uvSets, uvSetCount, outTangents, outBitangents) \
{ \
SurfaceGradientNormalMapping_Init(normal, worldPos, !isFrontFace); \
[unroll] \
for (uint i = 0; i < uvSetCount; ++i) \
{ \
if (DrawSrg::GetTangentIndexAtUv(i) == 0) \
if (DrawSrg::GetTangentAtUv(i) == 0) \
{ \
continue; \
} \

@ -98,7 +98,7 @@ namespace AZ
//! List of shader options set for this specific draw packet
typedef AZStd::pair<Name, RPI::ShaderOptionValue> ShaderOptionPair;
typedef AZStd::vector<ShaderOptionPair> ShaderOptionVector;
ShaderOptionVector m_shaderOptions;
ShaderOptionVector m_shaderOptions;
};
} // namespace RPI
} // namespace AZ

@ -34,7 +34,7 @@ namespace AZ
//! A map matches the UV shader inputs of this material to the custom UV names from the model.
using MaterialModelUvOverrideMap = AZStd::unordered_map<RHI::ShaderSemantic, AZ::Name>;
class UvStreamTangentIndex;
class UvStreamTangentBitmask;
class ModelLod final
: public Data::InstanceData
@ -110,6 +110,7 @@ namespace AZ
const MaterialUvNameMap& materialUvNameMap = {}) const;
//! Fills a InputStreamLayout and StreamBufferViewList for the set of streams that satisfy a ShaderInputContract.
// @param uvStreamTangentBitmaskOut a mask processed during UV stream matching, and later to determine which tangent/bitangent stream to use.
// @param contract the contract that defines the expected inputs for a shader, used to determine which streams are optional.
// @param meshIndex the index of the mesh to search in.
// @param materialModelUvMap a map of UV name overrides, which can be supplied to bind a specific mesh stream name to a different material shader stream name.
@ -117,7 +118,7 @@ namespace AZ
bool GetStreamsForMesh(
RHI::InputStreamLayout& layoutOut,
ModelLod::StreamBufferViewList& streamBufferViewsOut,
UvStreamTangentIndex& uvStreamTangentIndexOut,
UvStreamTangentBitmask* uvStreamTangentBitmaskOut,
const ShaderInputContract& contract,
size_t meshIndex,
const MaterialModelUvOverrideMap& materialModelUvMap = {},
@ -151,7 +152,7 @@ namespace AZ
const ShaderInputContract::StreamChannelInfo& contractStreamChannel,
StreamInfoList::const_iterator defaultUv,
StreamInfoList::const_iterator firstUv,
UvStreamTangentIndex& uvStreamTangentIndexOut) const;
UvStreamTangentBitmask* uvStreamTangentBitmaskOut) const;
// Meshes may share index/stream buffers in an LOD or they may have
// unique buffers. Often the asset builder will prioritize shared buffers
@ -175,35 +176,53 @@ namespace AZ
AZStd::mutex m_callbackMutex;
};
//! An encoded bitset for tangent used by a UV stream.
//! It will be passed through DefaultDrawSrg.
class UvStreamTangentIndex
//! An encoded bitmask for tangent used by UV streams.
//! It contains the information about number of UV streams and which tangent/bitangent is used by each UV stream.
//! See m_mask for more details.
//! The mask will be passed through per draw SRG.
class UvStreamTangentBitmask
{
public:
uint32_t GetFullFlag() const;
uint32_t GetNextAvailableUvIndex() const;
uint32_t GetTangentIndexAtUv(uint32_t uvIndex) const;
//! Get the full mask including number of UVs and tangent/bitangent assignment to each UV.
uint32_t GetFullTangentBitmask() const;
void ApplyTangentIndex(uint32_t tangentIndex);
//! Get number of UVs that have tangent/bitangent assigned.
uint32_t GetUvStreamCount() const;
//! Get tangent/bitangent assignment to the specified UV in the material.
//! @param uvIndex the index of the UV from the material, in default order as in the shader code.
uint32_t GetTangentAtUv(uint32_t uvIndex) const;
//! Apply the tangent to the next UV, whose index is the same as GetUvStreamCount.
//! @param tangent the tangent/bitangent to be assigned. Ranged in [0, 0xF)
//! It comes from the model in order, e.g. 0 means the first available tangent stream from the model.
//! Specially, value 0xF(=UnassignedTangent) means generated tangent/bitangent will be used in shader.
//! If ranged out of definition, unassigned tangent will be applied.
void ApplyTangent(uint32_t tangent);
//! Reset the bitmask to clear state.
void Reset();
// The flag indicating generated tangent/bitangent will be used.
static constexpr uint32_t UnassignedTangentIndex = 0b1111u;
//! The bit mask indicating generated tangent/bitangent will be used.
static constexpr uint32_t UnassignedTangent = 0b1111u;
//! The variable name defined in the SRG shader code.
static constexpr const char* SrgName = "m_uvStreamTangentBitmask";
private:
// Flag composition:
// The next available slot index (highest 4 bits) + tangent index (4 bits each) * 7
// e.g. 0x200000F0 means there are 2 UV streams,
// the first UV stream uses 0th tangent stream,
// the second UV stream uses the generated tangent stream (0xF).
uint32_t m_flag = 0;
static constexpr uint32_t BitsPerTangentIndex = 4;
//! Mask composition:
//! The number of UV slots (highest 4 bits) + tangent mask (4 bits each) * 7
//! e.g. 0x200000F0 means there are 2 UV streams,
//! the first UV stream uses 0th tangent stream (0x0),
//! the second UV stream uses the generated tangent stream (0xF).
uint32_t m_mask = 0;
//! Bit size in the mask composition.
static constexpr uint32_t BitsPerTangent = 4;
static constexpr uint32_t BitsForUvIndex = 4;
public:
static constexpr uint32_t MaxTangents = (sizeof(m_flag) * CHAR_BIT - BitsForUvIndex) / BitsPerTangentIndex;
//! Max UV slots available in this bit mask.
static constexpr uint32_t MaxUvSlots = (sizeof(m_mask) * CHAR_BIT - BitsForUvIndex) / BitsPerTangent;
};
} // namespace RPI
} // namespace AZ

@ -209,12 +209,12 @@ namespace AZ
streamBufferViewsPerShader.push_back();
auto& streamBufferViews = streamBufferViewsPerShader.back();
UvStreamTangentIndex uvStreamTangentIndex;
UvStreamTangentBitmask uvStreamTangentBitmask;
if (!m_modelLod->GetStreamsForMesh(
pipelineStateDescriptor.m_inputStreamLayout,
streamBufferViews,
uvStreamTangentIndex,
&uvStreamTangentBitmask,
variant.GetInputContract(),
m_modelLodMeshIndex,
m_materialModelUvMap,
@ -235,9 +235,16 @@ namespace AZ
drawSrg->SetShaderVariantKeyFallbackValue(shaderOptions.GetShaderVariantKeyFallbackValue());
}
RHI::ShaderInputNameIndex shaderUvStreamTangentIndex = "m_uvStreamTangentIndex";
// Pass UvStreamTangentBitmask to the shader if the draw SRG has it.
{
AZ::Name shaderUvStreamTangentBitmask = AZ::Name(UvStreamTangentBitmask::SrgName);
auto index = drawSrg->FindShaderInputConstantIndex(shaderUvStreamTangentBitmask);
drawSrg->SetConstant(shaderUvStreamTangentIndex, uvStreamTangentIndex.GetFullFlag());
if (index.IsValid())
{
drawSrg->SetConstant(index, uvStreamTangentBitmask.GetFullTangentBitmask());
}
}
drawSrg->Compile();
}

@ -173,7 +173,7 @@ namespace AZ
const ShaderInputContract::StreamChannelInfo& contractStreamChannel,
StreamInfoList::const_iterator defaultUv,
StreamInfoList::const_iterator firstUv,
UvStreamTangentIndex& uvStreamTangentIndexOut) const
UvStreamTangentBitmask* uvStreamTangentBitmaskOut) const
{
const Mesh& mesh = m_meshes[meshIndex];
auto iter = mesh.m_streamInfo.end();
@ -197,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);
@ -237,14 +237,14 @@ namespace AZ
});
}
if (iter == mesh.m_streamInfo.end() && IsUv)
if (iter == mesh.m_streamInfo.end() && isUv)
{
iter = defaultUv;
}
if (IsUv)
if (isUv && uvStreamTangentBitmaskOut)
{
uvStreamTangentIndexOut.ApplyTangentIndex(iter == firstUv ? 0 : UvStreamTangentIndex::UnassignedTangentIndex);
uvStreamTangentBitmaskOut->ApplyTangent(iter == firstUv ? 0 : UvStreamTangentBitmask::UnassignedTangent);
}
return iter;
@ -253,7 +253,7 @@ namespace AZ
bool ModelLod::GetStreamsForMesh(
RHI::InputStreamLayout& layoutOut,
StreamBufferViewList& streamBufferViewsOut,
UvStreamTangentIndex& uvStreamTangentIndexOut,
UvStreamTangentBitmask* uvStreamTangentBitmaskOut,
const ShaderInputContract& contract,
size_t meshIndex,
const MaterialModelUvOverrideMap& materialModelUvMap,
@ -272,11 +272,14 @@ namespace AZ
// 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);
uvStreamTangentIndexOut.Reset();
if (uvStreamTangentBitmaskOut)
{
uvStreamTangentBitmaskOut->Reset();
}
for (auto& contractStreamChannel : contract.m_streamChannels)
{
auto iter = FindMatchingStream(meshIndex, materialModelUvMap, materialUvNameMap, contractStreamChannel, defaultUv, firstUv, uvStreamTangentIndexOut);
auto iter = FindMatchingStream(meshIndex, materialModelUvMap, materialUvNameMap, contractStreamChannel, defaultUv, firstUv, uvStreamTangentBitmaskOut);
if (iter == mesh.m_streamInfo.end())
{
@ -363,7 +366,6 @@ namespace AZ
auto defaultUv = FindDefaultUvStream(meshIndex, materialUvNameMap);
auto firstUv = FindFirstUvStreamFromMesh(meshIndex);
UvStreamTangentIndex dummyUvStreamTangentIndex;
for (auto& contractStreamChannel : contract.m_streamChannels)
{
@ -374,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, firstUv, dummyUvStreamTangentIndex);
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);
@ -438,55 +440,55 @@ namespace AZ
return static_cast<uint32_t>(m_buffers.size() - 1);
}
uint32_t UvStreamTangentIndex::GetFullFlag() const
uint32_t UvStreamTangentBitmask::GetFullTangentBitmask() const
{
return m_flag;
return m_mask;
}
uint32_t UvStreamTangentIndex::GetNextAvailableUvIndex() const
uint32_t UvStreamTangentBitmask::GetUvStreamCount() const
{
return m_flag >> (sizeof(m_flag) * CHAR_BIT - BitsForUvIndex);
return m_mask >> (sizeof(m_mask) * CHAR_BIT - BitsForUvIndex);
}
uint32_t UvStreamTangentIndex::GetTangentIndexAtUv(uint32_t uvIndex) const
uint32_t UvStreamTangentBitmask::GetTangentAtUv(uint32_t uvIndex) const
{
return (m_flag >> (BitsPerTangentIndex * uvIndex)) & 0b1111u;
return (m_mask >> (BitsPerTangent * uvIndex)) & 0b1111u;
}
void UvStreamTangentIndex::ApplyTangentIndex(uint32_t tangentIndex)
void UvStreamTangentBitmask::ApplyTangent(uint32_t tangentIndex)
{
uint32_t currentSlot = GetNextAvailableUvIndex();
if (currentSlot >= MaxTangents)
uint32_t currentSlot = GetUvStreamCount();
if (currentSlot >= MaxUvSlots)
{
AZ_Error("UV Stream", false, "Reaching the max of avaiblable stream slots.");
return;
}
if (tangentIndex > UnassignedTangentIndex)
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.",
BitsPerTangentIndex);
tangentIndex = UnassignedTangentIndex;
BitsPerTangent);
tangentIndex = UnassignedTangent;
}
uint32_t mask = 0b1111u << (BitsPerTangentIndex * currentSlot);
mask = ~mask;
uint32_t clearMask = 0b1111u << (BitsPerTangent * currentSlot);
clearMask = ~clearMask;
// Clear the writing bits in case
m_flag &= mask;
m_mask &= clearMask;
// Write the bits to the slot
m_flag |= (tangentIndex << (BitsPerTangentIndex * currentSlot));
m_mask |= (tangentIndex << (BitsPerTangent * currentSlot));
// Increase the index
m_flag += (1u << (sizeof(m_flag) * CHAR_BIT - BitsForUvIndex));
m_mask += (1u << (sizeof(m_mask) * CHAR_BIT - BitsForUvIndex));
}
void UvStreamTangentIndex::Reset()
void UvStreamTangentBitmask::Reset()
{
m_flag = 0;
m_mask = 0;
}
} // namespace RPI
} // namespace AZ

@ -920,29 +920,39 @@ namespace UnitTest
TEST_F(ModelTests, UvStream)
{
AZ::RPI::UvStreamTangentIndex uvStreamTangentIndex;
EXPECT_EQ(uvStreamTangentIndex.GetFullFlag(), 0u);
uvStreamTangentIndex.ApplyTangentIndex(1u);
EXPECT_EQ(uvStreamTangentIndex.GetTangentIndexAtUv(0u), 1u);
EXPECT_EQ(uvStreamTangentIndex.GetNextAvailableUvIndex(), 1u);
uvStreamTangentIndex.ApplyTangentIndex(5u);
EXPECT_EQ(uvStreamTangentIndex.GetTangentIndexAtUv(1u), 5u);
EXPECT_EQ(uvStreamTangentIndex.GetNextAvailableUvIndex(), 2u);
uvStreamTangentIndex.ApplyTangentIndex(100u);
EXPECT_EQ(uvStreamTangentIndex.GetTangentIndexAtUv(2u), AZ::RPI::UvStreamTangentIndex::UnassignedTangentIndex);
EXPECT_EQ(uvStreamTangentIndex.GetNextAvailableUvIndex(), 3u);
for (uint32_t i = 3; i < AZ::RPI::UvStreamTangentIndex::MaxTangents; ++i)
AZ::RPI::UvStreamTangentBitmask uvStreamTangentBitmask;
EXPECT_EQ(uvStreamTangentBitmask.GetFullTangentBitmask(), 0u);
uvStreamTangentBitmask.ApplyTangent(1u);
EXPECT_EQ(uvStreamTangentBitmask.GetTangentAtUv(0u), 1u);
EXPECT_EQ(uvStreamTangentBitmask.GetFullTangentBitmask(), 0x10000001);
EXPECT_EQ(uvStreamTangentBitmask.GetUvStreamCount(), 1u);
uvStreamTangentBitmask.ApplyTangent(5u);
EXPECT_EQ(uvStreamTangentBitmask.GetTangentAtUv(0u), 1u);
EXPECT_EQ(uvStreamTangentBitmask.GetTangentAtUv(1u), 5u);
EXPECT_EQ(uvStreamTangentBitmask.GetFullTangentBitmask(), 0x20000051);
EXPECT_EQ(uvStreamTangentBitmask.GetUvStreamCount(), 2u);
uvStreamTangentBitmask.ApplyTangent(100u);
EXPECT_EQ(uvStreamTangentBitmask.GetTangentAtUv(0u), 1u);
EXPECT_EQ(uvStreamTangentBitmask.GetTangentAtUv(1u), 5u);
EXPECT_EQ(uvStreamTangentBitmask.GetTangentAtUv(2u), AZ::RPI::UvStreamTangentBitmask::UnassignedTangent);
EXPECT_EQ(uvStreamTangentBitmask.GetFullTangentBitmask(), 0x30000F51);
EXPECT_EQ(uvStreamTangentBitmask.GetUvStreamCount(), 3u);
for (uint32_t i = 3; i < AZ::RPI::UvStreamTangentBitmask::MaxUvSlots; ++i)
{
uvStreamTangentIndex.ApplyTangentIndex(0u);
uvStreamTangentBitmask.ApplyTangent(0u);
}
EXPECT_EQ(uvStreamTangentBitmask.GetFullTangentBitmask(), 0x70000F51);
AZ_TEST_START_TRACE_SUPPRESSION;
uvStreamTangentIndex.ApplyTangentIndex(0u);
uvStreamTangentBitmask.ApplyTangent(0u);
AZ_TEST_STOP_TRACE_SUPPRESSION(1);
EXPECT_EQ(uvStreamTangentBitmask.GetFullTangentBitmask(), 0x70000F51);
}
// This class creates a Model with one LOD, whose mesh contains 2 planes. Plane 1 is in the XY plane at Z=-0.5, and

Loading…
Cancel
Save