Merge branch 'stabilization/2106' of https://github.com/aws-lumberyard/o3de into Network/olexl/entity_replicator_cherrypick_fix

main
AMZN-Olex 5 years ago
commit 0550b1998d

@ -198,11 +198,13 @@ namespace AzFramework
AZ::SerializeContext* m_serializeContext{ nullptr };
//! The priority at which this call will be executed.
SpawnablePriority m_priority{ SpawnablePriority_Default };
//! Entity references are resolved by referring to the last entity spawned from a template entity in the spawnable. If this
//! is set to false entities from previous spawn calls are not taken into account. If set to true entity references may be
//! resolved to a previously spawned entity. A lookup table has to be constructed when true, which may negatively impact
//! performance, especially if a large number of entities are present on a ticket.
bool m_referencePreviouslySpawnedEntities{ false };
//! Entity references are resolved by referring to the most recent entity spawned from a template entity in the spawnable.
//! If the entity referred to hasn't been spawned yet, the reference will be resolved to the first one that *will* be spawned.
//! If this flag is set to "true", the id mappings will persist across SpawnEntites calls, and the entity references will resolve
//! correctly across them.
//! When "false", the entity id mappings will be reset on this call, so entity references will only work within this call, or
//! potentially with any subsequent SpawnEntities call where the flag is true once again.
bool m_referencePreviouslySpawnedEntities{ true };
};
struct DespawnAllEntitiesOptionalArgs final

@ -250,10 +250,47 @@ namespace AzFramework
AZ::Entity* SpawnableEntitiesManager::CloneSingleEntity(const AZ::Entity& entityTemplate,
EntityIdMap& templateToCloneMap, AZ::SerializeContext& serializeContext)
{
return AZ::IdUtils::Remapper<AZ::EntityId, true>::CloneObjectAndGenerateNewIdsAndFixRefs(
// If the same ID gets remapped more than once, preserve the original remapping instead of overwriting it.
constexpr bool allowDuplicateIds = false;
return AZ::IdUtils::Remapper<AZ::EntityId, allowDuplicateIds>::CloneObjectAndGenerateNewIdsAndFixRefs(
&entityTemplate, templateToCloneMap, &serializeContext);
}
void SpawnableEntitiesManager::InitializeEntityIdMappings(
const Spawnable::EntityList& entities, EntityIdMap& idMap, AZStd::unordered_set<AZ::EntityId>& previouslySpawned)
{
// Make sure we don't have any previous data lingering around.
idMap.clear();
previouslySpawned.clear();
idMap.reserve(entities.size());
previouslySpawned.reserve(entities.size());
for (auto& entity : entities)
{
idMap.emplace(entity->GetId(), AZ::Entity::MakeId());
}
}
void SpawnableEntitiesManager::RefreshEntityIdMapping(
const AZ::EntityId& entityId, EntityIdMap& idMap, AZStd::unordered_set<AZ::EntityId>& previouslySpawned)
{
if (previouslySpawned.contains(entityId))
{
// This entity has already been spawned at least once before, so we need to generate a new id for it and
// preserve the new id to fix up any future entity references to this entity.
idMap[entityId] = AZ::Entity::MakeId();
}
else
{
// This entity hasn't been spawned yet, so use the first id we've already generated for this entity and mark
// it as spawned so we know not to reuse this id next time.
previouslySpawned.emplace(entityId);
}
}
bool SpawnableEntitiesManager::ProcessRequest(SpawnAllEntitiesCommand& request)
{
Ticket& ticket = *request.m_ticket;
@ -269,18 +306,24 @@ namespace AzFramework
const Spawnable::EntityList& entitiesToSpawn = ticket.m_spawnable->GetEntities();
size_t entitiesToSpawnSize = entitiesToSpawn.size();
// Map keeps track of ids from template (spawnable) to clone (instance)
// Allowing patch ups of fields referring to entityIds outside of a given entity
EntityIdMap templateToCloneEntityIdMap;
// Reserve buffers
spawnedEntities.reserve(spawnedEntities.size() + entitiesToSpawnSize);
spawnedEntityIndices.reserve(spawnedEntityIndices.size() + entitiesToSpawnSize);
templateToCloneEntityIdMap.reserve(entitiesToSpawnSize);
// Pre-generate the full set of entity id to new entity id mappings, so that during the clone operation below,
// any entity references that point to a not-yet-cloned entity will still get their ids remapped correctly.
// We clear out and regenerate the set of IDs on every SpawnAllEntities call, because presumably every entity reference
// in every entity we're about to instantiate is intended to point to an entity in our newly-instantiated batch, regardless
// of spawn order. If we didn't clear out the map, it would be possible for some entities here to have references to
// previously-spawned entities from a previous SpawnEntities or SpawnAllEntities call.
InitializeEntityIdMappings(entitiesToSpawn, ticket.m_entityIdReferenceMap, ticket.m_previouslySpawned);
for (size_t i = 0; i < entitiesToSpawnSize; ++i)
{
AZ::Entity* clone = CloneSingleEntity(*entitiesToSpawn[i], templateToCloneEntityIdMap, *request.m_serializeContext);
// If this entity has previously been spawned, give it a new id in the reference map
RefreshEntityIdMapping(entitiesToSpawn[i].get()->GetId(), ticket.m_entityIdReferenceMap, ticket.m_previouslySpawned);
AZ::Entity* clone = CloneSingleEntity(*entitiesToSpawn[i], ticket.m_entityIdReferenceMap, *request.m_serializeContext);
AZ_Assert(clone != nullptr, "Failed to clone spawnable entity.");
spawnedEntities.emplace_back(clone);
@ -337,21 +380,17 @@ namespace AzFramework
const Spawnable::EntityList& entitiesToSpawn = ticket.m_spawnable->GetEntities();
size_t entitiesToSpawnSize = request.m_entityIndices.size();
// Reconstruct the template to entity mapping.
EntityIdMap templateToCloneEntityIdMap;
if (!request.m_referencePreviouslySpawnedEntities)
{
templateToCloneEntityIdMap.reserve(entitiesToSpawnSize);
}
else
if (ticket.m_entityIdReferenceMap.empty() || !request.m_referencePreviouslySpawnedEntities)
{
templateToCloneEntityIdMap.reserve(spawnedEntitiesInitialCount + entitiesToSpawnSize);
SpawnableConstIndexEntityContainerView indexEntityView(
spawnedEntities.begin(), spawnedEntityIndices.begin(), spawnedEntities.size());
for (auto& entry : indexEntityView)
{
templateToCloneEntityIdMap.insert_or_assign(entitiesToSpawn[entry.GetIndex()]->GetId(), entry.GetEntity()->GetId());
}
// This map keeps track of ids from template (spawnable) to clone (instance) allowing patch ups of fields referring
// to entityIds outside of a given entity.
// We pre-generate the full set of entity id to new entity id mappings, so that during the clone operation below,
// any entity references that point to a not-yet-cloned entity will still get their ids remapped correctly.
// By default, we only initialize this map once because it needs to persist across multiple SpawnEntities calls, so
// that reference fixups work even when the entity being referenced is spawned in a different SpawnEntities
// (or SpawnAllEntities) call.
// However, the caller can also choose to reset the map by passing in "m_referencePreviouslySpawnedEntities = false".
InitializeEntityIdMappings(entitiesToSpawn, ticket.m_entityIdReferenceMap, ticket.m_previouslySpawned);
}
spawnedEntities.reserve(spawnedEntities.size() + entitiesToSpawnSize);
@ -361,7 +400,12 @@ namespace AzFramework
{
if (index < entitiesToSpawn.size())
{
AZ::Entity* clone = CloneSingleEntity(*entitiesToSpawn[index], templateToCloneEntityIdMap, *request.m_serializeContext);
// If this entity has previously been spawned, give it a new id in the reference map
RefreshEntityIdMapping(
entitiesToSpawn[index].get()->GetId(), ticket.m_entityIdReferenceMap, ticket.m_previouslySpawned);
AZ::Entity* clone =
CloneSingleEntity(*entitiesToSpawn[index], ticket.m_entityIdReferenceMap, *request.m_serializeContext);
AZ_Assert(clone != nullptr, "Failed to clone spawnable entity.");
spawnedEntities.push_back(clone);
@ -451,9 +495,11 @@ namespace AzFramework
ticket.m_spawnedEntities.clear();
const Spawnable::EntityList& entities = request.m_spawnable->GetEntities();
// Map keeps track of ids from template (spawnable) to clone (instance)
// Allowing patch ups of fields referring to entityIds outside of a given entity
EntityIdMap templateToCloneEntityIdMap;
// Pre-generate the full set of entity id to new entity id mappings, so that during the clone operation below,
// any entity references that point to a not-yet-cloned entity will still get their ids remapped correctly.
// This map is intentionally cleared out and regenerated here to ensure that we're starting fresh with mappings that
// match the new set of template entities getting spawned.
InitializeEntityIdMappings(entities, ticket.m_entityIdReferenceMap, ticket.m_previouslySpawned);
if (ticket.m_loadAll)
{
@ -461,11 +507,13 @@ namespace AzFramework
// to spawn every entity, simply start over.
ticket.m_spawnedEntityIndices.clear();
size_t entitiesToSpawnSize = entities.size();
templateToCloneEntityIdMap.reserve(entitiesToSpawnSize);
for (size_t i = 0; i < entitiesToSpawnSize; ++i)
{
AZ::Entity* clone = CloneSingleEntity(*entities[i], templateToCloneEntityIdMap, *request.m_serializeContext);
// If this entity has previously been spawned, give it a new id in the reference map
RefreshEntityIdMapping(entities[i].get()->GetId(), ticket.m_entityIdReferenceMap, ticket.m_previouslySpawned);
AZ::Entity* clone = CloneSingleEntity(*entities[i], ticket.m_entityIdReferenceMap, *request.m_serializeContext);
AZ_Assert(clone != nullptr, "Failed to clone spawnable entity.");
ticket.m_spawnedEntities.push_back(clone);
@ -475,7 +523,7 @@ namespace AzFramework
else
{
size_t entitiesSize = entities.size();
templateToCloneEntityIdMap.reserve(entitiesSize);
for (size_t index : ticket.m_spawnedEntityIndices)
{
// It's possible for the new spawnable to have a different number of entities, so guard against this.
@ -483,7 +531,10 @@ namespace AzFramework
// detected and will result in the incorrect entities being spawned.
if (index < entitiesSize)
{
AZ::Entity* clone = CloneSingleEntity(*entities[index], templateToCloneEntityIdMap, *request.m_serializeContext);
// If this entity has previously been spawned, give it a new id in the reference map
RefreshEntityIdMapping(entities[index].get()->GetId(), ticket.m_entityIdReferenceMap, ticket.m_previouslySpawned);
AZ::Entity* clone = CloneSingleEntity(*entities[index], ticket.m_entityIdReferenceMap, *request.m_serializeContext);
AZ_Assert(clone != nullptr, "Failed to clone spawnable entity.");
ticket.m_spawnedEntities.push_back(clone);
}

@ -85,6 +85,22 @@ namespace AzFramework
AZ_CLASS_ALLOCATOR(Ticket, AZ::ThreadPoolAllocator, 0);
static constexpr uint32_t Processing = AZStd::numeric_limits<uint32_t>::max();
//! Map of template entity ids to their associated instance ids.
//! Tickets can be used to spawn the same template entities multiple times, in any order, across multiple calls.
//! Since template entities can reference other entities, this map is used to fix up those references across calls
//! using the following policy:
//! - Entities referencing an entity that hasn't been spawned yet will get a reference to the id that *will* be used
//! the first time that entity will be spawned. The reference will be invalid until that entity is spawned, but
//! will be valid if/when it gets spawned.
//! - Entities referencing an entity that *has* been spawned will get a reference to the id that was *last* used to
//! spawn the entity.
//! Note that this implies a certain level of non-determinism when spawning across calls, because the entity references
//! will be based on the order in which the SpawnEntity calls occur, which can be affected by things like priority.
EntityIdMap m_entityIdReferenceMap;
//! For this to work, we also need to keep track of whether or not each entity has been spawned at least once, so we know
//! whether or not to replace the id in the map when spawning a new instance of that entity.
AZStd::unordered_set<AZ::EntityId> m_previouslySpawned;
AZStd::vector<AZ::Entity*> m_spawnedEntities;
AZStd::vector<size_t> m_spawnedEntityIndices;
AZ::Data::Asset<Spawnable> m_spawnable;
@ -194,6 +210,15 @@ namespace AzFramework
bool ProcessRequest(BarrierCommand& request);
bool ProcessRequest(DestroyTicketCommand& request);
//! Generate a base set of original-to-new entity ID mappings to use during spawning.
//! Since Entity references get fixed up on an entity-by-entity basis while spawning, it's important to have the complete
//! set of new IDs available right at the start. This way, entities that refer to other entities that haven't spawned yet
//! will still get their references remapped correctly.
void InitializeEntityIdMappings(
const Spawnable::EntityList& entities, EntityIdMap& idMap, AZStd::unordered_set<AZ::EntityId>& previouslySpawned);
void RefreshEntityIdMapping(
const AZ::EntityId& entityId, EntityIdMap& idMap, AZStd::unordered_set<AZ::EntityId>& previouslySpawned);
Queue m_highPriorityQueue;
Queue m_regularPriorityQueue;

@ -32,6 +32,33 @@ namespace UnitTest
}
};
// Test component that has a reference to a different entity for use in validating per-instance entity id fixups.
class ComponentWithEntityReference : public AZ::Component
{
public:
AZ_COMPONENT(ComponentWithEntityReference, "{CF5FDE59-86E5-40B6-9272-BBC1C4AFD061}");
void Activate() override
{
}
void Deactivate() override
{
}
static void Reflect(AZ::ReflectContext* reflection)
{
if (auto* serializeContext = azrtti_cast<AZ::SerializeContext*>(reflection))
{
serializeContext->Class<ComponentWithEntityReference, AZ::Component>()
->Field("EntityReference", &ComponentWithEntityReference::m_entityReference)
;
}
}
AZ::EntityId m_entityReference;
};
class SpawnableEntitiesManagerTest : public AllocatorsFixture
{
public:
@ -42,6 +69,8 @@ namespace UnitTest
m_application = new TestApplication();
AZ::ComponentApplication::Descriptor descriptor;
m_application->Start(descriptor);
m_application->RegisterComponentDescriptor(ComponentWithEntityReference::CreateDescriptor());
// Without this, the user settings component would attempt to save on finalize/shutdown. Since the file is
// shared across the whole engine, if multiple tests are run in parallel, the saving could cause a crash
// in the unit tests.
@ -80,6 +109,7 @@ namespace UnitTest
void FillSpawnable(size_t numElements)
{
AzFramework::Spawnable::EntityList& entities = m_spawnable->GetEntities();
entities.clear();
entities.reserve(numElements);
for (size_t i=0; i<numElements; ++i)
{
@ -123,6 +153,94 @@ namespace UnitTest
}
}
enum class EntityReferenceScheme
{
AllReferenceFirst,
AllReferenceLast,
AllReferenceThemselves,
AllReferenceNextCircular,
AllReferencePreviousCircular
};
void CreateEntityReferences(EntityReferenceScheme refScheme)
{
AzFramework::Spawnable::EntityList& entities = m_spawnable->GetEntities();
size_t numElements = entities.size();
for (size_t i = 0; i < numElements; ++i)
{
AZStd::unique_ptr<AZ::Entity>& entity = entities[i];
auto component = entity->CreateComponent<ComponentWithEntityReference>();
switch (refScheme)
{
case EntityReferenceScheme::AllReferenceFirst :
component->m_entityReference = entities[0]->GetId();
break;
case EntityReferenceScheme::AllReferenceLast:
component->m_entityReference = entities[numElements - 1]->GetId();
break;
case EntityReferenceScheme::AllReferenceThemselves:
component->m_entityReference = entities[i]->GetId();
break;
case EntityReferenceScheme::AllReferenceNextCircular:
component->m_entityReference = entities[(i + 1) % numElements]->GetId();
break;
case EntityReferenceScheme::AllReferencePreviousCircular:
component->m_entityReference = entities[(i + numElements - 1) % numElements]->GetId();
break;
}
}
}
// Verify that the entity references are pointing to the correct other entities within the same spawn batch.
// A "spawn batch" is the set of entities produced for each SpawnAllEntities command.
void ValidateEntityReferences(
EntityReferenceScheme refScheme, size_t entitiesPerBatch, AzFramework::SpawnableConstEntityContainerView entities)
{
size_t numElements = entities.size();
for (size_t i = 0; i < numElements; ++i)
{
// Calculate the element offset that's the start of each batch of entities spawned.
size_t curSpawnBatch = i / entitiesPerBatch;
size_t curBatchOffset = curSpawnBatch * entitiesPerBatch;
size_t curBatchIndex = i - curBatchOffset;
const AZ::Entity* const entity = *(entities.begin() + i);
auto component = entity->FindComponent<ComponentWithEntityReference>();
ASSERT_NE(nullptr, component);
AZ::EntityId comparisonId;
// Ids should be local to a batch, so each of these will be compared within a batch of entities, not globally across
// the entire set.
switch (refScheme)
{
case EntityReferenceScheme::AllReferenceFirst:
// Compare against the first entity in each batch
comparisonId = (*(entities.begin() + curBatchOffset))->GetId();
break;
case EntityReferenceScheme::AllReferenceLast:
// Compare against the last entity in each batch
comparisonId = (*(entities.begin() + curBatchOffset + (entitiesPerBatch - 1)))->GetId();
break;
case EntityReferenceScheme::AllReferenceThemselves:
// Compare against itself
comparisonId = entity->GetId();
break;
case EntityReferenceScheme::AllReferenceNextCircular:
// Compare against the next entity in each batch, looping around so that the last entity in the batch should refer
// to the first entity in the batch.
comparisonId = (*(entities.begin() + curBatchOffset + ((curBatchIndex + 1) % entitiesPerBatch)))->GetId();
break;
case EntityReferenceScheme::AllReferencePreviousCircular:
// Compare against the previous entity in each batch, looping around so that the first entity in the batch should refer
// to the last entity in the batch.
comparisonId = (*(entities.begin() + curBatchOffset + ((curBatchIndex + numElements - 1) % entitiesPerBatch)))->GetId();
break;
}
EXPECT_EQ(comparisonId, component->m_entityReference);
}
};
protected:
AZ::Data::Asset<AzFramework::Spawnable>* m_spawnableAsset { nullptr };
AzFramework::SpawnableEntitiesManager* m_manager { nullptr };
@ -185,6 +303,73 @@ namespace UnitTest
m_manager->ProcessQueue(AzFramework::SpawnableEntitiesManager::CommandQueuePriority::Regular);
}
TEST_F(SpawnableEntitiesManagerTest, SpawnAllEntities_AllEntitiesReferenceOtherEntities_EntityIdsAreMappedCorrectly)
{
// This tests that entity id references get mapped correctly in a SpawnAllEntities call whether they're forward referencing
// in the list, backwards referencing, or self-referencing. The circular tests are to ensure the implementation works regardless
// of entity ordering.
for (EntityReferenceScheme refScheme : {
EntityReferenceScheme::AllReferenceFirst, EntityReferenceScheme::AllReferenceLast,
EntityReferenceScheme::AllReferenceThemselves, EntityReferenceScheme::AllReferenceNextCircular,
EntityReferenceScheme::AllReferencePreviousCircular })
{
constexpr size_t NumEntities = 4;
FillSpawnable(NumEntities);
CreateEntityReferences(refScheme);
auto callback = [this, refScheme, NumEntities]
(AzFramework::EntitySpawnTicket::Id, AzFramework::SpawnableConstEntityContainerView entities)
{
ValidateEntityReferences(refScheme, NumEntities, entities);
};
AzFramework::SpawnAllEntitiesOptionalArgs optionalArgs;
optionalArgs.m_completionCallback = AZStd::move(callback);
m_manager->SpawnAllEntities(*m_ticket, AZStd::move(optionalArgs));
m_manager->ProcessQueue(AzFramework::SpawnableEntitiesManager::CommandQueuePriority::Regular);
}
}
TEST_F(SpawnableEntitiesManagerTest, SpawnAllEntities_AllEntitiesReferenceOtherEntities_EntityIdsOnlyReferWithinASingleCall)
{
// This tests that entity id references get mapped correctly with multiple SpawnAllEntities calls. Each call should only map
// the entities to other entities within the same call, regardless of forward or backward mapping.
// For example, suppose entities 1, 2, and 3 refer to 4. In the first SpawnAllEntities call, entities 1-3 will refer to 4.
// In the second SpawnAllEntities call, entities 1-3 will refer to the second 4, not the previously-spawned 4.
for (EntityReferenceScheme refScheme :
{ EntityReferenceScheme::AllReferenceFirst, EntityReferenceScheme::AllReferenceLast,
EntityReferenceScheme::AllReferenceThemselves, EntityReferenceScheme::AllReferenceNextCircular,
EntityReferenceScheme::AllReferencePreviousCircular
})
{
// Make sure we start with a fresh ticket each time, or else each iteration through this loop would continue to build up
// more and more entities.
delete m_ticket;
m_ticket = new AzFramework::EntitySpawnTicket(*m_spawnableAsset);
constexpr size_t NumEntities = 4;
FillSpawnable(NumEntities);
CreateEntityReferences(refScheme);
auto callback = [this, refScheme, NumEntities]
(AzFramework::EntitySpawnTicket::Id, AzFramework::SpawnableConstEntityContainerView entities)
{
ValidateEntityReferences(refScheme, NumEntities, entities);
};
// Spawn twice.
constexpr size_t NumSpawnAllCalls = 2;
for (int spawns = 0; spawns < NumSpawnAllCalls; spawns++)
{
AzFramework::SpawnAllEntitiesOptionalArgs optionalArgs;
optionalArgs.m_completionCallback = AZStd::move(callback);
m_manager->SpawnAllEntities(*m_ticket, AZStd::move(optionalArgs));
}
m_manager->ListEntities(*m_ticket, callback);
m_manager->ProcessQueue(AzFramework::SpawnableEntitiesManager::CommandQueuePriority::Regular);
}
}
TEST_F(SpawnableEntitiesManagerTest, SpawnAllEntities_DeleteTicketBeforeCall_NoCrash)
{
{
@ -363,6 +548,180 @@ namespace UnitTest
m_manager->ProcessQueue(AzFramework::SpawnableEntitiesManager::CommandQueuePriority::Regular);
}
TEST_F(SpawnableEntitiesManagerTest, SpawnEntities_AllEntitiesReferenceOtherEntities_ForwardReferencesWorkInSingleCall)
{
constexpr EntityReferenceScheme refScheme = EntityReferenceScheme::AllReferenceNextCircular;
constexpr size_t NumEntities = 4;
FillSpawnable(NumEntities);
CreateEntityReferences(refScheme);
auto callback =
[this, refScheme, NumEntities](AzFramework::EntitySpawnTicket::Id, AzFramework::SpawnableConstEntityContainerView entities)
{
ValidateEntityReferences(refScheme, NumEntities, entities);
};
// Verify that by default, entities that refer to other entities that haven't been spawned yet have the correct references
// when the spawning all occurs in the same call
m_manager->SpawnEntities(*m_ticket, { 0, 1, 2, 3 });
m_manager->ListEntities(*m_ticket, callback);
m_manager->ProcessQueue(AzFramework::SpawnableEntitiesManager::CommandQueuePriority::Regular);
}
TEST_F(SpawnableEntitiesManagerTest, SpawnEntities_AllEntitiesReferenceOtherEntities_ForwardReferencesWorkAcrossCalls)
{
constexpr EntityReferenceScheme refScheme = EntityReferenceScheme::AllReferenceNextCircular;
constexpr size_t NumEntities = 4;
FillSpawnable(NumEntities);
CreateEntityReferences(refScheme);
auto callback =
[this, refScheme, NumEntities](AzFramework::EntitySpawnTicket::Id, AzFramework::SpawnableConstEntityContainerView entities)
{
ValidateEntityReferences(refScheme, NumEntities, entities);
};
// Verify that by default, entities that refer to other entities that haven't been spawned yet have the correct references
// even when the spawning is across multiple calls
m_manager->SpawnEntities(*m_ticket, { 0 });
m_manager->SpawnEntities(*m_ticket, { 1 });
m_manager->SpawnEntities(*m_ticket, { 2 });
m_manager->SpawnEntities(*m_ticket, { 3 });
m_manager->ListEntities(*m_ticket, callback);
m_manager->ProcessQueue(AzFramework::SpawnableEntitiesManager::CommandQueuePriority::Regular);
}
TEST_F(SpawnableEntitiesManagerTest, SpawnEntities_AllEntitiesReferenceOtherEntities_ReferencesPointToFirstOrLatest)
{
// With SpawnEntities, entity references should either refer to the first entity that *will* be spawned, or the last entity
// that *has* been spawned. This test will create entities 0 1 2 3 that all refer to entity 3, and it will create two batches
// of those. In the first batch, they'll forward-reference. In the second batch, they should backward-reference, except for
// the second entity 3, which will now refer to itself as the last one that's been spawned.
constexpr EntityReferenceScheme refScheme = EntityReferenceScheme::AllReferenceLast;
constexpr size_t NumEntities = 4;
FillSpawnable(NumEntities);
CreateEntityReferences(refScheme);
auto callback =
[this, refScheme, NumEntities](AzFramework::EntitySpawnTicket::Id, AzFramework::SpawnableConstEntityContainerView entities)
{
size_t numElements = entities.size();
for (size_t i = 0; i < numElements; ++i)
{
const AZ::Entity* const entity = *(entities.begin() + i);
auto component = entity->FindComponent<ComponentWithEntityReference>();
ASSERT_NE(nullptr, component);
AZ::EntityId comparisonId;
if (i < (numElements - 1))
{
// There are two batches of NumEntities elements. Every entity should either forward-reference or backward-reference
// to the last entity of the first batch, except for the very last entity of the second batch, which should reference
// itself.
comparisonId = (*(entities.begin() + (NumEntities- 1)))->GetId();
}
else
{
// The very last entity of the second batch should reference itself because it's now the latest instance of that
// entity to be spawned.
comparisonId = entity->GetId();
}
EXPECT_EQ(comparisonId, component->m_entityReference);
}
};
// Create 2 batches of forward references. In the first batch, entities 0 1 2 will point forward to 3. In the second batch,
// entities 0 1 2 will point *backward* to the first 3, and the second entity 3 will point to itself.
m_manager->SpawnEntities(*m_ticket, { 0, 1, 2, 3 });
m_manager->SpawnEntities(*m_ticket, { 0, 1, 2, 3 });
m_manager->ListEntities(*m_ticket, callback);
m_manager->ProcessQueue(AzFramework::SpawnableEntitiesManager::CommandQueuePriority::Regular);
}
TEST_F(SpawnableEntitiesManagerTest, SpawnEntities_AllEntitiesReferenceOtherEntities_MultipleSpawnsInSameCallReferenceCorrectly)
{
// With SpawnEntities, entity references should either refer to the first entity that *will* be spawned, or the last entity
// that *has* been spawned. This test will create entities 0 1 2 3 that all refer to entity 3, and it will create three sets
// of those in the same call, with the following results:
// - The first 0 1 2 will forward-reference to the first 3
// - The first 3 will reference itself
// - The second 0 1 2 will backwards-reference to the first 3
// - The second 3 will reference itself
// - The third 0 1 2 will backwards-reference to the second 3
// - The third 3 will reference itself
constexpr EntityReferenceScheme refScheme = EntityReferenceScheme::AllReferenceLast;
constexpr size_t NumEntities = 4;
FillSpawnable(NumEntities);
CreateEntityReferences(refScheme);
auto callback =
[this, refScheme, NumEntities](AzFramework::EntitySpawnTicket::Id, AzFramework::SpawnableConstEntityContainerView entities)
{
size_t numElements = entities.size();
for (size_t i = 0; i < numElements; ++i)
{
const AZ::Entity* const entity = *(entities.begin() + i);
auto component = entity->FindComponent<ComponentWithEntityReference>();
ASSERT_NE(nullptr, component);
AZ::EntityId comparisonId;
if (i < ((NumEntities * 2) - 1))
{
// The first 7 entities (0 1 2 3 0 1 2) will all refer to the 4th one (1st '3').
comparisonId = (*(entities.begin() + (NumEntities - 1)))->GetId();
}
else if (i < (numElements - 1))
{
// The next 4 entities (3 0 1 2) will all refer to the 8th one (2nd '3').
comparisonId = (*(entities.begin() + ((NumEntities * 2) - 1)))->GetId();
}
else
{
// The very last entity (3) will reference itself (3rd '3').
comparisonId = entity->GetId();
}
EXPECT_EQ(comparisonId, component->m_entityReference);
}
};
// Create the 3 batches of entities 0, 1, 2, 3. The entity references should work as described at the top of the test.
m_manager->SpawnEntities(*m_ticket, { 0, 1, 2, 3, 0, 1, 2, 3, 0, 1, 2, 3 });
m_manager->ListEntities(*m_ticket, callback);
m_manager->ProcessQueue(AzFramework::SpawnableEntitiesManager::CommandQueuePriority::Regular);
}
TEST_F(SpawnableEntitiesManagerTest, SpawnEntities_AllEntitiesReferenceOtherEntities_OptionalFlagClearsReferenceMap)
{
constexpr EntityReferenceScheme refScheme = EntityReferenceScheme::AllReferenceLast;
constexpr size_t NumEntities = 4;
FillSpawnable(NumEntities);
CreateEntityReferences(refScheme);
auto callback =
[this, refScheme, NumEntities](AzFramework::EntitySpawnTicket::Id, AzFramework::SpawnableConstEntityContainerView entities)
{
ValidateEntityReferences(refScheme, NumEntities, entities);
};
// By setting the "referencePreviouslySpawnedEntities" flag to false, the map will get cleared on each call, so in both batches
// the entities will forward-reference to the last entity in the batch. If the flag were true, entities 0 1 2 in the second
// batch would refer backwards to the first entity 3.
AzFramework::SpawnEntitiesOptionalArgs optionalArgsSecondBatch;
optionalArgsSecondBatch.m_completionCallback = AZStd::move(callback);
optionalArgsSecondBatch.m_referencePreviouslySpawnedEntities = false;
m_manager->SpawnEntities(*m_ticket, { 0, 1, 2, 3 }, optionalArgsSecondBatch);
m_manager->SpawnEntities(*m_ticket, { 0, 1, 2, 3 }, AZStd::move(optionalArgsSecondBatch));
m_manager->ListEntities(*m_ticket, callback);
m_manager->ProcessQueue(AzFramework::SpawnableEntitiesManager::CommandQueuePriority::Regular);
}
TEST_F(SpawnableEntitiesManagerTest, SpawnEntities_DeleteTicketBeforeCall_NoCrash)
{
{

@ -82,11 +82,11 @@ namespace AZ
RPI::Cullable m_cullable;
MaterialAssignmentMap m_materialAssignments;
MeshHandleDescriptor m_descriptor;
Data::Instance<RPI::Model> m_model;
//! A reference to the original model asset in case it got cloned before creating the model instance.
Data::Asset<RPI::ModelAsset> m_originalModelAsset;
MeshFeatureProcessorInterface::RequiresCloneCallback m_requiresCloningCallback;
Data::Instance<RPI::ShaderResourceGroup> m_shaderResourceGroup;
AZStd::unique_ptr<MeshLoader> m_meshLoader;
@ -99,10 +99,7 @@ namespace AZ
bool m_cullableNeedsRebuild = false;
bool m_objectSrgNeedsUpdate = true;
bool m_excludeFromReflectionCubeMaps = false;
bool m_skinnedMeshWithMotion = false;
bool m_rayTracingEnabled = true;
bool m_visible = true;
bool m_useForwardPassIblSpecular = false;
bool m_hasForwardPassIblSpecularMaterial = false;
};
@ -132,17 +129,11 @@ namespace AZ
void OnEndPrepareRender() override;
MeshHandle AcquireMesh(
const Data::Asset<RPI::ModelAsset>& modelAsset,
const MaterialAssignmentMap& materials = {},
bool skinnedMeshWithMotion = false,
bool rayTracingEnabled = true,
RequiresCloneCallback requiresCloneCallback = {}) override;
const MeshHandleDescriptor& descriptor,
const MaterialAssignmentMap& materials = {}) override;
MeshHandle AcquireMesh(
const Data::Asset<RPI::ModelAsset> &modelAsset,
const Data::Instance<RPI::Material>& material,
bool skinnedMeshWithMotion = false,
bool rayTracingEnabled = true,
RequiresCloneCallback requiresCloneCallback = {}) override;
const MeshHandleDescriptor& descriptor,
const Data::Instance<RPI::Material>& material) override;
bool ReleaseMesh(MeshHandle& meshHandle) override;
MeshHandle CloneMesh(const MeshHandle& meshHandle) override;

@ -26,6 +26,18 @@ namespace AZ
{
class MeshDataInstance;
//! Settings to apply to a mesh handle when acquiring it for the first time
struct MeshHandleDescriptor
{
using RequiresCloneCallback = AZStd::function<bool(const Data::Asset<RPI::ModelAsset>& modelAsset)>;
Data::Asset<RPI::ModelAsset> m_modelAsset;
bool m_isSkinnedMeshWithMotion = false;
bool m_isRayTracingEnabled = true;
bool m_useForwardPassIblSpecular = false;
RequiresCloneCallback m_requiresCloneCallback = {};
};
//! MeshFeatureProcessorInterface provides an interface to acquire and release a MeshHandle from the underlying MeshFeatureProcessor
class MeshFeatureProcessorInterface
: public RPI::FeatureProcessor
@ -35,23 +47,16 @@ namespace AZ
using MeshHandle = StableDynamicArrayHandle<MeshDataInstance>;
using ModelChangedEvent = Event<const Data::Instance<RPI::Model>>;
using RequiresCloneCallback = AZStd::function<bool(const Data::Asset<RPI::ModelAsset>& modelAsset)>;
//! Acquires a model with an optional collection of material assignments.
//! @param requiresCloneCallback The callback indicates whether cloning is required for a given model asset.
virtual MeshHandle AcquireMesh(
const Data::Asset<RPI::ModelAsset>& modelAsset,
const MaterialAssignmentMap& materials = {},
bool skinnedMeshWithMotion = false,
bool rayTracingEnabled = true,
RequiresCloneCallback requiresCloneCallback = {}) = 0;
const MeshHandleDescriptor& descriptor,
const MaterialAssignmentMap& materials = {}) = 0;
//! Acquires a model with a single material applied to all its meshes.
virtual MeshHandle AcquireMesh(
const Data::Asset<RPI::ModelAsset>& modelAsset,
const Data::Instance<RPI::Material>& material,
bool skinnedMeshWithMotion = false,
bool rayTracingEnabled = true,
RequiresCloneCallback requiresCloneCallback = {}) = 0;
const MeshHandleDescriptor& descriptor,
const Data::Instance<RPI::Material>& material) = 0;
//! Releases the mesh handle
virtual bool ReleaseMesh(MeshHandle& meshHandle) = 0;
//! Creates a new instance and handle of a mesh using an existing MeshId. Currently, this will reset the new mesh to default materials.

@ -37,8 +37,8 @@ namespace UnitTest
MOCK_METHOD1(GetSortKey, AZ::RHI::DrawItemSortKey(const MeshHandle&));
MOCK_METHOD2(SetLodOverride, void(const MeshHandle&, AZ::RPI::Cullable::LodOverride));
MOCK_METHOD1(GetLodOverride, AZ::RPI::Cullable::LodOverride(const MeshHandle&));
MOCK_METHOD5(AcquireMesh, MeshHandle (const AZ::Data::Asset<AZ::RPI::ModelAsset>&, const AZ::Render::MaterialAssignmentMap&, bool, bool, AZ::Render::MeshFeatureProcessorInterface::RequiresCloneCallback));
MOCK_METHOD5(AcquireMesh, MeshHandle (const AZ::Data::Asset<AZ::RPI::ModelAsset>&, const AZ::Data::Instance<AZ::RPI::Material>&, bool, bool, AZ::Render::MeshFeatureProcessorInterface::RequiresCloneCallback));
MOCK_METHOD2(AcquireMesh, MeshHandle (const AZ::Render::MeshHandleDescriptor&, const AZ::Render::MaterialAssignmentMap&));
MOCK_METHOD2(AcquireMesh, MeshHandle (const AZ::Render::MeshHandleDescriptor&, const AZ::Data::Instance<AZ::RPI::Material>&));
MOCK_METHOD2(SetRayTracingEnabled, void (const MeshHandle&, bool));
MOCK_METHOD2(SetVisible, void (const MeshHandle&, bool));
MOCK_METHOD2(SetUseForwardPassIblSpecular, void (const MeshHandle&, bool));

@ -149,46 +149,38 @@ namespace AZ
}
MeshFeatureProcessor::MeshHandle MeshFeatureProcessor::AcquireMesh(
const Data::Asset<RPI::ModelAsset>& modelAsset,
const MaterialAssignmentMap& materials,
bool skinnedMeshWithMotion,
bool rayTracingEnabled,
RequiresCloneCallback requiresCloneCallback)
const MeshHandleDescriptor& descriptor,
const MaterialAssignmentMap& materials)
{
AZ_PROFILE_FUNCTION(Debug::ProfileCategory::AzRender);
// don't need to check the concurrency during emplace() because the StableDynamicArray won't move the other elements during insertion
MeshHandle meshDataHandle = m_meshData.emplace();
// Mark skinned meshes to enable special processes to generate motion vector
meshDataHandle->m_skinnedMeshWithMotion = skinnedMeshWithMotion;
meshDataHandle->m_descriptor = descriptor;
// set ray tracing flag, but always disable on skinned meshes
// Always disable ray tracing flag on skinned meshes
// [GFX TODO][ATOM-13067] Enable raytracing on skinned meshes
meshDataHandle->m_rayTracingEnabled = rayTracingEnabled && (skinnedMeshWithMotion == false);
meshDataHandle->m_descriptor.m_isRayTracingEnabled &= !descriptor.m_isSkinnedMeshWithMotion;
meshDataHandle->m_scene = GetParentScene();
meshDataHandle->m_materialAssignments = materials;
meshDataHandle->m_objectId = m_transformService->ReserveObjectId();
meshDataHandle->m_originalModelAsset = modelAsset;
meshDataHandle->m_requiresCloningCallback = requiresCloneCallback;
meshDataHandle->m_meshLoader = AZStd::make_unique<MeshDataInstance::MeshLoader>(modelAsset, &*meshDataHandle);
meshDataHandle->m_originalModelAsset = descriptor.m_modelAsset;
meshDataHandle->m_meshLoader = AZStd::make_unique<MeshDataInstance::MeshLoader>(descriptor.m_modelAsset, &*meshDataHandle);
return meshDataHandle;
}
MeshFeatureProcessor::MeshHandle MeshFeatureProcessor::AcquireMesh(
const Data::Asset<RPI::ModelAsset>& modelAsset,
const Data::Instance<RPI::Material>& material,
bool skinnedMeshWithMotion,
bool rayTracingEnabled,
RequiresCloneCallback requiresCloneCallback)
const MeshHandleDescriptor& descriptor,
const Data::Instance<RPI::Material>& material)
{
Render::MaterialAssignmentMap materials;
Render::MaterialAssignment& defaultMaterial = materials[AZ::Render::DefaultMaterialAssignmentId];
defaultMaterial.m_materialInstance = material;
return AcquireMesh(modelAsset, materials, skinnedMeshWithMotion, rayTracingEnabled, requiresCloneCallback);
return AcquireMesh(descriptor, materials);
}
bool MeshFeatureProcessor::ReleaseMesh(MeshHandle& meshHandle)
@ -210,7 +202,7 @@ namespace AZ
{
if (meshHandle.IsValid())
{
MeshHandle clone = AcquireMesh(meshHandle->m_originalModelAsset, meshHandle->m_materialAssignments);
MeshHandle clone = AcquireMesh(meshHandle->m_descriptor, meshHandle->m_materialAssignments);
return clone;
}
return MeshFeatureProcessor::MeshHandle();
@ -377,6 +369,14 @@ namespace AZ
if (meshHandle.IsValid())
{
meshHandle->m_excludeFromReflectionCubeMaps = excludeFromReflectionCubeMaps;
if (excludeFromReflectionCubeMaps)
{
meshHandle->m_cullable.m_cullData.m_hideFlags |= RPI::View::UsageReflectiveCubeMap;
}
else
{
meshHandle->m_cullable.m_cullData.m_hideFlags &= ~RPI::View::UsageReflectiveCubeMap;
}
}
}
@ -385,12 +385,12 @@ namespace AZ
if (meshHandle.IsValid())
{
// update the ray tracing data based on the current state and the new state
if (rayTracingEnabled && !meshHandle->m_rayTracingEnabled)
if (rayTracingEnabled && !meshHandle->m_descriptor.m_isRayTracingEnabled)
{
// add to ray tracing
meshHandle->SetRayTracingData();
}
else if (!rayTracingEnabled && meshHandle->m_rayTracingEnabled)
else if (!rayTracingEnabled && meshHandle->m_descriptor.m_isRayTracingEnabled)
{
// remove from ray tracing
if (m_rayTracingFeatureProcessor)
@ -400,7 +400,7 @@ namespace AZ
}
// set new state
meshHandle->m_rayTracingEnabled = rayTracingEnabled;
meshHandle->m_descriptor.m_isRayTracingEnabled = rayTracingEnabled;
}
}
@ -416,7 +416,7 @@ namespace AZ
{
if (meshHandle.IsValid())
{
meshHandle->m_useForwardPassIblSpecular = useForwardPassIblSpecular;
meshHandle->m_descriptor.m_useForwardPassIblSpecular = useForwardPassIblSpecular;
meshHandle->m_objectSrgNeedsUpdate = true;
if (meshHandle->m_model)
@ -450,7 +450,7 @@ namespace AZ
// we need to rebuild the Srg for any meshes that are using the forward pass IBL specular option
for (auto& meshInstance : m_meshData)
{
if (meshInstance.m_useForwardPassIblSpecular)
if (meshInstance.m_descriptor.m_useForwardPassIblSpecular)
{
meshInstance.m_objectSrgNeedsUpdate = true;
}
@ -507,8 +507,8 @@ namespace AZ
Data::Instance<RPI::Model> model;
// Check if a requires cloning callback got set and if so check if cloning the model asset is requested.
if (m_parent->m_requiresCloningCallback &&
m_parent->m_requiresCloningCallback(modelAsset))
if (m_parent->m_descriptor.m_requiresCloneCallback &&
m_parent->m_descriptor.m_requiresCloneCallback(modelAsset))
{
// Clone the model asset to force create another model instance.
AZ::Data::AssetId newId(AZ::Uuid::CreateRandom(), /*subId=*/0);
@ -598,7 +598,7 @@ namespace AZ
objectIdIndex.AssertValid();
}
if (m_rayTracingEnabled)
if (m_descriptor.m_isRayTracingEnabled)
{
SetRayTracingData();
}
@ -671,7 +671,7 @@ namespace AZ
RPI::MeshDrawPacket drawPacket(modelLod, meshIndex, material, m_shaderResourceGroup, materialAssignment.m_matModUvOverrides);
// set the shader option to select forward pass IBL specular if necessary
if (!drawPacket.SetShaderOption(AZ::Name("o_meshUseForwardPassIBLSpecular"), AZ::RPI::ShaderOptionValue{ m_useForwardPassIblSpecular }))
if (!drawPacket.SetShaderOption(AZ::Name("o_meshUseForwardPassIBLSpecular"), AZ::RPI::ShaderOptionValue{ m_descriptor.m_useForwardPassIblSpecular }))
{
AZ_Warning("MeshDrawPacket", false, "Failed to set o_meshUseForwardPassIBLSpecular on mesh draw packet");
}
@ -682,7 +682,7 @@ namespace AZ
m_hasForwardPassIblSpecularMaterial |= materialRequiresForwardPassIblSpecular;
// stencil bits
uint8_t stencilRef = m_useForwardPassIblSpecular || materialRequiresForwardPassIblSpecular ? Render::StencilRefs::None : Render::StencilRefs::UseIBLSpecularPass;
uint8_t stencilRef = m_descriptor.m_useForwardPassIblSpecular || materialRequiresForwardPassIblSpecular ? Render::StencilRefs::None : Render::StencilRefs::UseIBLSpecularPass;
stencilRef |= Render::StencilRefs::UseDiffuseGIPass;
drawPacket.SetStencilRef(stencilRef);
@ -1102,12 +1102,12 @@ namespace AZ
//[GFX TODO][ATOM-4726] Replace this with a "isSkinnedMesh" external material property and a functor that enables/disables the appropriate shader
for (auto& shaderItem : material->GetShaderCollection())
{
if (shaderItem.GetShaderAsset()->GetName() == Name{ "StaticMeshMotionVector" } && m_skinnedMeshWithMotion)
if (shaderItem.GetShaderAsset()->GetName() == Name{ "StaticMeshMotionVector" } && m_descriptor.m_isSkinnedMeshWithMotion)
{
shaderItem.SetEnabled(false);
}
if (shaderItem.GetShaderAsset()->GetName() == Name{ "SkinnedMeshMotionVector" } && (!m_skinnedMeshWithMotion))
if (shaderItem.GetShaderAsset()->GetName() == Name{ "SkinnedMeshMotionVector" } && (!m_descriptor.m_isSkinnedMeshWithMotion))
{
shaderItem.SetEnabled(false);
}
@ -1123,7 +1123,7 @@ namespace AZ
ReflectionProbeFeatureProcessor* reflectionProbeFeatureProcessor = m_scene->GetFeatureProcessor<ReflectionProbeFeatureProcessor>();
if (reflectionProbeFeatureProcessor && (m_useForwardPassIblSpecular || m_hasForwardPassIblSpecularMaterial))
if (reflectionProbeFeatureProcessor && (m_descriptor.m_useForwardPassIblSpecular || m_hasForwardPassIblSpecularMaterial))
{
// retrieve probe constant indices
AZ::RHI::ShaderInputConstantIndex posConstantIndex = m_shaderResourceGroup->FindShaderInputConstantIndex(Name("m_reflectionProbeData.m_aabbPos"));

@ -39,7 +39,7 @@ namespace AZ
"Models/OcclusionCullingPlane.azmodel",
AZ::RPI::AssetUtils::TraceLevel::Assert);
m_visualizationMeshHandle = m_meshFeatureProcessor->AcquireMesh(m_visualizationModelAsset);
m_visualizationMeshHandle = m_meshFeatureProcessor->AcquireMesh(MeshHandleDescriptor{ m_visualizationModelAsset });
m_meshFeatureProcessor->SetExcludeFromReflectionCubeMaps(m_visualizationMeshHandle, true);
m_meshFeatureProcessor->SetRayTracingEnabled(m_visualizationMeshHandle, false);
m_meshFeatureProcessor->SetTransform(m_visualizationMeshHandle, AZ::Transform::CreateIdentity());

@ -67,7 +67,7 @@ namespace AZ
"Models/ReflectionProbeSphere.azmodel",
AZ::RPI::AssetUtils::TraceLevel::Assert);
m_visualizationMeshHandle = m_meshFeatureProcessor->AcquireMesh(m_visualizationModelAsset);
m_visualizationMeshHandle = m_meshFeatureProcessor->AcquireMesh(MeshHandleDescriptor{ m_visualizationModelAsset });
m_meshFeatureProcessor->SetExcludeFromReflectionCubeMaps(m_visualizationMeshHandle, true);
m_meshFeatureProcessor->SetRayTracingEnabled(m_visualizationMeshHandle, false);
m_meshFeatureProcessor->SetTransform(m_visualizationMeshHandle, AZ::Transform::CreateIdentity());

@ -160,13 +160,19 @@ namespace AZ
0,0,1,0,
0,0,0,1 };
yUpWorld.StoreToRowMajorFloat12(viewToWorldMatrixRaw);
const AZ::Matrix4x4 prevViewToWorldMatrix = m_viewToWorldMatrix;
m_viewToWorldMatrix = AZ::Matrix4x4::CreateFromRowMajorFloat16(viewToWorldMatrixRaw);
m_worldToViewMatrix = m_viewToWorldMatrix.GetInverseFast();
m_worldToClipMatrix = m_viewToClipMatrix * m_worldToViewMatrix;
m_onWorldToViewMatrixChange.Signal(m_worldToViewMatrix);
// Only signal an update when there is a change, otherwise this might block
// user input from changing the value.
if (!prevViewToWorldMatrix.IsClose(m_viewToWorldMatrix))
{
m_onWorldToViewMatrixChange.Signal(m_worldToViewMatrix);
}
m_onWorldToClipMatrixChange.Signal(m_worldToClipMatrix);
InvalidateSrg();

@ -317,8 +317,11 @@ namespace AZ
MaterialComponentRequestBus::EventResult(materials, entityId, &MaterialComponentRequests::GetMaterialOverrides);
m_meshFeatureProcessor->ReleaseMesh(m_meshHandle);
m_meshHandle = m_meshFeatureProcessor->AcquireMesh(m_configuration.m_modelAsset, materials,
/*skinnedMeshWithMotion=*/false, /*rayTracingEnabled=*/true, RequiresCloning);
MeshHandleDescriptor meshDescriptor;
meshDescriptor.m_modelAsset = m_configuration.m_modelAsset;
meshDescriptor.m_useForwardPassIblSpecular = m_configuration.m_useForwardPassIblSpecular;
meshDescriptor.m_requiresCloneCallback = RequiresCloning;
m_meshHandle = m_meshFeatureProcessor->AcquireMesh(meshDescriptor, materials);
m_meshFeatureProcessor->ConnectModelChangeEventHandler(m_meshHandle, m_changeEventHandler);
const AZ::Transform& transform = m_transformInterface ? m_transformInterface->GetWorldTM() : AZ::Transform::CreateIdentity();
@ -327,7 +330,6 @@ namespace AZ
m_meshFeatureProcessor->SetSortKey(m_meshHandle, m_configuration.m_sortKey);
m_meshFeatureProcessor->SetLodOverride(m_meshHandle, m_configuration.m_lodOverride);
m_meshFeatureProcessor->SetExcludeFromReflectionCubeMaps(m_meshHandle, m_configuration.m_excludeFromReflectionCubeMaps);
m_meshFeatureProcessor->SetUseForwardPassIblSpecular(m_meshHandle, m_configuration.m_useForwardPassIblSpecular);
// [GFX TODO] This should happen automatically. m_changeEventHandler should be passed to AcquireMesh
// If the model instance or asset already exists, announce a model change to let others know it's loaded.

@ -626,9 +626,11 @@ namespace AZ
AZ_Error("ActorComponentController", meshFeatureProcessor, "Unable to find a MeshFeatureProcessorInterface on the entityId.");
if (meshFeatureProcessor)
{
// Last boolean parameter indicates if motion vector is enabled
MeshHandleDescriptor meshDescriptor;
meshDescriptor.m_modelAsset = m_skinnedMeshInstance->m_model->GetModelAsset();
meshDescriptor.m_isSkinnedMeshWithMotion = true;
m_meshHandle = AZStd::make_shared<MeshFeatureProcessorInterface::MeshHandle>(
m_meshFeatureProcessor->AcquireMesh(m_skinnedMeshInstance->m_model->GetModelAsset(), materials, /*skinnedMeshWithMotion=*/true));
m_meshFeatureProcessor->AcquireMesh(meshDescriptor, materials));
}
// If render proxies already exist, they will be auto-freed

@ -187,7 +187,7 @@ namespace Blast
materials, GetEntityId(), &AZ::Render::MaterialComponentRequests::GetMaterialOverrides);
m_meshFeatureProcessor->ReleaseMesh(m_meshHandle);
m_meshHandle = m_meshFeatureProcessor->AcquireMesh(m_meshAssets[0], materials);
m_meshHandle = m_meshFeatureProcessor->AcquireMesh(AZ::Render::MeshHandleDescriptor{ m_meshAssets[0] }, materials);
m_meshFeatureProcessor->ConnectModelChangeEventHandler(m_meshHandle, m_changeEventHandler);
HandleModelChange(m_meshFeatureProcessor->GetModel(m_meshHandle));

@ -47,7 +47,7 @@ namespace Blast
{
m_chunkActors[chunkId] = &actor;
m_chunkMeshHandles[chunkId] =
m_meshFeatureProcessor->AcquireMesh(m_meshData->GetMeshAsset(chunkId), m_materialMap);
m_meshFeatureProcessor->AcquireMesh(AZ::Render::MeshHandleDescriptor{ m_meshData->GetMeshAsset(chunkId) }, m_materialMap);
}
}

@ -98,7 +98,7 @@ namespace Blast
// ActorRenderManager::OnActorCreated
{
EXPECT_CALL(
*m_mockMeshFeatureProcessor, AcquireMesh(_, testing::A<const AZ::Render::MaterialAssignmentMap&>(), _, _, _))
*m_mockMeshFeatureProcessor, AcquireMesh(_, testing::A<const AZ::Render::MaterialAssignmentMap&>()))
.Times(aznumeric_cast<int>(m_actorFactory->m_mockActors[0]->GetChunkIndices().size()))
.WillOnce(Return(testing::ByMove(AZ::Render::MeshFeatureProcessorInterface::MeshHandle())))
.WillOnce(Return(testing::ByMove(AZ::Render::MeshFeatureProcessorInterface::MeshHandle())));

@ -300,7 +300,7 @@ namespace GraphModel
// Slot
AZ::JsonSerializationResult::Result JsonSlotSerializer::Load(
void* outputValue, const AZ::Uuid& outputValueTypeId, const rapidjson::Value& inputValue,
void* outputValue, [[maybe_unused]] const AZ::Uuid& outputValueTypeId, const rapidjson::Value& inputValue,
AZ::JsonDeserializerContext& context)
{
namespace JSR = AZ::JsonSerializationResult;
@ -343,12 +343,12 @@ namespace GraphModel
return context.Report(
result,
result.GetProcessing() != JSR::Processing::Halted ? "Succesfully loaded Slot information."
result.GetProcessing() != JSR::Processing::Halted ? "Successfully loaded Slot information."
: "Failed to load Slot information.");
}
AZ::JsonSerializationResult::Result JsonSlotSerializer::Store(
rapidjson::Value& outputValue, const void* inputValue, [[maybe_unused]] const void* defaultValue, const AZ::Uuid& valueTypeId,
rapidjson::Value& outputValue, const void* inputValue, [[maybe_unused]] const void* defaultValue, [[maybe_unused]] const AZ::Uuid& valueTypeId,
AZ::JsonSerializerContext& context)
{
namespace JSR = AZ::JsonSerializationResult;

@ -17,7 +17,6 @@
#include <GradientSignal/Editor/EditorGradientComponentBase.h>
#include <Vegetation/Editor/EditorVegetationComponentTypeIds.h>
#include <LmbrCentral/Component/EditorWrappedComponentBase.h>
#include <CrySystemBus.h>
namespace Vegetation
{
@ -28,7 +27,6 @@ namespace Vegetation
template<typename TComponent, typename TConfiguration>
class EditorVegetationComponentBase
: public LmbrCentral::EditorWrappedComponentBase<TComponent, TConfiguration>
, private CrySystemEventBus::Handler
{
public:
using BaseClassType = LmbrCentral::EditorWrappedComponentBase<TComponent, TConfiguration>;
@ -48,11 +46,6 @@ namespace Vegetation
static void Reflect(AZ::ReflectContext* context);
////////////////////////////////////////////////////////////////////////////
// CrySystemEvents
void OnCryEditorBeginLevelExport() override;
void OnCryEditorEndLevelExport(bool /*success*/) override;
protected:
using BaseClassType::m_configuration;
using BaseClassType::m_component;

@ -12,24 +12,6 @@
namespace Vegetation
{
template<typename TComponent, typename TConfiguration>
void EditorVegetationComponentBase<TComponent, TConfiguration>::OnCryEditorEndLevelExport(bool /*success*/)
{
// Restore the activation state of our components after the export is complete.
if (m_visible)
{
m_component.Activate();
}
}
template<typename TComponent, typename TConfiguration>
void EditorVegetationComponentBase<TComponent, TConfiguration>::OnCryEditorBeginLevelExport()
{
// We need to deactivate our game components at the start of level exports because any vegetation meshes that are loaded
// or instances that are spawned can end up in our static vegetation level data.
m_component.Deactivate();
}
template<typename TComponent, typename TConfiguration>
AZ::u32 EditorVegetationComponentBase<TComponent, TConfiguration>::ConfigurationChanged()
{
@ -69,13 +51,11 @@ namespace Vegetation
{
GradientSignal::SetSamplerOwnerEntity(m_configuration, GetEntityId());
BaseClassType::Activate();
CrySystemEventBus::Handler::BusConnect();
}
template<typename TComponent, typename TConfiguration>
void EditorVegetationComponentBase<TComponent, TConfiguration>::Deactivate()
{
CrySystemEventBus::Handler::BusDisconnect();
BaseClassType::Deactivate();
}

@ -1,3 +0,0 @@
version https://git-lfs.github.com/spec/v1
oid sha256:f2a70cf9523c07263261bb2a912f656609419318e680611ccc8e2652c2f5ec0a
size 410840

@ -1,3 +0,0 @@
version https://git-lfs.github.com/spec/v1
oid sha256:69c699ebfb1f4ffe241b047499d0f52292112b38783d08eb50ccfeb97f76c91a
size 3145784

@ -1,3 +0,0 @@
version https://git-lfs.github.com/spec/v1
oid sha256:e2519313a259f6df040e17ce27cffc3c96a2c8616aeeffd3899481ab52efd41f
size 3145784

@ -1,3 +0,0 @@
version https://git-lfs.github.com/spec/v1
oid sha256:9d76c75c2b18850a091f9787ee4ac684a648d8dea0bcc8141f4e895942428fd4
size 3145784

@ -1,3 +0,0 @@
version https://git-lfs.github.com/spec/v1
oid sha256:3c22f26d5921218882dbe7d55deb9f4e33744a34eb02804efb44998f7299afb6
size 3145784

@ -1,3 +0,0 @@
version https://git-lfs.github.com/spec/v1
oid sha256:3841e927bb9a411af5287e1f69c68ad6fbcfefc4ed4696ee58ab80f6554e4b3e
size 12602708

@ -1 +0,0 @@
/autooptimizefile=0 /M=50,50,0,50,50,50 /preset=Albedo /reduce=0

@ -1,16 +0,0 @@
<Material MtlFlags="524544" vertModifType="0">
<SubMaterials>
<Material Name="AM_Barrel_01_M" MtlFlags="524416" Shader="Illum" GenMask="4001010000001" StringGenMask="%ALLOW_SILHOUETTE_POM%NORMAL_MAP%SPECULAR_MAP%SUBSURFACE_SCATTERING" SurfaceType="mat_metal" Diffuse="1,1,1,1" Specular="1,1,1,1" Opacity="1" Shininess="255" vertModifType="0" LayerAct="1">
<Textures>
<Texture Map="Diffuse" File="Objects/ManMade/Props/Barrel/AM_Barrel_01_Diff.tif"/>
<Texture Map="Bumpmap" File="objects/manmade/props/barrel/am_barrel_01_ddna.dds"/>
<Texture Map="Specular" File="objects/manmade/props/barrel/am_barrel_01_spec.dds"/>
</Textures>
<PublicParams EmittanceMapGamma="1" SSSIndex="0" IndirectColor="0.25,0.25,0.25"/>
</Material>
<Material Name="Proxy_COL" MtlFlags="525440" Shader="Nodraw" GenMask="0" StringGenMask="" SurfaceType="mat_metal" Diffuse="0.5,0.5,0.5,1" Specular="0,0,0,1" Opacity="1" Shininess="10" vertModifType="0" LayerAct="1">
<Textures />
</Material>
</SubMaterials>
<PublicParams EmittanceMapGamma="1" SSSIndex="0" IndirectColor="0.25,0.25,0.25"/>
</Material>

@ -1,3 +0,0 @@
version https://git-lfs.github.com/spec/v1
oid sha256:c318de8b5e831429c0852043df2b496ea360f7e7a16a09728057e936b5f9d82f
size 16797014

@ -1 +0,0 @@
/autooptimizefile=0 /M=50,50,0,50,50,50 /preset=NormalsWithSmoothness /reduce=0

@ -1,3 +0,0 @@
version https://git-lfs.github.com/spec/v1
oid sha256:7a64b6827e7f837f35d802433419ad88b196ea99ed97215cdee4d77009584152
size 3157332

@ -1,3 +0,0 @@
version https://git-lfs.github.com/spec/v1
oid sha256:45ab25afac85d92c63c939cea3086545975412a81d2c1d03210a9c4c0a57b8ab
size 12602708

@ -1,3 +0,0 @@
version https://git-lfs.github.com/spec/v1
oid sha256:f582c61b53f2bde096345e6a1dbbfb70fabbe05aaa96f5f560885acbc2ecb76c
size 111276

@ -1,16 +0,0 @@
<Material MtlFlags="524544" vertModifType="0">
<SubMaterials>
<Material Name="AM_Barrel_01_M" MtlFlags="524416" Shader="Illum" GenMask="4001010000001" StringGenMask="%ALLOW_SILHOUETTE_POM%NORMAL_MAP%SPECULAR_MAP%SUBSURFACE_SCATTERING" SurfaceType="mat_metal" Diffuse="1,1,1,1" Specular="1,1,1,1" Opacity="1" Shininess="255" vertModifType="0" LayerAct="1">
<Textures>
<Texture Map="Diffuse" File="objects/manmade/props/barrel/am_barrel_02_diff.dds"/>
<Texture Map="Bumpmap" File="objects/manmade/props/barrel/am_barrel_01_ddna.dds"/>
<Texture Map="Specular" File="objects/manmade/props/barrel/am_barrel_01_spec.dds"/>
</Textures>
<PublicParams EmittanceMapGamma="1" SSSIndex="0" IndirectColor="0.25,0.25,0.25"/>
</Material>
<Material Name="Proxy_COL" MtlFlags="525440" Shader="Nodraw" GenMask="0" StringGenMask="" SurfaceType="mat_metal" Diffuse="0.5,0.5,0.5,1" Specular="0,0,0,1" Opacity="1" Shininess="10" vertModifType="0" LayerAct="1">
<Textures />
</Material>
</SubMaterials>
<PublicParams EmittanceMapGamma="1" SSSIndex="0" IndirectColor="0.25,0.25,0.25"/>
</Material>

@ -1,18 +0,0 @@
<Material MtlFlags="524544" vertModifType="0">
<SubMaterials>
<Material Name="AM_Rock_Boulder_01_Mat" MtlFlags="524416" Shader="Illum" GenMask="4000010000041" StringGenMask="%ALLOW_SILHOUETTE_POM%DETAIL_MAPPING%NORMAL_MAP%SUBSURFACE_SCATTERING" SurfaceType="mat_rock" Diffuse="1,1,1,1" Specular="0.03954624,0.03954624,0.03954624,1" Opacity="1" Shininess="255" vertModifType="0" LayerAct="1">
<Textures>
<Texture Map="Diffuse" File="Objects/Natural/Rocks/AM_Rock_Boulder_01_diff.tif"/>
<Texture Map="Bumpmap" File="objects/natural/rocks/am_rock_boulder_01_ddna.dds"/>
<Texture Map="Detail" File="objects/natural/rocks/rock03_detail.dds">
<TexMod TexMod_RotateType="0" TexMod_TexGenType="0" TexMod_bTexGenProjected="0" TileU="4" TileV="4"/>
</Texture>
</Textures>
<PublicParams EmittanceMapGamma="1" DetailDiffuseScale="0.5" SSSIndex="0" DetailBumpScale="0" DetailGlossScale="0.5" IndirectColor="0.25,0.25,0.25"/>
</Material>
<Material Name="AM_Rock_Boulder_01_Proxy_Mat" MtlFlags="525440" Shader="Nodraw" GenMask="0" StringGenMask="" SurfaceType="mat_rock" Diffuse="0.5,0.5,0.5,1" Specular="0,0,0,1" Opacity="1" Shininess="10" vertModifType="0" LayerAct="1">
<Textures />
</Material>
</SubMaterials>
<PublicParams EmittanceMapGamma="1" SSSIndex="0" IndirectColor="0.25,0.25,0.25"/>
</Material>

@ -1,3 +0,0 @@
version https://git-lfs.github.com/spec/v1
oid sha256:70148ec39ccbbb05bc3c5df8857fbbdc1ee455574b4a141e4d6ceb78aacd6c76
size 16797012

@ -1,3 +0,0 @@
version https://git-lfs.github.com/spec/v1
oid sha256:7da1eab71d64b032264f1cb3b1b8b768496c56c90d057e42183b6dcfe9d1ada9
size 12602706

@ -1 +0,0 @@
/autooptimizefile=0 /M=50,50,0,50,50,50 /preset=AlbedoWithGenericAlpha /reduce=0

@ -1,3 +0,0 @@
version https://git-lfs.github.com/spec/v1
oid sha256:26c78881443d317e708efaa2266fe6c0e2a52d04109887c408cf539e31a3aed2
size 16797018

@ -1,18 +0,0 @@
<Material MtlFlags="524544" vertModifType="0">
<SubMaterials>
<Material Name="AM_Rock_Cliff_01_mat" MtlFlags="524416" Shader="Illum" GenMask="4000010000045" StringGenMask="%ALLOW_SILHOUETTE_POM%ALPHAMASK_DETAILMAP%DETAIL_MAPPING%NORMAL_MAP%SUBSURFACE_SCATTERING" SurfaceType="mat_rock" Diffuse="0.83879912,0.79910284,0.76052463,1" Specular="0.03954624,0.03954624,0.03954624,1" Opacity="1" Shininess="255" vertModifType="0" LayerAct="1">
<Textures>
<Texture Map="Diffuse" File="Objects/Natural/Rocks/Rock_Cliff_01_diff.tif"/>
<Texture Map="Bumpmap" File="objects/natural/rocks/rock_cliff_01_ddna.dds"/>
<Texture Map="Detail" File="objects/natural/rocks/rock03_detail.dds">
<TexMod TexMod_RotateType="0" TexMod_TexGenType="0" TexMod_bTexGenProjected="0" TileU="16" TileV="16"/>
</Texture>
</Textures>
<PublicParams EmittanceMapGamma="1" DetailDiffuseScale="0.5" SSSIndex="0" DetailBumpScale="0" DetailGlossScale="0" IndirectColor="0.25,0.25,0.25"/>
</Material>
<Material Name="AM_Rock_Cliff_01_Proxy_mat" MtlFlags="525440" Shader="Nodraw" GenMask="0" StringGenMask="" SurfaceType="mat_rock" Diffuse="0.5,0.5,0.5,1" Specular="0,0,0,1" Opacity="1" Shininess="10" vertModifType="0" LayerAct="1">
<Textures />
</Material>
</SubMaterials>
<PublicParams EmittanceMapGamma="1" SSSIndex="0" IndirectColor="0.25,0.25,0.25"/>
</Material>

@ -1,18 +0,0 @@
<Material MtlFlags="524544" vertModifType="0">
<SubMaterials>
<Material Name="AM_Rock_Cliff_02_Mat" MtlFlags="524416" Shader="Illum" GenMask="4000010000045" StringGenMask="%ALLOW_SILHOUETTE_POM%ALPHAMASK_DETAILMAP%DETAIL_MAPPING%NORMAL_MAP%SUBSURFACE_SCATTERING" SurfaceType="mat_rock" Diffuse="0.83879912,0.79910284,0.76052463,1" Specular="0.03954624,0.03954624,0.03954624,1" Opacity="1" Shininess="255" vertModifType="0" LayerAct="1">
<Textures>
<Texture Map="Diffuse" File="objects/natural/rocks/am_rock_cliff_02_diff.dds"/>
<Texture Map="Bumpmap" File="objects/natural/rocks/am_rock_cliff_02_ddna.dds"/>
<Texture Map="Detail" File="objects/natural/rocks/rock03_detail.dds">
<TexMod TexMod_RotateType="0" TexMod_TexGenType="0" TexMod_bTexGenProjected="0" TileU="16" TileV="16"/>
</Texture>
</Textures>
<PublicParams EmittanceMapGamma="1" DetailDiffuseScale="0.5" SSSIndex="0" DetailBumpScale="0" DetailGlossScale="0" IndirectColor="0.25,0.25,0.25"/>
</Material>
<Material Name="AM_Rock_Cliff_02_proxy_Mat" MtlFlags="525440" Shader="Nodraw" GenMask="0" StringGenMask="" SurfaceType="mat_rock" Diffuse="0.5,0.5,0.5,1" Specular="0.5,0.5,0.5,1" Opacity="1" Shininess="10" vertModifType="0" LayerAct="1">
<Textures />
</Material>
</SubMaterials>
<PublicParams EmittanceMapGamma="1" SSSIndex="0" IndirectColor="0.25,0.25,0.25"/>
</Material>

@ -1,3 +0,0 @@
version https://git-lfs.github.com/spec/v1
oid sha256:960fcf7aa076eae6578e40bd566b0bc978f77899f87de2b3a4306568e9eb5f10
size 67145042

@ -1 +0,0 @@
/autooptimizefile=0 /M=50,50,0,50,50,50 /preset=NormalsWithSmoothness /reduce=0

@ -1,3 +0,0 @@
version https://git-lfs.github.com/spec/v1
oid sha256:bb9f5e3093ee1e19dc4bae286d4e34ae2095a3e70dbd02b64343fdb7e75ff897
size 67145042

@ -1 +0,0 @@
/autooptimizefile=0 /M=50,50,0,50,50,50 /preset=AlbedoWithGenericAlpha /reduce=0

@ -1,3 +0,0 @@
version https://git-lfs.github.com/spec/v1
oid sha256:c484e208ee7bdda60ef6ffeba1e6c523596ad9fd36cf24ac424baaf06c57cca9
size 67145048

@ -1,3 +0,0 @@
version https://git-lfs.github.com/spec/v1
oid sha256:046b2105e45016bad314e8ad4ed3800018f60ea218bf33b2637554c0efd1c0b5
size 16797016

@ -1,3 +0,0 @@
version https://git-lfs.github.com/spec/v1
oid sha256:a4285c8231bde77d1dbc9cbce60ee4a35a566f75cb96cb4279f1c1098a6fd5c3
size 67145054

@ -1,3 +0,0 @@
version https://git-lfs.github.com/spec/v1
oid sha256:fd21e1c93650c69e841a5a87812a6937f77d9ae44c7f28bf37567a314e27d7d6
size 67145058

@ -1,3 +0,0 @@
version https://git-lfs.github.com/spec/v1
oid sha256:45630fa430865bea236013ea2c6c91966ced24d51bdf791d04a5ba71d76dae69
size 67145058

@ -1,3 +0,0 @@
version https://git-lfs.github.com/spec/v1
oid sha256:cecb571c673a412031a64e704122ac6eef77bd66005e26b767edd8c28037e11e
size 67145048

@ -1 +0,0 @@
/autooptimizefile=0 /M=50,50,0,50,0,50 /preset=NormalsWithSmoothness /reduce=0

@ -1,3 +0,0 @@
version https://git-lfs.github.com/spec/v1
oid sha256:0e0da4f69d5496bb3329b4bd4e5e32bceacf98d6e2eb6af1771812a225b241a7
size 67145048

@ -1 +0,0 @@
/autooptimizefile=0 /M=50,50,0,50,50,50 /preset=AlbedoWithGenericAlpha /reduce=0

@ -1,18 +0,0 @@
<Material MtlFlags="524544" vertModifType="0">
<SubMaterials>
<Material Name="AM_Rock_Flat_Multi_01_mat" MtlFlags="524416" Shader="Illum" GenMask="4000010000045" StringGenMask="%ALLOW_SILHOUETTE_POM%ALPHAMASK_DETAILMAP%DETAIL_MAPPING%NORMAL_MAP%SUBSURFACE_SCATTERING" SurfaceType="mat_rock" Diffuse="0.83879912,0.79910284,0.76052463,1" Specular="0.03954624,0.03954624,0.03954624,1" Opacity="1" Shininess="255" vertModifType="0" LayerAct="1">
<Textures>
<Texture Map="Diffuse" File="objects/natural/rocks/am_rock_flat_multi_01_diff.dds"/>
<Texture Map="Bumpmap" File="objects/natural/rocks/am_rock_flat_multi_01_ddna.dds"/>
<Texture Map="Detail" File="objects/natural/rocks/rock03_detail.dds">
<TexMod TexMod_RotateType="0" TexMod_TexGenType="0" TexMod_bTexGenProjected="0" TileU="12" TileV="12"/>
</Texture>
</Textures>
<PublicParams EmittanceMapGamma="1" DetailDiffuseScale="0.5" SSSIndex="0" DetailBumpScale="0" DetailGlossScale="0" IndirectColor="0.24620135,0.24620135,0.24620135"/>
</Material>
<Material Name="AM_Rock_Flat_01_proxy_mat" MtlFlags="525440" Shader="Nodraw" GenMask="0" StringGenMask="" SurfaceType="mat_rock" Diffuse="0.5,0.5,0.5,1" Specular="0.5,0.5,0.5,1" Opacity="1" Shininess="10" vertModifType="0" LayerAct="1">
<Textures />
</Material>
</SubMaterials>
<PublicParams EmittanceMapGamma="1" SSSIndex="0" IndirectColor="0.25,0.25,0.25"/>
</Material>

@ -1,18 +0,0 @@
<Material MtlFlags="524544" vertModifType="0">
<SubMaterials>
<Material Name="AM_Rock_Flat_Multi_02_M" MtlFlags="524416" Shader="Illum" GenMask="4000010000041" StringGenMask="%ALLOW_SILHOUETTE_POM%DETAIL_MAPPING%NORMAL_MAP%SUBSURFACE_SCATTERING" SurfaceType="mat_rock" Diffuse="0.85499275,0.81484669,0.78353792,1" Specular="0.03954624,0.03954624,0.03954624,1" Opacity="1" Shininess="255" vertModifType="0" LayerAct="1">
<Textures>
<Texture Map="Diffuse" File="objects/natural/rocks/am_rock_flat_multi_02_diff.dds"/>
<Texture Map="Bumpmap" File="objects/natural/rocks/am_rock_flat_multi_02_ddna.dds"/>
<Texture Map="Detail" File="objects/natural/rocks/rock03_detail.dds">
<TexMod TexMod_RotateType="0" TexMod_TexGenType="0" TexMod_bTexGenProjected="0" TileU="4" TileV="4"/>
</Texture>
</Textures>
<PublicParams EmittanceMapGamma="1" DetailDiffuseScale="0.72500002" SSSIndex="0" DetailBumpScale="0" DetailGlossScale="0.5" IndirectColor="0.25,0.25,0.25"/>
</Material>
<Material Name="COL_Proxy" MtlFlags="525440" Shader="Nodraw" GenMask="0" StringGenMask="" SurfaceType="mat_rock" Diffuse="0.5,0.5,0.5,1" Specular="0.5,0.5,0.5,1" Opacity="1" Shininess="10" vertModifType="0" LayerAct="1">
<Textures />
</Material>
</SubMaterials>
<PublicParams EmittanceMapGamma="1" SSSIndex="0" IndirectColor="0.25,0.25,0.25"/>
</Material>

@ -1,3 +0,0 @@
version https://git-lfs.github.com/spec/v1
oid sha256:dfce23f8a59c8ef97dc9d8bdeb81072fc5300bff3c11735f65b7f78652f93cd4
size 16797016

@ -1 +0,0 @@
/autooptimizefile=0 /M=50,50,0,50,50,50 /preset=NormalsWithSmoothness /reduce=0

@ -1,3 +0,0 @@
version https://git-lfs.github.com/spec/v1
oid sha256:b157eab497ef89c8f575f039b6da5b3c43a9fea06b2e6c2335ee1347357b49e3
size 12602710

@ -1 +0,0 @@
/autooptimizefile=0 /M=50,50,0,50,50,50 /preset=Albedo /reduce=0

@ -1,3 +0,0 @@
version https://git-lfs.github.com/spec/v1
oid sha256:0f9378510d3f75fa80a5ca5884f1ad9e20852c5eb88d6e10d74238c89dbda208
size 16797012

@ -1 +0,0 @@
/autooptimizefile=0 /M=50,0,50,0,0,50 /preset=NormalsWithSmoothness /reduce=0

@ -1,3 +0,0 @@
version https://git-lfs.github.com/spec/v1
oid sha256:117d37d86b808768d74f70a522e66a76a6ffc71ceb5858e901a3f5191994d92b
size 12602706

@ -1 +0,0 @@
/autooptimizefile=0 /M=50,0,0,50,50,50 /preset=AlbedoWithGenericAlpha /reduce=0

@ -1,18 +0,0 @@
<Material MtlFlags="524544" vertModifType="0">
<SubMaterials>
<Material Name="AM_Rock_Square_01_mat" MtlFlags="524416" Shader="Illum" GenMask="4000010000041" StringGenMask="%ALLOW_SILHOUETTE_POM%DETAIL_MAPPING%NORMAL_MAP%SUBSURFACE_SCATTERING" SurfaceType="mat_rock" Diffuse="1,1,1,1" Specular="0.03954624,0.03954624,0.03954624,1" Opacity="1" Shininess="180" vertModifType="0" LayerAct="1">
<Textures>
<Texture Map="Diffuse" File="objects/natural/rocks/am_rock_square_01_diff.dds"/>
<Texture Map="Bumpmap" File="objects/natural/rocks/am_rock_square_01_ddna.dds"/>
<Texture Map="Detail" File="objects/natural/rocks/rock03_detail.dds">
<TexMod TexMod_RotateType="0" TexMod_TexGenType="0" TexMod_bTexGenProjected="0" TileU="8" TileV="8"/>
</Texture>
</Textures>
<PublicParams EmittanceMapGamma="1" DetailDiffuseScale="0.5" SSSIndex="0" DetailBumpScale="0" DetailGlossScale="0.5" IndirectColor="0.25,0.25,0.25"/>
</Material>
<Material Name="AM_Rock_Square_01_proxy_mat" MtlFlags="525440" Shader="Nodraw" GenMask="0" StringGenMask="" SurfaceType="mat_rock" Diffuse="0.5,0.5,0.5,1" Specular="0.5,0.5,0.5,1" Opacity="1" Shininess="10" vertModifType="0" LayerAct="1">
<Textures />
</Material>
</SubMaterials>
<PublicParams EmittanceMapGamma="1" SSSIndex="0" IndirectColor="0.25,0.25,0.25"/>
</Material>

@ -1,3 +0,0 @@
version https://git-lfs.github.com/spec/v1
oid sha256:10b24991a5042c283f7af1a75360d0d9ad78384c6c4eadf99340506e253c8762
size 16797012

@ -1 +0,0 @@
/autooptimizefile=0 /M=50,0,0,0,0,50 /preset=NormalsWithSmoothness /reduce=0

@ -1,3 +0,0 @@
version https://git-lfs.github.com/spec/v1
oid sha256:6909db9fd61da354c863b1f8d6abb6f504f47b79515410b4c1337d5d5c06a69b
size 12602706

@ -1 +0,0 @@
/autooptimizefile=0 /M=50,0,0,50,50,50 /preset=Albedo /reduce=0

@ -1,18 +0,0 @@
<Material MtlFlags="524544" vertModifType="0">
<SubMaterials>
<Material Name="AM_Rock_Square_02_mat" MtlFlags="524416" Shader="Illum" GenMask="4000010000041" StringGenMask="%ALLOW_SILHOUETTE_POM%DETAIL_MAPPING%NORMAL_MAP%SUBSURFACE_SCATTERING" SurfaceType="mat_rock" Diffuse="0.86315733,0.82278591,0.80695242,1" Specular="0.03954624,0.03954624,0.03954624,1" Opacity="1" Shininess="120" vertModifType="0" LayerAct="1">
<Textures>
<Texture Map="Diffuse" File="objects/natural/rocks/am_rock_square_02_diff.dds"/>
<Texture Map="Bumpmap" File="objects/natural/rocks/am_rock_square_02_ddna.dds"/>
<Texture Map="Detail" File="objects/natural/rocks/rock03_detail.dds">
<TexMod TexMod_RotateType="0" TexMod_TexGenType="0" TexMod_bTexGenProjected="0" TileU="6" TileV="6"/>
</Texture>
</Textures>
<PublicParams EmittanceMapGamma="1" DetailDiffuseScale="0.5" SSSIndex="0" DetailBumpScale="0" DetailGlossScale="0.5" IndirectColor="0.25,0.25,0.25"/>
</Material>
<Material Name="AM_Rock_Square_02_proxy_mat" MtlFlags="525440" Shader="Nodraw" GenMask="0" StringGenMask="" SurfaceType="mat_rock" Diffuse="0.5,0.5,0.5,1" Specular="0.5,0.5,0.5,1" Opacity="1" Shininess="10" vertModifType="0" LayerAct="1">
<Textures />
</Material>
</SubMaterials>
<PublicParams EmittanceMapGamma="1" SSSIndex="0" IndirectColor="0.25,0.25,0.25"/>
</Material>

@ -1,3 +0,0 @@
version https://git-lfs.github.com/spec/v1
oid sha256:94e30359c97338d4edeaeab700596993f20fa434606af4fcaa29d8ae1be7c781
size 852132

@ -1,24 +0,0 @@
<Material MtlFlags="524544" >
<SubMaterials>
<Material Name="AM_Rock_Square_01_mat" MtlFlags="524416" Shader="Illum" GenMask="4000010000041" StringGenMask="%ALLOW_SILHOUETTE_POM%DETAIL_MAPPING%NORMAL_MAP%SUBSURFACE_SCATTERING" SurfaceType="mat_rock" Diffuse="1,1,1,1" Specular="0.03954624,0.03954624,0.03954624,1" Opacity="1" Shininess="180" vertModifType="0" LayerAct="1">
<Textures>
<Texture Map="Diffuse" File="objects/natural/rocks/am_rock_square_01_diff.dds"/>
<Texture Map="Bumpmap" File="objects/natural/rocks/am_rock_square_01_ddna.dds"/>
<Texture Map="Detail" File="objects/natural/rocks/rock03_detail.dds">
<TexMod TexMod_RotateType="0" TexMod_TexGenType="0" TexMod_bTexGenProjected="0" TileU="8" TileV="8"/>
</Texture>
</Textures>
<PublicParams EmittanceMapGamma="1" DetailDiffuseScale="0.5" SSSIndex="0" DetailBumpScale="0" DetailGlossScale="0.5" IndirectColor="0.25,0.25,0.25"/>
</Material>
<Material Name="AM_Rock_Square_02_mat" MtlFlags="524416" Shader="Illum" GenMask="4000010000041" StringGenMask="%ALLOW_SILHOUETTE_POM%DETAIL_MAPPING%NORMAL_MAP%SUBSURFACE_SCATTERING" SurfaceType="mat_rock" Diffuse="0.86315733,0.82278591,0.80695242,1" Specular="0.03954624,0.03954624,0.03954624,1" Opacity="1" Shininess="120" vertModifType="0" LayerAct="1">
<Textures>
<Texture Map="Diffuse" File="objects/natural/rocks/am_rock_square_02_diff.dds"/>
<Texture Map="Bumpmap" File="objects/natural/rocks/am_rock_square_02_ddna.dds"/>
<Texture Map="Detail" File="objects/natural/rocks/rock03_detail.dds">
<TexMod TexMod_RotateType="0" TexMod_TexGenType="0" TexMod_bTexGenProjected="0" TileU="6" TileV="6"/>
</Texture>
</Textures>
<PublicParams EmittanceMapGamma="1" DetailDiffuseScale="0.5" SSSIndex="0" DetailBumpScale="0" DetailGlossScale="0.5" IndirectColor="0.25,0.25,0.25"/>
</Material>
</SubMaterials>
</Material>

@ -1,3 +0,0 @@
version https://git-lfs.github.com/spec/v1
oid sha256:20545079f3e0a61cc144a161999753996797a090f285d63f1c6b1ac1a050729b
size 24956

@ -1,3 +0,0 @@
version https://git-lfs.github.com/spec/v1
oid sha256:2cb13a66c6d06e7cd5f06eb05f45c817db0dc76c64afde5225213f742bc0cf40
size 1056084

@ -1,3 +0,0 @@
version https://git-lfs.github.com/spec/v1
oid sha256:de80f21e0f6d48e3894fcf309f2564e1b74be0a65e415506034ff144b051bc74
size 3157330

@ -1 +0,0 @@
/autooptimizefile=0 /M=50,50,0,50,50,50 /preset=Albedo /reduce=0

@ -1,12 +0,0 @@
<Material MtlFlags="524544" vertModifType="0">
<SubMaterials>
<Material Name="AM_Rocks_Small_02_Mat" MtlFlags="524416" Shader="Illum" GenMask="4000010000001" StringGenMask="%ALLOW_SILHOUETTE_POM%NORMAL_MAP%SUBSURFACE_SCATTERING" SurfaceType="mat_rock" Diffuse="1,1,1,1" Specular="0.03954624,0.03954624,0.03954624,1" Opacity="1" Shininess="255" vertModifType="0" LayerAct="1">
<Textures>
<Texture Map="Diffuse" File="objects/natural/rocks/am_rocks_small_02_diff.dds"/>
<Texture Map="Bumpmap" File="objects/natural/rocks/am_rocks_small_02_ddna.dds"/>
</Textures>
<PublicParams EmittanceMapGamma="1" SSSIndex="0" IndirectColor="0.25,0.25,0.25"/>
</Material>
</SubMaterials>
<PublicParams EmittanceMapGamma="1" SSSIndex="0" IndirectColor="0.25,0.25,0.25"/>
</Material>

@ -1,3 +0,0 @@
version https://git-lfs.github.com/spec/v1
oid sha256:c2c2f43f48f2b661f69b955e7009006a6aa616a25131b4b5e9a5017ac6b18193
size 1056084

@ -1,3 +0,0 @@
version https://git-lfs.github.com/spec/v1
oid sha256:51ba30ea6a9749edf269e3d22a0eb73ebc4589f87f1d207166cb0f5ad1201a45
size 793938

@ -1,12 +0,0 @@
<Material MtlFlags="524544" vertModifType="0">
<SubMaterials>
<Material Name="AM_Rocks_Small_02" MtlFlags="524416" Shader="Illum" GenMask="4000010000001" StringGenMask="%ALLOW_SILHOUETTE_POM%NORMAL_MAP%SUBSURFACE_SCATTERING" SurfaceType="mat_rock" Diffuse="1,1,1,1" Specular="0.03954624,0.03954624,0.03954624,1" Opacity="1" Shininess="255" vertModifType="0" LayerAct="1">
<Textures>
<Texture Map="Diffuse" File="objects/natural/rocks/am_rocks_small_01_diff.dds"/>
<Texture Map="Bumpmap" File="objects/natural/rocks/am_rocks_small_01_ddna.dds"/>
</Textures>
<PublicParams EmittanceMapGamma="1" SSSIndex="0" IndirectColor="0.25,0.25,0.25"/>
</Material>
</SubMaterials>
<PublicParams EmittanceMapGamma="1" SSSIndex="0" IndirectColor="0.25,0.25,0.25"/>
</Material>

@ -1,17 +0,0 @@
<Material MtlFlags="524544" vertModifType="0">
<SubMaterials>
<Material Name="AM_Rocks_Small_ShinyM" MtlFlags="524416" Shader="Illum" GenMask="12000020040002" StringGenMask="%ALLOW_SPECULAR_ANTIALIASING%EMITTANCE_MAP%NORMAL_MAP%SPECULAR_MAP%SUBSURFACE_SCATTERING" SurfaceType="mat_default" Diffuse="0.39157251,0.3467041,0.31398875,1" Specular="0.65140575,0.5332765,0.49102089,1" Opacity="1" Shininess="255" vertModifType="0" LayerAct="1">
<Textures>
<Texture Map="Diffuse" File="objects/natural/rocks/am_rocks_small_02_diff.dds"/>
<Texture Map="Bumpmap" File="objects/natural/rocks/am_rocks_small_shiny_ddna.dds"/>
<Texture Map="Specular" File="objects/natural/rocks/am_rocks_small_shiny_diff.dds" Filter="0" IsTileU="0" IsTileV="0" TexType="0"/>
<Texture Map="Smoothness" File="objects/natural/rocks/am_rocks_small_shiny_ddna.dds"/>
<Texture Map="Heightmap" File="textures/natural/terrain/am_rockground_displ.dds">
<TexMod TexMod_RotateType="0" TexMod_TexGenType="0" TexMod_bTexGenProjected="0" TileU="0.25" TileV="0.25"/>
</Texture>
</Textures>
<PublicParams EmittanceMapGamma="1" SSSIndex="0" IndirectColor="0.25,0.25,0.25"/>
</Material>
</SubMaterials>
<PublicParams EmittanceMapGamma="1" SSSIndex="0" IndirectColor="0.25,0.25,0.25"/>
</Material>

@ -1,3 +0,0 @@
version https://git-lfs.github.com/spec/v1
oid sha256:dda8085556f470dc023e20f6d26c7ea4a5a47ed486db90050e31dfe7838d18dd
size 1056058

@ -1,3 +0,0 @@
version https://git-lfs.github.com/spec/v1
oid sha256:37866b8a07a89274c76b53a545076fa0be9071b2fea21787b3c7890f8fa6d303
size 793912

@ -1,3 +0,0 @@
version https://git-lfs.github.com/spec/v1
oid sha256:21cde0da4644e3153946411ea409e4632ba523b69b0fc681a3b09f523089181e
size 12602664

@ -1 +0,0 @@
/autooptimizefile=0 /M=50,50,0,50,50,50 /mipgentype=sigma-six /preset=Detail_MergedAlbedoNormalsSmoothness /reduce=0

@ -1,3 +0,0 @@
version https://git-lfs.github.com/spec/v1
oid sha256:5d4d82f4b0f24f608d5e4dbdab6fa71709cbaa0413cc3523eaae0ec3cefcf529
size 67145040

@ -1 +0,0 @@
/autooptimizefile=0 /M=50,0,0,50,50,50 /preset=NormalsWithSmoothness /reduce=0

Some files were not shown because too many files have changed in this diff Show More

Loading…
Cancel
Save