/* * 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 * */ #include #include #include #include namespace AZ { namespace RPI { AZ::Data::Asset ModelAssetHelpers::CreateBufferAsset( const void* data, const uint32_t elementCount, const uint32_t elementSize) { // Create a buffer pool asset for use with the buffer asset AZ::Data::Asset bufferPoolAsset; { AZ::Data::AssetId bufferPoolId = AZ::Uuid::CreateRandom(); bufferPoolAsset = AZ::Data::AssetManager::Instance().CreateAsset( bufferPoolId, azrtti_typeid(), Data::AssetLoadBehavior::PreLoad); auto bufferPoolDesc = AZStd::make_unique(); bufferPoolDesc->m_bindFlags = AZ::RHI::BufferBindFlags::InputAssembly; bufferPoolDesc->m_heapMemoryLevel = AZ::RHI::HeapMemoryLevel::Host; AZ::RPI::ResourcePoolAssetCreator creator; creator.Begin(bufferPoolId); creator.SetPoolDescriptor(AZStd::move(bufferPoolDesc)); creator.SetPoolName("ModelAssetHelperBufferPool"); creator.End(bufferPoolAsset); } // Create a buffer asset that contains a copy of the input data. AZ::Data::Asset asset; { AZ::Data::AssetId bufferId = AZ::Uuid::CreateRandom(); asset = AZ::Data::AssetManager::Instance().CreateAsset( bufferId, azrtti_typeid(), Data::AssetLoadBehavior::PreLoad); AZ::RHI::BufferDescriptor bufferDescriptor; bufferDescriptor.m_bindFlags = AZ::RHI::BufferBindFlags::InputAssembly; bufferDescriptor.m_byteCount = elementCount * elementSize; AZ::RPI::BufferAssetCreator creator; creator.Begin(bufferId); creator.SetPoolAsset(bufferPoolAsset); creator.SetBuffer(data, bufferDescriptor.m_byteCount, bufferDescriptor); creator.SetBufferViewDescriptor(AZ::RHI::BufferViewDescriptor::CreateStructured(0, elementCount, elementSize)); creator.End(asset); } return asset; } void ModelAssetHelpers::CreateModel( ModelAsset* modelAsset, const AZ::Name& name, AZStd::span indices, AZStd::span positions, AZStd::span normals, AZStd::span tangents, AZStd::span bitangents, AZStd::span uvs) { // First build a model LOD asset that contains a mesh for the given data. AZ::Data::Asset lodAsset; AZ::Data::AssetId lodAssetId = AZ::Uuid::CreateRandom(); lodAsset = AZ::Data::AssetManager::Instance().CreateAsset( lodAssetId, azrtti_typeid(), Data::AssetLoadBehavior::PreLoad); AZ::RPI::ModelLodAssetCreator creator; creator.Begin(lodAssetId); const uint32_t positionElementCount = aznumeric_cast(positions.size() / 3); const uint32_t indexElementCount = aznumeric_cast(indices.size()); const uint32_t uvElementCount = aznumeric_cast(uvs.size() / 2); const uint32_t normalElementCount = aznumeric_cast(normals.size() / 3); const uint32_t tangentElementCount = aznumeric_cast(tangents.size() / 4); const uint32_t bitangentElementCount = aznumeric_cast(bitangents.size() / 3); constexpr uint32_t PositionElementSize = aznumeric_cast(sizeof(float) * 3); constexpr uint32_t IndexElementSize = aznumeric_cast(sizeof(uint32_t)); constexpr uint32_t UvElementSize = aznumeric_cast(sizeof(float) * 2); constexpr uint32_t NormalElementSize = aznumeric_cast(sizeof(float) * 3); constexpr uint32_t TangentElementSize = aznumeric_cast(sizeof(float) * 4); constexpr uint32_t BitangentElementSize = aznumeric_cast(sizeof(float) * 3); // Calculate the Aabb for the given positions. AZ::Aabb aabb = AZ::Aabb::CreateNull(); for (uint32_t i = 0; i < positions.size(); i += 3) { aabb.AddPoint(AZ::Vector3(positions[i], positions[i + 1], positions[i + 2])); } // Set up a single-mesh asset with only position data. creator.BeginMesh(); creator.SetMeshAabb(AZStd::move(aabb)); creator.SetMeshMaterialSlot(0); creator.SetMeshIndexBuffer({ CreateBufferAsset(indices.data(), indexElementCount, IndexElementSize), AZ::RHI::BufferViewDescriptor::CreateTyped(0, indexElementCount, AZ::RHI::Format::R32_UINT) }); creator.AddMeshStreamBuffer( AZ::RHI::ShaderSemantic(AZ::Name("POSITION")), AZ::Name(), { CreateBufferAsset(positions.data(), positionElementCount, PositionElementSize), AZ::RHI::BufferViewDescriptor::CreateTyped(0, positionElementCount, AZ::RHI::Format::R32G32B32_FLOAT) }); creator.AddMeshStreamBuffer( AZ::RHI::ShaderSemantic(AZ::Name("NORMAL")), AZ::Name(), { CreateBufferAsset(normals.data(), normalElementCount, NormalElementSize), AZ::RHI::BufferViewDescriptor::CreateTyped(0, normalElementCount, AZ::RHI::Format::R32G32B32_FLOAT) }); creator.AddMeshStreamBuffer( AZ::RHI::ShaderSemantic(AZ::Name("TANGENT")), AZ::Name(), { CreateBufferAsset(tangents.data(), tangentElementCount, TangentElementSize), AZ::RHI::BufferViewDescriptor::CreateTyped(0, tangentElementCount, AZ::RHI::Format::R32G32B32A32_FLOAT) }); creator.AddMeshStreamBuffer( AZ::RHI::ShaderSemantic(AZ::Name("BITANGENT")), AZ::Name(), { CreateBufferAsset(bitangents.data(), bitangentElementCount, BitangentElementSize), AZ::RHI::BufferViewDescriptor::CreateTyped(0, bitangentElementCount, AZ::RHI::Format::R32G32B32_FLOAT) }); creator.AddMeshStreamBuffer( AZ::RHI::ShaderSemantic(AZ::Name("UV")), AZ::Name(), { CreateBufferAsset(uvs.data(), uvElementCount, UvElementSize), AZ::RHI::BufferViewDescriptor::CreateTyped(0, uvElementCount, AZ::RHI::Format::R32G32_FLOAT) }); creator.EndMesh(); creator.End(lodAsset); // Create a model asset that contains the single LOD built above. modelAsset->InitData( name, AZStd::span>(&lodAsset, 1), {}, // no material slots {}, // no fallback material {} // no tags ); } void ModelAssetHelpers::CreateUnitCube(ModelAsset* modelAsset) { // Build a mesh containing a unit cube. // The vertices are duplicated for each face so that we can have correct per-face normals and UVs. constexpr int ValuesPerPositionEntry = 3; constexpr int ValuesPerUvEntry = 2; constexpr int ValuesPerNormalEntry = 3; constexpr int ValuesPerTangentEntry = 4; constexpr int ValuesPerBitangentEntry = 3; constexpr int VerticesPerFace = 6; constexpr int MeshFaces = 6; constexpr int ValuesPerFace = 4; // 6 vertices per face, 6 faces. constexpr AZStd::array indices = { 0, 1, 2, 0, 2, 3, // front face 4, 5, 6, 4, 6, 7, // right face 8, 9, 10, 8, 10, 11, // back face 12, 13, 14, 12, 14, 15, // left face 16, 17, 18, 16, 18, 19, // top face 20, 21, 22, 20, 22, 23 // bottom face }; // 3 values per position, 4 positions per face, 6 faces constexpr AZStd::array positions = { -0.5f, -0.5f, -0.5f, +0.5f, -0.5f, -0.5f, +0.5f, -0.5f, +0.5f, -0.5f, -0.5f, +0.5f, // front +0.5f, -0.5f, -0.5f, +0.5f, +0.5f, -0.5f, +0.5f, +0.5f, +0.5f, +0.5f, -0.5f, +0.5f, // right +0.5f, +0.5f, -0.5f, -0.5f, +0.5f, -0.5f, -0.5f, +0.5f, +0.5f, +0.5f, +0.5f, +0.5f, // back -0.5f, +0.5f, -0.5f, -0.5f, -0.5f, -0.5f, -0.5f, -0.5f, +0.5f, -0.5f, +0.5f, +0.5f, // left -0.5f, -0.5f, +0.5f, +0.5f, -0.5f, +0.5f, +0.5f, +0.5f, +0.5f, -0.5f, +0.5f, +0.5f, // top -0.5f, +0.5f, -0.5f, +0.5f, +0.5f, -0.5f, +0.5f, -0.5f, -0.5f, -0.5f, -0.5f, -0.5f, // bottom }; // 2 values per position, 4 positions per face, 6 faces // This aribtrarily maps the UVs to use the full texture on each face. // This choice can be changed if a different mapping would be more usable. constexpr AZStd::array uvs = { 0.0f, 0.0f, 1.0f, 0.0f, 1.0f, 1.0f, 0.0f, 1.0f, // front 0.0f, 0.0f, 1.0f, 0.0f, 1.0f, 1.0f, 0.0f, 1.0f, // right 0.0f, 0.0f, 1.0f, 0.0f, 1.0f, 1.0f, 0.0f, 1.0f, // back 0.0f, 0.0f, 1.0f, 0.0f, 1.0f, 1.0f, 0.0f, 1.0f, // left 0.0f, 0.0f, 1.0f, 0.0f, 1.0f, 1.0f, 0.0f, 1.0f, // top 0.0f, 0.0f, 1.0f, 0.0f, 1.0f, 1.0f, 0.0f, 1.0f, // bottom }; // 3 values per position, 4 positions per face, 6 faces constexpr AZStd::array normals = { +0.0f, -1.0f, +0.0f, +0.0f, -1.0f, +0.0f, +0.0f, -1.0f, +0.0f, +0.0f, -1.0f, +0.0f, // front (-Y) +1.0f, +0.0f, +0.0f, +1.0f, +0.0f, +0.0f, +1.0f, +0.0f, +0.0f, +1.0f, +0.0f, +0.0f, // right (+X) +0.0f, +1.0f, +0.0f, +0.0f, +1.0f, +0.0f, +0.0f, +1.0f, +0.0f, +0.0f, +1.0f, +0.0f, // back (+Y) -1.0f, +0.0f, +0.0f, -1.0f, +0.0f, +0.0f, -1.0f, +0.0f, +0.0f, -1.0f, +0.0f, +0.0f, // left (-X) +0.0f, +0.0f, +1.0f, +0.0f, +0.0f, +1.0f, +0.0f, +0.0f, +1.0f, +0.0f, +0.0f, +1.0f, // top (+Z) +0.0f, +0.0f, -1.0f, +0.0f, +0.0f, -1.0f, +0.0f, +0.0f, -1.0f, +0.0f, +0.0f, -1.0f, // bottom (-Z) }; // 4 values per position, 4 positions per face, 6 faces constexpr AZStd::array tangents = { 0.0f, 0.0f, 1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f, // front (+Z) 0.0f, 0.0f, 1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f, // right (+Z) 0.0f, 0.0f, 1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f, // back (+Z) 0.0f, 0.0f, 1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f, // left (+Z) 0.0f, 1.0f, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f, 1.0f, // top (+Y) 0.0f, -1.0f, 0.0f, 1.0f, 0.0f, -1.0f, 0.0f, 1.0f, 0.0f, -1.0f, 0.0f, 1.0f, 0.0f, -1.0f, 0.0f, 1.0f, // bottom (-Y) }; // 3 values per position, 4 positions per face, 6 faces constexpr AZStd::array bitangents = { +1.0f, +0.0f, +0.0f, +1.0f, +0.0f, +0.0f, +1.0f, +0.0f, +0.0f, +1.0f, +0.0f, +0.0f, // front (+X) +0.0f, +1.0f, +0.0f, +0.0f, +1.0f, +0.0f, +0.0f, +1.0f, +0.0f, +0.0f, +1.0f, +0.0f, // right (+Y) -1.0f, +0.0f, +0.0f, -1.0f, +0.0f, +0.0f, -1.0f, +0.0f, +0.0f, -1.0f, +0.0f, +0.0f, // back (-X) +0.0f, -1.0f, +0.0f, +0.0f, -1.0f, +0.0f, +0.0f, -1.0f, +0.0f, +0.0f, -1.0f, +0.0f, // left (-Y) +1.0f, +0.0f, +0.0f, +1.0f, +0.0f, +0.0f, +1.0f, +0.0f, +0.0f, +1.0f, +0.0f, +0.0f, // top (+X) +1.0f, +0.0f, +0.0f, +1.0f, +0.0f, +0.0f, +1.0f, +0.0f, +0.0f, +1.0f, +0.0f, +0.0f, // bottom (+X) }; CreateModel(modelAsset, AZ::Name("UnitCube"), indices, positions, normals, tangents, bitangents, uvs); } void ModelAssetHelpers::CreateUnitX(ModelAsset* modelAsset) { // Build a mesh containing a unit X model. // To make the X double-sided regardless of material, we'll create two faces for each branch of the X. constexpr int ValuesPerPositionEntry = 3; constexpr int ValuesPerUvEntry = 2; constexpr int ValuesPerNormalEntry = 3; constexpr int ValuesPerTangentEntry = 4; constexpr int ValuesPerBitangentEntry = 3; constexpr int VerticesPerFace = 6; constexpr int MeshFaces = 4; constexpr int ValuesPerFace = 4; // 6 vertices per face, 4 faces. constexpr AZStd::array indices = { 0, 1, 2, 0, 2, 3, // / face of X 4, 5, 6, 4, 6, 7, // \ face of X 8, 9, 10, 8, 10, 11, // / face of X (back) 12, 13, 14, 12, 14, 15, // \ face of X (back) }; // 3 values per position, 4 positions per face, 2 faces constexpr AZStd::array positions = { -0.5f, -0.5f, -0.5f, +0.5f, +0.5f, -0.5f, +0.5f, +0.5f, +0.5f, -0.5f, -0.5f, +0.5f, // / face of X -0.5f, +0.5f, -0.5f, +0.5f, -0.5f, -0.5f, +0.5f, -0.5f, +0.5f, -0.5f, +0.5f, +0.5f, // \ face of X +0.5f, +0.5f, -0.5f, -0.5f, -0.5f, -0.5f, -0.5f, -0.5f, +0.5f, +0.5f, +0.5f, +0.5f, // / face of X (back) +0.5f, -0.5f, -0.5f, -0.5f, +0.5f, -0.5f, -0.5f, +0.5f, +0.5f, +0.5f, -0.5f, +0.5f, // \ face of X (back) }; // 2 values per position, 4 positions per face, 2 faces // This aribtrarily maps the UVs to use the full texture on each face. // This choice can be changed if a different mapping would be more usable. constexpr AZStd::array uvs = { 0.0f, 0.0f, 1.0f, 0.0f, 1.0f, 1.0f, 0.0f, 1.0f, // / face of X 0.0f, 0.0f, 1.0f, 0.0f, 1.0f, 1.0f, 0.0f, 1.0f, // \ face of X 0.0f, 0.0f, 1.0f, 0.0f, 1.0f, 1.0f, 0.0f, 1.0f, // / face of X (back) 0.0f, 0.0f, 1.0f, 0.0f, 1.0f, 1.0f, 0.0f, 1.0f, // \ face of X (back }; // 3 values per position, 4 positions per face, 2 faces constexpr AZStd::array normals = { +0.5f, -0.5f, +0.0f, +0.5f, -0.5f, +0.0f, +0.5f, -0.5f, +0.0f, +0.5f, -0.5f, +0.0f, // / face of X -0.5f, -0.5f, +0.0f, -0.5f, -0.5f, +0.0f, -0.5f, -0.5f, +0.0f, -0.5f, -0.5f, +0.0f, // \ face of X -0.5f, +0.5f, +0.0f, -0.5f, +0.5f, +0.0f, -0.5f, +0.5f, +0.0f, -0.5f, +0.5f, +0.0f, // / face of X (back) +0.5f, +0.5f, +0.0f, +0.5f, +0.5f, +0.0f, +0.5f, +0.5f, +0.0f, +0.5f, +0.5f, +0.0f, // \ face of X (back) }; // 4 values per position, 4 positions per face, 2 faces constexpr AZStd::array tangents = { 0.0f, 0.0f, 1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f, // / face of X 0.0f, 0.0f, 1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f, // \ face of X 0.0f, 0.0f, 1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f, // / face of X (back) 0.0f, 0.0f, 1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f, // \ face of X (back) }; // 3 values per position, 4 positions per face, 2 faces constexpr AZStd::array bitangents = { +0.5f, +0.5f, +0.0f, +0.5f, +0.5f, +0.0f, +0.5f, +0.5f, +0.0f, +0.5f, +0.5f, +0.0f, // / face of X -0.5f, +0.5f, +0.0f, -0.5f, +0.5f, +0.0f, -0.5f, +0.5f, +0.0f, -0.5f, +0.5f, +0.0f, // \ face of X -0.5f, -0.5f, +0.0f, -0.5f, -0.5f, +0.0f, -0.5f, -0.5f, +0.0f, -0.5f, -0.5f, +0.0f, // / face of X (back) +0.5f, -0.5f, +0.0f, +0.5f, -0.5f, +0.0f, +0.5f, -0.5f, +0.0f, +0.5f, -0.5f, +0.0f, // \ face of X (back) }; CreateModel(modelAsset, AZ::Name("UnitX"), indices, positions, normals, tangents, bitangents, uvs); } } // namespace RPI } // namespace AZ