@ -8,21 +8,19 @@
# include <TerrainRenderer/Components/TerrainSurfaceMaterialsListComponent.h>
# include <AzCore/Asset/AssetManagerBus.h>
# include <AzCore/Component/Entity.h>
# include <AzCore/Asset/AssetManager.h>
# include <AzCore/Asset/AssetManagerBus.h>
# include <AzCore/Asset/AssetSerializer.h>
# include <AzCore/Component/Entity.h>
# include <AzCore/Math/Aabb.h>
# include <AzCore/RTTI/BehaviorContext.h>
# include <AzCore/Serialization/EditContext.h>
# include <AzCore/Serialization/SerializeContext.h>
# include <AzCore/Math/Aabb.h>
# include <AzCore/std/smart_ptr/make_shared.h>
# include <GradientSignal/Ebuses/GradientRequestBus.h>
# include <SurfaceData/SurfaceDataProviderRequestBus.h>
# include <AtomLyIntegration/CommonFeatures/Material/MaterialComponentBus.h>
# include <GradientSignal/Ebuses/GradientRequestBus.h>
# include <SurfaceData/SurfaceDataProviderRequestBus.h>
# include <TerrainSystem/TerrainSystemBus.h>
namespace Terrain
@ -38,13 +36,12 @@ namespace Terrain
if ( auto edit = serialize - > GetEditContext ( ) )
{
edit - > Class < TerrainSurfaceMaterialMapping > ( " Terrain Surface Gradient M apping" , " Mapping between a surface and a material. " )
edit - > Class < TerrainSurfaceMaterialMapping > ( " Terrain surface gradient m apping" , " Mapping between a surface and a material. " )
- > ClassElement ( AZ : : Edit : : ClassElements : : EditorData , " " )
- > Attribute ( AZ : : Edit : : Attributes : : AutoExpand , true )
- > Attribute ( AZ : : Edit : : Attributes : : Visibility , AZ : : Edit : : PropertyVisibility : : Show )
- > DataElement ( AZ : : Edit : : UIHandlers : : ComboBox , & TerrainSurfaceMaterialMapping : : m_surfaceTag , " Surface T ag" , " Surface type to map to a material. " )
- > DataElement ( AZ : : Edit : : UIHandlers : : Default , & TerrainSurfaceMaterialMapping : : m_materialAsset , " Material A sset" , " " )
- > DataElement ( AZ : : Edit : : UIHandlers : : ComboBox , & TerrainSurfaceMaterialMapping : : m_surfaceTag , " Surface t ag" , " Surface type to map to a material. " )
- > DataElement ( AZ : : Edit : : UIHandlers : : Default , & TerrainSurfaceMaterialMapping : : m_materialAsset , " Material a sset" , " " )
- > Attribute ( AZ : : Edit : : Attributes : : AutoExpand , true )
- > Attribute ( AZ : : Edit : : Attributes : : ShowProductAssetFileName , true )
;
@ -60,7 +57,8 @@ namespace Terrain
if ( serialize )
{
serialize - > Class < TerrainSurfaceMaterialsListConfig , AZ : : ComponentConfig > ( )
- > Version ( 1 )
- > Version ( 2 )
- > Field ( " DefaultMaterial " , & TerrainSurfaceMaterialsListConfig : : m_defaultSurfaceMaterial )
- > Field ( " Mappings " , & TerrainSurfaceMaterialsListConfig : : m_surfaceMaterials ) ;
AZ : : EditContext * edit = serialize - > GetEditContext ( ) ;
@ -68,10 +66,13 @@ namespace Terrain
{
edit - > Class < TerrainSurfaceMaterialsListConfig > (
" Terrain Surface Material List Component " , " Provide mapping between surfaces and render materials. " )
- > SetDynamicEditDataProvider ( & TerrainSurfaceMaterialsListConfig : : GetDynamicData )
- > ClassElement ( AZ : : Edit : : ClassElements : : EditorData , " " )
- > Attribute ( AZ : : Edit : : Attributes : : Visibility , AZ : : Edit : : PropertyVisibility : : Show )
- > Attribute ( AZ : : Edit : : Attributes : : AutoExpand , true )
- > DataElement ( AZ : : Edit : : UIHandlers : : Default , & TerrainSurfaceMaterialsListConfig : : m_defaultSurfaceMaterial ,
" Default Material " , " The default material to fall back to where no other material surface mappings exist. " )
- > DataElement (
AZ : : Edit : : UIHandlers : : Default , & TerrainSurfaceMaterialsListConfig : : m_surfaceMaterials ,
" Material Mappings " , " Maps surfaces to materials. " ) ;
@ -79,6 +80,26 @@ namespace Terrain
}
}
TerrainSurfaceMaterialsListConfig : : TerrainSurfaceMaterialsListConfig ( )
{
m_hideSurfaceTagData . m_attributes . push_back (
{
AZ : : Edit : : Attributes : : Visibility ,
aznew AZ : : Edit : : AttributeData < AZ : : Crc32 > ( AZ : : Edit : : PropertyVisibility : : Hide )
}
) ;
}
const AZ : : Edit : : ElementData * TerrainSurfaceMaterialsListConfig : : GetDynamicData ( const void * handlerPtr , const void * elementPtr , const AZ : : Uuid & )
{
const TerrainSurfaceMaterialsListConfig * owner = reinterpret_cast < const TerrainSurfaceMaterialsListConfig * > ( handlerPtr ) ;
if ( elementPtr = = & owner - > m_defaultSurfaceMaterial . m_surfaceTag )
{
return & owner - > m_hideSurfaceTagData ;
}
return nullptr ;
}
void TerrainSurfaceMaterialsListComponent : : GetProvidedServices ( AZ : : ComponentDescriptor : : DependencyArrayType & services )
{
services . push_back ( AZ_CRC_CE ( " TerrainMaterialProviderService " ) ) ;
@ -116,15 +137,21 @@ namespace Terrain
{
m_cachedAabb = AZ : : Aabb : : CreateNull ( ) ;
// Set all the materials as inactive and start loading.
for ( auto & surfaceMaterialMapping : m_configuration . m_surfaceMaterials )
auto checkLoadMaterial = [ & ] ( TerrainSurfaceMaterialMapping & material )
{
if ( surfaceMaterialMapping . m_materialAsset . GetId ( ) . IsValid ( ) )
if ( material . m_materialAsset . GetId ( ) . IsValid ( ) )
{
surfaceMaterialMapping . m_active = false ;
surfaceMaterialMapping . m_materialAsset . QueueLoad ( ) ;
AZ : : Data : : AssetBus : : MultiHandler : : BusConnect ( surfaceMaterialMapping . m_materialAsset . GetId ( ) ) ;
material . m_active = false ;
material . m_materialAsset . QueueLoad ( ) ;
AZ : : Data : : AssetBus : : MultiHandler : : BusConnect ( material . m_materialAsset . GetId ( ) ) ;
}
} ;
// Set all the materials as inactive and start loading.
checkLoadMaterial ( m_configuration . m_defaultSurfaceMaterial ) ;
for ( auto & surfaceMaterialMapping : m_configuration . m_surfaceMaterials )
{
checkLoadMaterial ( surfaceMaterialMapping ) ;
}
// Announce initial shape using OnShapeChanged
@ -135,24 +162,35 @@ namespace Terrain
{
TerrainAreaMaterialRequestBus : : Handler : : BusDisconnect ( ) ;
for ( auto & surfaceMaterialMapping : m_configuration . m_surfaceMaterials )
auto checkResetMaterial = [ & ] ( TerrainSurfaceMaterialMapping & material )
{
if ( surfaceMaterialMapping . m_materialAsset . GetId ( ) . IsValid ( ) )
if ( material . m_materialAsset . GetId ( ) . IsValid ( ) )
{
AZ : : Data : : AssetBus : : MultiHandler : : BusDisconnect ( surfaceMaterialMapping . m_materialAsset . GetId ( ) ) ;
surfaceMaterialMapping . m_materialAsset . Release ( ) ;
surfaceMaterialMapping . m_materialInstance . reset ( ) ;
surfaceMaterialMapping . m_activeMaterialAssetId = AZ : : Data : : AssetId ( ) ;
AZ : : Data : : AssetBus : : MultiHandler : : BusDisconnect ( material . m_materialAsset . GetId ( ) ) ;
material . m_materialAsset . Release ( ) ;
material . m_materialInstance . reset ( ) ;
material . m_activeMaterialAssetId = AZ : : Data : : AssetId ( ) ;
}
} ;
checkResetMaterial ( m_configuration . m_defaultSurfaceMaterial ) ;
for ( auto & surfaceMaterialMapping : m_configuration . m_surfaceMaterials )
{
checkResetMaterial ( surfaceMaterialMapping ) ;
}
HandleMaterialStateChanges ( ) ;
}
int TerrainSurfaceMaterialsListComponent : : CountMaterialIDInstances ( AZ : : Data : : AssetId id ) const
int TerrainSurfaceMaterialsListComponent : : CountMaterialI d Instances( AZ : : Data : : AssetId id ) const
{
int count = 0 ;
if ( m_configuration . m_defaultSurfaceMaterial . m_activeMaterialAssetId = = id )
{
count + + ;
}
for ( const auto & surfaceMaterialMapping : m_configuration . m_surfaceMaterials )
{
if ( surfaceMaterialMapping . m_activeMaterialAssetId = = id )
@ -169,28 +207,63 @@ namespace Terrain
bool anyMaterialIsActive = false ;
bool anyMaterialWasAlreadyActive = false ;
for ( auto & surfaceMaterialMapping : m_configuration . m_surfaceMaterials )
{
const bool wasPreviouslyActive = surfaceMaterialMapping . m_active ;
const bool isNowActive = ( surfaceMaterialMapping . m_materialInstance ! = nullptr ) ;
// Handle default material first
auto & defaultMaterial = m_configuration . m_defaultSurfaceMaterial ;
const bool wasPreviouslyActive = defaultMaterial . m_active ;
defaultMaterial . m_active = ( defaultMaterial . m_materialInstance ! = nullptr ) ;
if ( wasPreviouslyActive )
anyMaterialWasAlreadyActive = wasPreviouslyActive ;
anyMaterialIsActive = defaultMaterial . m_active ;
if ( ! wasPreviouslyActive & & ! defaultMaterial . m_active )
{
// A material has been assigned but has not yet completed loading.
}
else if ( ! wasPreviouslyActive & & defaultMaterial . m_active )
{
anyMaterialWasAlreadyActive = true ;
TerrainAreaMaterialNotificationBus : : Broadcast (
& TerrainAreaMaterialNotificationBus : : Events : : OnTerrainDefaultSurfaceMaterialCreated , GetEntityId ( ) ,
defaultMaterial . m_materialInstance ) ;
defaultMaterial . m_previousChangeId = defaultMaterial . m_materialInstance - > GetCurrentChangeId ( ) ;
}
else if ( wasPreviouslyActive & & ! defaultMaterial . m_active )
{
// Don't disconnect from the AssetBus if this material is mapped more than once.
if ( CountMaterialIdInstances ( defaultMaterial . m_activeMaterialAssetId ) = = 1 )
{
AZ : : Data : : AssetBus : : MultiHandler : : BusDisconnect ( defaultMaterial . m_activeMaterialAssetId ) ;
}
defaultMaterial = { } ;
if ( isNowActive )
TerrainAreaMaterialNotificationBus : : Broadcast (
& TerrainAreaMaterialNotificationBus : : Events : : OnTerrainDefaultSurfaceMaterialDestroyed , GetEntityId ( ) ) ;
}
else if ( defaultMaterial . m_materialInstance - > GetAssetId ( ) ! = defaultMaterial . m_activeMaterialAssetId | |
defaultMaterial . m_materialInstance - > GetCurrentChangeId ( ) ! = defaultMaterial . m_previousChangeId )
{
anyMaterialIsActive = true ;
defaultMaterial . m_previousChangeId = defaultMaterial . m_materialInstance - > GetCurrentChangeId ( ) ;
defaultMaterial . m_activeMaterialAssetId = defaultMaterial . m_materialInstance - > GetAssetId ( ) ;
TerrainAreaMaterialNotificationBus : : Broadcast (
& TerrainAreaMaterialNotificationBus : : Events : : OnTerrainDefaultSurfaceMaterialChanged , GetEntityId ( ) , defaultMaterial . m_materialInstance ) ;
}
}
surfaceMaterialMapping . m_active = isNowActive ;
for ( auto & surfaceMaterialMapping : m_configuration . m_surfaceMaterials )
{
const bool wasPreviouslyActive = surfaceMaterialMapping . m_active ;
surfaceMaterialMapping . m_active = surfaceMaterialMapping . m_materialInstance ! = nullptr ;
anyMaterialWasAlreadyActive = anyMaterialWasAlreadyActive | | wasPreviouslyActive ;
anyMaterialIsActive = anyMaterialIsActive | | surfaceMaterialMapping . m_active ;
if ( ! wasPreviouslyActive & & ! isNowActive )
if ( ! wasPreviouslyActive & & ! surfaceMaterialMapping. m_a ctive)
{
// A material has been assigned but has not yet completed loading.
}
else if ( ! wasPreviouslyActive & & isNowActive )
else if ( ! wasPreviouslyActive & & surfaceMaterialMapping. m_a ctive)
{
// Remember the asset id so we can disconnect from the AssetBus if the material asset is removed.
surfaceMaterialMapping . m_activeMaterialAssetId = surfaceMaterialMapping . m_materialAsset . GetId ( ) ;
@ -199,16 +272,21 @@ namespace Terrain
& TerrainAreaMaterialNotificationBus : : Events : : OnTerrainSurfaceMaterialMappingCreated , GetEntityId ( ) ,
surfaceMaterialMapping . m_surfaceTag ,
surfaceMaterialMapping . m_materialInstance ) ;
surfaceMaterialMapping . m_previousChangeId = surfaceMaterialMapping . m_materialInstance - > GetCurrentChangeId ( ) ;
surfaceMaterialMapping . m_previousTag = surfaceMaterialMapping . m_surfaceTag ;
}
else if ( wasPreviouslyActive & & ! isNowActive )
else if ( wasPreviouslyActive & & ! surfaceMaterialMapping. m_a ctive)
{
// Don't disconnect from the AssetBus if this material is mapped more than once.
if ( CountMaterialI D Instances( surfaceMaterialMapping . m_activeMaterialAssetId ) = = 1 )
if ( CountMaterialI d Instances( surfaceMaterialMapping . m_activeMaterialAssetId ) = = 1 )
{
AZ : : Data : : AssetBus : : MultiHandler : : BusDisconnect ( surfaceMaterialMapping . m_activeMaterialAssetId ) ;
}
surfaceMaterialMapping . m_activeMaterialAssetId = AZ : : Data : : AssetId ( ) ;
surfaceMaterialMapping . m_activeMaterialAssetId = { } ;
surfaceMaterialMapping . m_previousChangeId = AZ : : RPI : : Material : : DEFAULT_CHANGE_ID ;
surfaceMaterialMapping . m_previousTag = { } ;
TerrainAreaMaterialNotificationBus : : Broadcast (
& TerrainAreaMaterialNotificationBus : : Events : : OnTerrainSurfaceMaterialMappingDestroyed , GetEntityId ( ) ,
@ -216,12 +294,27 @@ namespace Terrain
}
else
{
if ( surfaceMaterialMapping . m_previousTag ! = surfaceMaterialMapping . m_surfaceTag )
{
TerrainAreaMaterialNotificationBus : : Broadcast (
& TerrainAreaMaterialNotificationBus : : Events : : OnTerrainSurfaceMaterialMappingTagChanged , GetEntityId ( ) ,
surfaceMaterialMapping . m_previousTag ,
surfaceMaterialMapping . m_surfaceTag ) ;
surfaceMaterialMapping . m_previousTag = surfaceMaterialMapping . m_surfaceTag ;
}
if ( surfaceMaterialMapping . m_materialInstance - > GetAssetId ( ) ! = surfaceMaterialMapping . m_activeMaterialAssetId | |
surfaceMaterialMapping . m_materialInstance - > GetCurrentChangeId ( ) ! = surfaceMaterialMapping . m_previousChangeId )
{
surfaceMaterialMapping . m_previousChangeId = surfaceMaterialMapping . m_materialInstance - > GetCurrentChangeId ( ) ;
surfaceMaterialMapping . m_activeMaterialAssetId = surfaceMaterialMapping . m_materialInstance - > GetAssetId ( ) ;
TerrainAreaMaterialNotificationBus : : Broadcast (
& TerrainAreaMaterialNotificationBus : : Events : : OnTerrainSurfaceMaterialMappingChanged , GetEntityId ( ) ,
& TerrainAreaMaterialNotificationBus : : Events : : OnTerrainSurfaceMaterialMapping Material Changed, GetEntityId ( ) ,
surfaceMaterialMapping . m_surfaceTag ,
surfaceMaterialMapping . m_materialInstance ) ;
}
}
}
if ( ! anyMaterialWasAlreadyActive & & anyMaterialIsActive )
{
@ -290,14 +383,28 @@ namespace Terrain
void TerrainSurfaceMaterialsListComponent : : OnAssetReady ( AZ : : Data : : Asset < AZ : : Data : : AssetData > asset )
{
// Find the missing material instance with the correct id.
auto checkUpdateMaterialAsset = [ ] ( TerrainSurfaceMaterialMapping & mapping , const AZ : : Data : : Asset < AZ : : Data : : AssetData > & asset ) - > bool
{
if ( mapping . m_materialAsset . GetId ( ) = = asset . GetId ( ) & &
( ! mapping . m_materialInstance | | mapping . m_materialInstance - > GetAssetId ( ) ! = mapping . m_materialAsset . GetId ( ) ) )
{
mapping . m_materialInstance = AZ : : RPI : : Material : : FindOrCreate ( mapping . m_materialAsset ) ;
mapping . m_materialAsset . Release ( ) ;
return true ;
}
return false ;
} ;
// First check the default material
if ( ! checkUpdateMaterialAsset ( m_configuration . m_defaultSurfaceMaterial , asset ) )
{
// If the default materail wasn't updated, then check all the surface material mappings.
for ( auto & surfaceMaterialMapping : m_configuration . m_surfaceMaterials )
{
if ( surfaceMaterialMapping . m_materialAsset . GetId ( ) = = asset . GetId ( ) & &
( ! surfaceMaterialMapping . m_materialInstance | |
surfaceMaterialMapping . m_materialInstance - > GetAssetId ( ) ! = surfaceMaterialMapping . m_materialAsset . GetId ( ) ) )
if ( checkUpdateMaterialAsset ( surfaceMaterialMapping , asset ) )
{
surfaceMaterialMapping . m_materialInstance = AZ : : RPI : : Material : : FindOrCreate ( surfaceMaterialMapping . m_materialAsset ) ;
surfaceMaterialMapping . m_materialAsset . Release ( ) ;
break ;
}
}
}
HandleMaterialStateChanges ( ) ;