Refactored how model material slots work in preparation to support more flexible material conversion options for the scene asset pipeline. The material slot IDs are based on the MaterialUid that come from SceneAPI. Since these IDs are also used as the AssetId sub-ID for the converted material assets, the system was just checking the material asset sub-ID to determine the material slot ID. But in order to support certain FBX material conversion options, we needed to break this tie, so the slot ID is separate from the AssetId of the material in that slot. This will allow some other material to be used in the slot, instead of being forced to use one that was generated from the FBX.

Here we inttroduce a new struct ModelMaterialSlot which formalizes the concept of material slot, with an ID, display name, and default material assignment. The ID still comes from the MaterialUid like before. The display name is built-in, rather than being parsed out from the asset file name. And the default material assignment can be any material asset, it doesn't have to come from the FBX (or other scene file).

This commit is just the preliminary set of changes. Cursory testing shows that it works pretty well but more testing is needed (and likely some fixes) before merging.

Here is what's left to do...
Add serialization version converters to preserve prior prefab data.
See if we can get rid of GetLabelByAssetId function only rely on the display name inside ModelMaterialSlot.
I'm not sure if the condition for enabling the "Edit Material Instance..." context menu item is correct.
Test actors
Lots more testing in general

Signed-off-by: santorac <55155825+santorac@users.noreply.github.com>
This commit is contained in:
Chris Santora
2021-07-17 00:07:23 -07:00
committed by santorac
parent 0cf6ecf3f7
commit 14d2e38b90
31 changed files with 399 additions and 195 deletions
@@ -72,6 +72,8 @@ namespace AZ
RHI::IndexBufferView m_indexBufferView;
StreamInfoList m_streamInfo;
ModelMaterialSlot::StableId m_materialSlotStableId = ModelMaterialSlot::InvalidStableId;
//! The default material assigned to the mesh by the asset.
Data::Instance<Material> m_material;
@@ -49,6 +49,9 @@ namespace AZ
//! Returns the model-space axis aligned bounding box
const AZ::Aabb& GetAabb() const;
//! Returns the list of all ModelMaterialSlot's for the model, across all LODs.
RPI::ModelMaterialSlotMap GetModelMaterialSlots() const;
//! Returns the number of Lods in the model
size_t GetLodCount() const;
@@ -16,6 +16,7 @@
#include <Atom/RPI.Reflect/Buffer/BufferAssetView.h>
#include <Atom/RPI.Reflect/Buffer/BufferAsset.h>
#include <Atom/RPI.Reflect/Material/MaterialAsset.h>
#include <Atom/RPI.Reflect/Model/ModelMaterialSlot.h>
#include <AzCore/Asset/AssetCommon.h>
#include <AzCore/Math/Aabb.h>
@@ -84,8 +85,9 @@ namespace AZ
//! Returns the number of indices in this mesh
uint32_t GetIndexCount() const;
//! Returns the reference to material asset used by this mesh
const Data::Asset <MaterialAsset>& GetMaterialAsset() const;
//! Returns the index of the material slot used by this mesh.
//! This indexes into the ModelLodAsset's material slot list.
size_t GetMaterialSlotIndex() const;
//! Returns the name of this mesh
const AZ::Name& GetName() const;
@@ -124,7 +126,9 @@ namespace AZ
AZ::Name m_name;
AZ::Aabb m_aabb = AZ::Aabb::CreateNull();
Data::Asset<MaterialAsset> m_materialAsset{ Data::AssetLoadBehavior::PreLoad };
// Identifies the material that is used by this mesh.
// References material slot in the ModelLodAsset that owns this mesh; see ModelLodAsset::GetMaterialSlot().
size_t m_materialSlotIndex = 0;
// Both the buffer in m_indexBufferAssetView and the buffers in m_streamBufferInfo
// may point to either unique buffers for the mesh or to consolidated
@@ -143,11 +147,21 @@ namespace AZ
//! Returns the model-space axis-aligned bounding box of all meshes in the lod
const AZ::Aabb& GetAabb() const;
//! Returns an array view into the collection of material slots available to this lod
AZStd::array_view<ModelMaterialSlot> GetMaterialSlots() const;
//! Returns a specific material slot by index, with error checking.
//! The index can be retrieved from Mesh::GetMaterialSlotIndex().
const ModelMaterialSlot& GetMaterialSlot(size_t slotIndex) const;
//! Find a material slot with the given stableId, or returns null if it isn't found.
const ModelMaterialSlot* FindMaterialSlot(uint32_t stableId) const;
private:
AZStd::vector<Mesh> m_meshes;
AZ::Aabb m_aabb = AZ::Aabb::CreateNull();
// These buffers owned by the lod are the consolidated super buffers.
// Meshes may either have views into these buffers or they may own
// their own buffers.
@@ -155,6 +169,13 @@ namespace AZ
Data::Asset<BufferAsset> m_indexBuffer;
AZStd::vector<Data::Asset<BufferAsset>> m_streamBuffers;
// Lists all of the material slots that are used by this LOD.
// Note the same slot can appear in multiple LODs in the model, so that LODs don't have to refer back to the model asset.
AZStd::vector<ModelMaterialSlot> m_materialSlots;
// A default ModelMaterialSlot to be returned upon error conditions.
ModelMaterialSlot m_fallbackSlot;
void AddMesh(const Mesh& mesh);
void SetReady();
@@ -8,6 +8,7 @@
#pragma once
#include <Atom/RPI.Reflect/Model/ModelAsset.h>
#include <Atom/RPI.Reflect/Model/ModelLodAsset.h>
#include <Atom/RPI.Reflect/AssetCreator.h>
@@ -45,9 +46,10 @@ namespace AZ
//! Begin and BeginMesh must be called first.
void SetMeshAabb(AZ::Aabb&& aabb);
//! Sets the material asset for the current SubMesh.
//! Sets the material slot data for the current SubMesh.
//! Adds a new material slot to the ModelLodAsset if it doesn't already exist.
//! Begin and BeginMesh must be called first
void SetMeshMaterialAsset(const Data::Asset<MaterialAsset>& materialAsset);
void SetMeshMaterialSlot(const ModelMaterialSlot& materialSlot);
//! Sets the given BufferAssetView to the current SubMesh as the index buffer.
//! Begin and BeginMesh must be called first
@@ -0,0 +1,43 @@
/*
* Copyright (c) Contributors to the Open 3D Engine Project. For complete copyright and license terms please see the LICENSE at the root of this distribution.
*
* SPDX-License-Identifier: Apache-2.0 OR MIT
*
*/
#pragma once
#include <Atom/RPI.Reflect/Material/MaterialAsset.h>
namespace AZ
{
class ReflectContext;
namespace RPI
{
//! Use by model assets to identify a logical material slot.
//! Each slot has a unique ID, a name, and a default material. Each mesh in model will reference a single ModelMaterialSlot.
//! Other classes like MeshFeatureProcessor and MaterialComponent can override the material associated with individual slots
//! to alter the default appearance of the mesh.
struct ModelMaterialSlot
{
AZ_TYPE_INFO(ModelMaterialSlot, "{0E88A62A-D83D-4C1B-8DE7-CE972B8124B5}");
static void Reflect(AZ::ReflectContext* context);
using StableId = uint32_t;
static const StableId InvalidStableId = -1;
//! This ID must have a consistent value when the asset is reprocessed by the asset pipeline, and must be unique within the ModelLodAsset.
//! In practice, this set using the MaterialUid from SceneAPI. See ModelAssetBuilderComponent::CreateMesh.
StableId m_stableId = InvalidStableId;
Name m_displayName; //!< The name of the slot as displayed to the user in UI. (Using Name instead of string for fast copies)
Data::Asset<MaterialAsset> m_defaultMaterialAsset{ Data::AssetLoadBehavior::PreLoad }; //!< The material that will be applied to this slot by default.
};
using ModelMaterialSlotMap = AZStd::unordered_map<ModelMaterialSlot::StableId, ModelMaterialSlot>;
} //namespace RPI
} // namespace AZ