diff --git a/Gems/Atom/Feature/Common/Assets/ShaderLib/Atom/Features/PBR/Decals.azsli b/Gems/Atom/Feature/Common/Assets/ShaderLib/Atom/Features/PBR/Decals.azsli index 1bd8e0b9a5..5e7088617b 100644 --- a/Gems/Atom/Feature/Common/Assets/ShaderLib/Atom/Features/PBR/Decals.azsli +++ b/Gems/Atom/Feature/Common/Assets/ShaderLib/Atom/Features/PBR/Decals.azsli @@ -16,6 +16,7 @@ #include #include #include +#include void ApplyDecal(uint currDecalIndex, inout Surface surface); @@ -47,9 +48,10 @@ void ApplyDecal(uint currDecalIndex, inout Surface surface) ViewSrg::Decal decal = ViewSrg::m_decals[currDecalIndex]; float3x3 decalRot = MatrixFromQuaternion(decal.m_quaternion); - + decalRot = transpose(decalRot); + float3 localPos = surface.position - decal.m_position; - localPos = mul(localPos, decalRot); + localPos = mul(decalRot, localPos); float3 decalUVW = localPos * rcp(decal.m_halfSize); if(decalUVW.x >= -1.0f && decalUVW.x <= 1.0f && @@ -63,30 +65,39 @@ void ApplyDecal(uint currDecalIndex, inout Surface surface) decalUVW.y *= -1; float3 decalUV = float3(decalUVW.xy * 0.5f + 0.5f, textureIndex); - + float3 decalSample; float4 baseMap = 0; + float2 normalMap = 0; switch(textureArrayIndex) { case 0: - baseMap = ViewSrg::m_decalTextureArray0.Sample(PassSrg::LinearSampler, decalUV); + baseMap = ViewSrg::m_decalTextureArrayDiffuse0.Sample(PassSrg::LinearSampler, decalUV); + normalMap = ViewSrg::m_decalTextureArrayNormalMaps0.Sample(PassSrg::LinearSampler, decalUV); break; case 1: - baseMap = ViewSrg::m_decalTextureArray1.Sample(PassSrg::LinearSampler, decalUV); + baseMap = ViewSrg::m_decalTextureArrayDiffuse1.Sample(PassSrg::LinearSampler, decalUV); + normalMap = ViewSrg::m_decalTextureArrayNormalMaps1.Sample(PassSrg::LinearSampler, decalUV); break; case 2: - baseMap = ViewSrg::m_decalTextureArray2.Sample(PassSrg::LinearSampler, decalUV); + baseMap = ViewSrg::m_decalTextureArrayDiffuse2.Sample(PassSrg::LinearSampler, decalUV); + normalMap = ViewSrg::m_decalTextureArrayNormalMaps2.Sample(PassSrg::LinearSampler, decalUV); break; case 3: - baseMap = ViewSrg::m_decalTextureArray3.Sample(PassSrg::LinearSampler, decalUV); + baseMap = ViewSrg::m_decalTextureArrayDiffuse3.Sample(PassSrg::LinearSampler, decalUV); + normalMap = ViewSrg::m_decalTextureArrayNormalMaps3.Sample(PassSrg::LinearSampler, decalUV); break; case 4: - baseMap = ViewSrg::m_decalTextureArray4.Sample(PassSrg::LinearSampler, decalUV); - break; + baseMap = ViewSrg::m_decalTextureArrayDiffuse4.Sample(PassSrg::LinearSampler, decalUV); + normalMap = ViewSrg::m_decalTextureArrayNormalMaps4.Sample(PassSrg::LinearSampler, decalUV); + break; } float opacity = baseMap.a * decal.m_opacity * GetDecalAttenuation(surface.normal, decalRot[2], decal.m_angleAttenuation); - surface.albedo = lerp(surface.albedo, baseMap.rgb, opacity); + surface.albedo = lerp(surface.albedo, baseMap.rgb, opacity); + + float3 normalMapWS = GetWorldSpaceNormal(normalMap, decalRot[2], decalRot[0], decalRot[1], 1.0f); + surface.normal = normalize(lerp(surface.normal, normalMapWS, opacity)); } } diff --git a/Gems/Atom/Feature/Common/Assets/ShaderResourceGroups/Decals/ViewSrg.azsli b/Gems/Atom/Feature/Common/Assets/ShaderResourceGroups/Decals/ViewSrg.azsli index 16b23432e1..260614b0f7 100644 --- a/Gems/Atom/Feature/Common/Assets/ShaderResourceGroups/Decals/ViewSrg.azsli +++ b/Gems/Atom/Feature/Common/Assets/ShaderResourceGroups/Decals/ViewSrg.azsli @@ -31,12 +31,18 @@ partial ShaderResourceGroup ViewSrg // e.g. m_decalTextureArray0 might store 24 textures @128x128, // m_decalTextureArray1 might store 16 * 256x256 // and m_decalTextureArray2 might store 4 @ 512x512 - - Texture2DArray m_decalTextureArray0; - Texture2DArray m_decalTextureArray1; - Texture2DArray m_decalTextureArray2; - Texture2DArray m_decalTextureArray3; - Texture2DArray m_decalTextureArray4; + // This must match the variable NumTextureArrays in DecalTextureArrayFeatureProcessor.h + Texture2DArray m_decalTextureArrayDiffuse0; + Texture2DArray m_decalTextureArrayDiffuse1; + Texture2DArray m_decalTextureArrayDiffuse2; + Texture2DArray m_decalTextureArrayDiffuse3; + Texture2DArray m_decalTextureArrayDiffuse4; + + Texture2DArray m_decalTextureArrayNormalMaps0; + Texture2DArray m_decalTextureArrayNormalMaps1; + Texture2DArray m_decalTextureArrayNormalMaps2; + Texture2DArray m_decalTextureArrayNormalMaps3; + Texture2DArray m_decalTextureArrayNormalMaps4; uint m_decalCount; } diff --git a/Gems/Atom/Feature/Common/Code/Source/Decals/DecalTextureArray.cpp b/Gems/Atom/Feature/Common/Code/Source/Decals/DecalTextureArray.cpp index ebdc884ecf..87ac0a9679 100644 --- a/Gems/Atom/Feature/Common/Code/Source/Decals/DecalTextureArray.cpp +++ b/Gems/Atom/Feature/Common/Code/Source/Decals/DecalTextureArray.cpp @@ -5,7 +5,6 @@ * SPDX-License-Identifier: Apache-2.0 OR MIT * */ - #include "DecalTextureArray.h" #include #include @@ -24,7 +23,16 @@ namespace AZ { namespace { - static const char* BaseColorTextureMapName = "baseColor.textureMap"; + static AZ::Name GetMapName(const DecalMapType mapType) + { + // Using local static to avoid cost of creating AZ::Name. Also so that this can be called from other static functions + static AZStd::array mapNames = + { + AZ::Name("baseColor.textureMap"), + AZ::Name("normal.textureMap") + }; + return mapNames[mapType]; + } static AZ::Data::AssetId GetImagePoolId() { @@ -40,6 +48,7 @@ namespace AZ return asset; } + // Extract exactly which texture asset we need to load from the given material and map type (diffuse, normal, etc). static AZ::Data::Asset GetStreamingImageAsset(const AZ::RPI::MaterialAsset& materialAsset, const AZ::Name& propertyName) { if (!materialAsset.IsReady()) @@ -78,11 +87,6 @@ namespace AZ const AZ::RPI::MaterialAsset* materialAsset = materialAssetData.GetAs(); return GetStreamingImageAsset(*materialAsset, propertyName); } - - AZ::Data::Asset GetBaseColorImageAsset(const AZ::Data::Asset materialAssetData) - { - return GetStreamingImageAsset(materialAssetData, AZ::Name(BaseColorTextureMapName)); - } } int DecalTextureArray::FindMaterial(const AZ::Data::AssetId materialAssetId) const @@ -103,7 +107,7 @@ namespace AZ { AZ_Error("DecalTextureArray", FindMaterial(materialAssetId) == -1, "Adding material when it already exists in the array"); // Invalidate the existing texture array, as we need to repack it taking into account the new material. - m_textureArrayPacked = nullptr; + AZStd::fill(m_textureArrayPacked.begin(), m_textureArrayPacked.end(), nullptr); MaterialData materialData; materialData.m_materialAssetId = materialAssetId; @@ -122,42 +126,42 @@ namespace AZ return m_materials[index].m_materialAssetId; } - RHI::Size DecalTextureArray::GetImageDimensions() const + RHI::Size DecalTextureArray::GetImageDimensions(const DecalMapType mapType) const { AZ_Assert(m_materials.size() > 0, "GetImageDimensions() cannot be called until at least one material has been added"); const int iter = m_materials.begin(); // All textures in a texture array must have the same size, so just pick the first const MaterialData& firstMaterial = m_materials[iter]; - const auto& baseColorAsset = GetBaseColorImageAsset(firstMaterial.m_materialAssetData); + const auto& baseColorAsset = GetStreamingImageAsset(firstMaterial.m_materialAssetData, GetMapName(mapType)); return baseColorAsset->GetImageDescriptor().m_size; } - const AZ::Data::Instance& DecalTextureArray::GetPackedTexture() const + const AZ::Data::Instance& DecalTextureArray::GetPackedTexture(const DecalMapType mapType) const { - return m_textureArrayPacked; + return m_textureArrayPacked[mapType]; } bool DecalTextureArray::IsValidDecalMaterial(const AZ::RPI::MaterialAsset& materialAsset) { - return GetStreamingImageAsset(materialAsset, AZ::Name(BaseColorTextureMapName)).IsReady(); + return GetStreamingImageAsset(materialAsset, GetMapName(DecalMapType_Diffuse)).IsReady(); } - AZ::Data::Asset DecalTextureArray::BuildPackedMipChainAsset(const size_t numTexturesToCreate) + AZ::Data::Asset DecalTextureArray::BuildPackedMipChainAsset(const DecalMapType mapType, const size_t numTexturesToCreate) { RPI::ImageMipChainAssetCreator assetCreator; - const uint32_t mipLevels = GetNumMipLevels(); + const uint32_t mipLevels = GetNumMipLevels(mapType); - assetCreator.Begin(Data::AssetId(AZ::Uuid::CreateRandom()), static_cast(mipLevels), aznumeric_cast(numTexturesToCreate)); + assetCreator.Begin(Data::AssetId(AZ::Uuid::CreateRandom()), aznumeric_cast(mipLevels), aznumeric_cast(numTexturesToCreate)); for (uint32_t mipLevel = 0; mipLevel < mipLevels; ++mipLevel) { - const auto& layout = GetLayout(mipLevel); + const auto& layout = GetLayout(mapType, mipLevel); assetCreator.BeginMip(layout); for (int i = 0; i < m_materials.array_size(); ++i) { - const auto rawData = GetRawImageData(i, mipLevel); - assetCreator.AddSubImage(rawData.data(), rawData.size()); + const auto imageData = GetRawImageData(GetMapName(mapType), i, mipLevel); + assetCreator.AddSubImage(imageData.data(), imageData.size()); } assetCreator.EndMip(); @@ -169,10 +173,12 @@ namespace AZ return AZStd::move(asset); } - RHI::ImageDescriptor DecalTextureArray::CreatePackedImageDescriptor(const uint16_t arraySize, const uint16_t mipLevels) const + RHI::ImageDescriptor DecalTextureArray::CreatePackedImageDescriptor( + const DecalMapType mapType, const uint16_t arraySize, const uint16_t mipLevels) const { - const RHI::Size imageDimensions = GetImageDimensions(); - RHI::ImageDescriptor imageDescriptor = RHI::ImageDescriptor::Create2DArray(RHI::ImageBindFlags::ShaderRead, imageDimensions.m_width, imageDimensions.m_height, arraySize, GetFormat()); + const RHI::Size imageDimensions = GetImageDimensions(mapType); + RHI::ImageDescriptor imageDescriptor = RHI::ImageDescriptor::Create2DArray( + RHI::ImageBindFlags::ShaderRead, imageDimensions.m_width, imageDimensions.m_height, arraySize, GetFormat(mapType)); imageDescriptor.m_mipLevels = mipLevels; return imageDescriptor; } @@ -189,21 +195,34 @@ namespace AZ } const size_t numTexturesToCreate = m_materials.array_size(); - const auto mipChainAsset = BuildPackedMipChainAsset(numTexturesToCreate); - RHI::ImageViewDescriptor imageViewDescriptor; - imageViewDescriptor.m_isArray = true; - - RPI::StreamingImageAssetCreator assetCreator; - assetCreator.Begin(Data::AssetId(Uuid::CreateRandom())); - assetCreator.SetPoolAssetId(GetImagePoolId()); - assetCreator.SetFlags(RPI::StreamingImageFlags::None); - assetCreator.SetImageDescriptor(CreatePackedImageDescriptor(aznumeric_cast(numTexturesToCreate), GetNumMipLevels())); - assetCreator.SetImageViewDescriptor(imageViewDescriptor); - assetCreator.AddMipChainAsset(*mipChainAsset); - Data::Asset packedAsset; - const bool createdOk = assetCreator.End(packedAsset); - AZ_Error("TextureArrayData", createdOk, "Pack() call failed."); - m_textureArrayPacked = createdOk ? RPI::StreamingImage::FindOrCreate(packedAsset) : nullptr; + for (int i = 0; i < DecalMapType_Num; ++i) + { + const DecalMapType mapType = aznumeric_cast(i); + if (!AreAllTextureMapsPresent(mapType)) + { + AZ_Warning("DecalTextureArray", true, "Missing decal texture maps for %s. Please make sure all maps of this type are present.\n", GetMapName(mapType).GetCStr()); + m_textureArrayPacked[i] = nullptr; + continue; + } + + const auto mipChainAsset = BuildPackedMipChainAsset(mapType, numTexturesToCreate); + RHI::ImageViewDescriptor imageViewDescriptor; + imageViewDescriptor.m_isArray = true; + + RPI::StreamingImageAssetCreator assetCreator; + assetCreator.Begin(Data::AssetId(Uuid::CreateRandom())); + assetCreator.SetPoolAssetId(GetImagePoolId()); + assetCreator.SetFlags(RPI::StreamingImageFlags::None); + assetCreator.SetImageDescriptor( + CreatePackedImageDescriptor(mapType, aznumeric_cast(numTexturesToCreate), GetNumMipLevels(mapType))); + assetCreator.SetImageViewDescriptor(imageViewDescriptor); + assetCreator.AddMipChainAsset(*mipChainAsset); + Data::Asset packedAsset; + const bool createdOk = assetCreator.End(packedAsset); + AZ_Error("TextureArrayData", createdOk, "Pack() call failed."); + m_textureArrayPacked[i] = createdOk ? RPI::StreamingImage::FindOrCreate(packedAsset) : nullptr; + + } // Free unused memory ClearAssets(); @@ -225,29 +244,30 @@ namespace AZ } } - uint16_t DecalTextureArray::GetNumMipLevels() const + uint16_t DecalTextureArray::GetNumMipLevels(const DecalMapType mapType) const { AZ_Assert(m_materials.size() > 0, "GetNumMipLevels() cannot be called until at least one material has been added"); // All decals in a texture array must have the same number of mips, so just pick the first const int iter = m_materials.begin(); const MaterialData& firstMaterial = m_materials[iter]; - const auto& baseColorAsset = GetBaseColorImageAsset(firstMaterial.m_materialAssetData); - return baseColorAsset->GetImageDescriptor().m_mipLevels; + const auto& imageAsset = GetStreamingImageAsset(firstMaterial.m_materialAssetData, GetMapName(mapType)); + return imageAsset->GetImageDescriptor().m_mipLevels; } - RHI::ImageSubresourceLayout DecalTextureArray::GetLayout(int mip) const + RHI::ImageSubresourceLayout DecalTextureArray::GetLayout(const DecalMapType mapType, int mip) const { AZ_Assert(m_materials.size() > 0, "GetLayout() cannot be called unless at least one material has been added"); const int iter = m_materials.begin(); - const auto& descriptor = GetBaseColorImageAsset(m_materials[iter].m_materialAssetData)->GetImageDescriptor(); + const auto& descriptor = + GetStreamingImageAsset(m_materials[iter].m_materialAssetData, GetMapName(mapType))->GetImageDescriptor(); RHI::Size mipSize = descriptor.m_size; mipSize.m_width >>= mip; mipSize.m_height >>= mip; return AZ::RHI::GetImageSubresourceLayout(mipSize, descriptor.m_format); } - AZStd::array_view DecalTextureArray::GetRawImageData(int arrayLevel, const int mip) const + AZStd::array_view DecalTextureArray::GetRawImageData(const AZ::Name& mapName, int arrayLevel, const int mip) const { // We always want to provide valid data to the AssetCreator for each texture. // If this spot in the array is empty, just provide some random image as filler. @@ -257,17 +277,20 @@ namespace AZ { arrayLevel = m_materials.begin(); } - - const auto image = GetBaseColorImageAsset(m_materials[arrayLevel].m_materialAssetData); + const auto image = GetStreamingImageAsset(m_materials[arrayLevel].m_materialAssetData, mapName); + if (!image) + { + return {}; + } const auto srcData = image->GetSubImageData(mip, 0); return srcData; } - AZ::RHI::Format DecalTextureArray::GetFormat() const + AZ::RHI::Format DecalTextureArray::GetFormat(const DecalMapType mapType) const { AZ_Assert(m_materials.size() > 0, "GetFormat() can only be called after at least one material has been added."); const int iter = m_materials.begin(); - const auto& baseColorAsset = GetBaseColorImageAsset(m_materials[iter].m_materialAssetData); + const auto& baseColorAsset = GetStreamingImageAsset(m_materials[iter].m_materialAssetData, GetMapName(mapType)); return baseColorAsset->GetImageDescriptor().m_format; } @@ -290,6 +313,25 @@ namespace AZ return id.IsValid() && materialData.m_materialAssetData.IsReady(); } + bool DecalTextureArray::AreAllTextureMapsPresent(const DecalMapType mapType) const + { + int iter = m_materials.begin(); + while (iter != -1) + { + if (!IsTextureMapPresentInMaterial(m_materials[iter], mapType)) + { + return false; + } + iter = m_materials.next(iter); + } + return true; + } + + bool DecalTextureArray::IsTextureMapPresentInMaterial(const MaterialData& materialData, const DecalMapType mapType) const + { + return GetStreamingImageAsset(materialData.m_materialAssetData, GetMapName(mapType)).IsReady(); + } + void DecalTextureArray::ClearAssets() { int iter = m_materials.begin(); @@ -330,7 +372,8 @@ namespace AZ if (m_materials.size() == 0) return false; - return m_textureArrayPacked == nullptr; + // We pack all diffuse/normal/etc in one go, so just check to see if the diffusemaps need packing + return m_textureArrayPacked[DecalMapType_Diffuse] == nullptr; } } diff --git a/Gems/Atom/Feature/Common/Code/Source/Decals/DecalTextureArray.h b/Gems/Atom/Feature/Common/Code/Source/Decals/DecalTextureArray.h index eb0f825e08..97bd8b9cbe 100644 --- a/Gems/Atom/Feature/Common/Code/Source/Decals/DecalTextureArray.h +++ b/Gems/Atom/Feature/Common/Code/Source/Decals/DecalTextureArray.h @@ -28,8 +28,18 @@ namespace AZ namespace Render { + enum DecalMapType : uint32_t + { + DecalMapType_Diffuse, + DecalMapType_Normal, + DecalMapType_Num + }; + //! Helper class used by DecalTextureArrayFeatureProcessor. //! Given a set of images (all with the same dimensions and format), it can pack them together into a single textureArray that can be sent to the GPU. + //! Note that once textures are packed, this class will release any material references + //! This might free memory if nothing else is holding onto them + //! The class DOES keep note of which material asset ids were added, so it can load them again if necessary if the whole thing needs to be repacked class DecalTextureArray : public Data::AssetBus::MultiHandler { public: @@ -40,8 +50,12 @@ namespace AZ AZ::Data::AssetId GetMaterialAssetId(const int index) const; + // Packs all the added materials into one texture array per DecalMapType. void Pack(); - const Data::Instance& GetPackedTexture() const; + + // Note that we pack each type into a separate texture array. This is because formats are + // often different (BC5 for normals, BC7 for diffuse, etc) + const Data::Instance& GetPackedTexture(const DecalMapType mapType) const; static bool IsValidDecalMaterial(const RPI::MaterialAsset& materialAsset); @@ -56,22 +70,25 @@ namespace AZ void OnAssetReady(Data::Asset asset) override; + // Returns the index of the material in the m_materials container. -1 if not present. int FindMaterial(const AZ::Data::AssetId materialAssetId) const; // packs the contents of the source images into a texture array readable by the GPU and returns it - AZ::Data::Asset BuildPackedMipChainAsset(const size_t numTexturesToCreate); - - RHI::ImageDescriptor CreatePackedImageDescriptor(const uint16_t arraySize, const uint16_t mipLevels) const; + AZ::Data::Asset BuildPackedMipChainAsset(const DecalMapType mapType, const size_t numTexturesToCreate); + RHI::ImageDescriptor CreatePackedImageDescriptor(const DecalMapType mapType, const uint16_t arraySize, const uint16_t mipLevels) const; - uint16_t GetNumMipLevels() const; - RHI::Size GetImageDimensions() const; - RHI::Format GetFormat() const; - RHI::ImageSubresourceLayout GetLayout(int mip) const; - AZStd::array_view GetRawImageData(int arrayLevel, int mip) const; + uint16_t GetNumMipLevels(const DecalMapType mapType) const; + RHI::Size GetImageDimensions(const DecalMapType mapType) const; + RHI::Format GetFormat(const DecalMapType mapType) const; + RHI::ImageSubresourceLayout GetLayout(const DecalMapType mapType, int mip) const; + AZStd::array_view GetRawImageData(const AZ::Name& mapName, int arrayLevel, int mip) const; bool AreAllAssetsReady() const; bool IsAssetReady(const MaterialData& materialData) const; + bool AreAllTextureMapsPresent(const DecalMapType mapType) const; + bool IsTextureMapPresentInMaterial(const MaterialData& materialData, const DecalMapType mapType) const; + void ClearAssets(); void ClearAsset(MaterialData& materialData); @@ -81,7 +98,7 @@ namespace AZ bool NeedsPacking() const; IndexableList m_materials; - Data::Instance m_textureArrayPacked; + AZStd::array, DecalMapType_Num> m_textureArrayPacked; AZStd::unordered_set m_assetsCurrentlyLoading; }; diff --git a/Gems/Atom/Feature/Common/Code/Source/Decals/DecalTextureArrayFeatureProcessor.cpp b/Gems/Atom/Feature/Common/Code/Source/Decals/DecalTextureArrayFeatureProcessor.cpp index c0b8f3315a..e5bf0bd9fa 100644 --- a/Gems/Atom/Feature/Common/Code/Source/Decals/DecalTextureArrayFeatureProcessor.cpp +++ b/Gems/Atom/Feature/Common/Code/Source/Decals/DecalTextureArrayFeatureProcessor.cpp @@ -322,13 +322,30 @@ namespace AZ void DecalTextureArrayFeatureProcessor::CacheShaderIndices() { - for (int i = 0; i < NumTextureArrays; ++i) - { - const RHI::ShaderResourceGroupLayout* viewSrgLayout = RPI::RPISystemInterface::Get()->GetViewSrgLayout().get(); - const AZStd::string baseName = "m_decalTextureArray" + AZStd::to_string(i); - - m_decalTextureArrayIndices[i] = viewSrgLayout->FindShaderInputImageIndex(Name(baseName.c_str())); - AZ_Warning("DecalTextureArrayFeatureProcessor", m_decalTextureArrayIndices[i].IsValid(), "Unable to find %s in decal shader.", baseName.c_str()); + // The azsl shader should define several texture arrays such as: + // Texture2DArray m_decalTextureArrayDiffuse0; + // Texture2DArray m_decalTextureArrayDiffuse1; + // Texture2DArray m_decalTextureArrayDiffuse2; + // and + // Texture2DArray m_decalTextureArrayNormalMaps0; + // Texture2DArray m_decalTextureArrayNormalMaps1; + // Texture2DArray m_decalTextureArrayNormalMaps2; + static const AZStd::array ShaderNames = { "m_decalTextureArrayDiffuse", + "m_decalTextureArrayNormalMaps" }; + + for (int mapType = 0; mapType < DecalMapType_Num; ++mapType) + { + for (int texArrayIdx = 0; texArrayIdx < NumTextureArrays; ++texArrayIdx) + { + const RHI::ShaderResourceGroupLayout* viewSrgLayout = RPI::RPISystemInterface::Get()->GetViewSrgLayout().get(); + const AZStd::string baseName = ShaderNames[mapType] + AZStd::to_string(texArrayIdx); + + m_decalTextureArrayIndices[texArrayIdx][mapType] = viewSrgLayout->FindShaderInputImageIndex(Name(baseName.c_str())); + AZ_Warning( + "DecalTextureArrayFeatureProcessor", m_decalTextureArrayIndices[texArrayIdx][mapType].IsValid(), + "Unable to find %s in decal shader.", + baseName.c_str()); + } } } @@ -411,8 +428,11 @@ namespace AZ int iter = m_textureArrayList.begin(); while (iter != -1) { - const auto& packedTexture = m_textureArrayList[iter].second.GetPackedTexture(); - view->GetShaderResourceGroup()->SetImage(m_decalTextureArrayIndices[iter], packedTexture); + for (int mapType = 0 ; mapType < DecalMapType_Num ; ++mapType) + { + const auto& packedTexture = m_textureArrayList[iter].second.GetPackedTexture(aznumeric_cast(mapType)); + view->GetShaderResourceGroup()->SetImage(m_decalTextureArrayIndices[iter][mapType], packedTexture); + } iter = m_textureArrayList.next(iter); } } diff --git a/Gems/Atom/Feature/Common/Code/Source/Decals/DecalTextureArrayFeatureProcessor.h b/Gems/Atom/Feature/Common/Code/Source/Decals/DecalTextureArrayFeatureProcessor.h index 57c5c69e0d..13a6682629 100644 --- a/Gems/Atom/Feature/Common/Code/Source/Decals/DecalTextureArrayFeatureProcessor.h +++ b/Gems/Atom/Feature/Common/Code/Source/Decals/DecalTextureArrayFeatureProcessor.h @@ -89,6 +89,7 @@ namespace AZ private: // Number of size and format permutations + // This number should match the number of texture arrays in Decals/ViewSrg.azsli static constexpr int NumTextureArrays = 5; static constexpr const char* FeatureProcessorName = "DecalTextureArrayFeatureProcessor"; @@ -128,7 +129,7 @@ namespace AZ // 4 textures @ 512x512 IndexableList < AZStd::pair < AZ::RHI::Size, DecalTextureArray>> m_textureArrayList; - AZStd::array m_decalTextureArrayIndices; + AZStd::array, NumTextureArrays> m_decalTextureArrayIndices; GpuBufferHandler m_decalBufferHandler; AsyncLoadTracker m_materialLoadTracker; diff --git a/Gems/Atom/Feature/Common/Code/Tests/Decals/DecalTextureArrayTests.cpp b/Gems/Atom/Feature/Common/Code/Tests/Decals/DecalTextureArrayTests.cpp index fcbcec0256..84c2b88507 100644 --- a/Gems/Atom/Feature/Common/Code/Tests/Decals/DecalTextureArrayTests.cpp +++ b/Gems/Atom/Feature/Common/Code/Tests/Decals/DecalTextureArrayTests.cpp @@ -42,7 +42,7 @@ namespace UnitTest { AZ::Render::DecalTextureArray decalTextureArray; decalTextureArray.Pack(); - auto nothing = decalTextureArray.GetPackedTexture(); + auto nothing = decalTextureArray.GetPackedTexture(AZ::Render::DecalMapType_Diffuse); EXPECT_EQ(nothing, nullptr); }