/* * All or portions of this file Copyright(c) Amazon.com, Inc.or its affiliates or * its licensors. * * For complete copyright and license terms please see the LICENSE at the root of this * distribution(the "License").All use of this software is governed by the License, *or, if provided, by the license below or the license accompanying this file.Do not * remove or modify any license notices.This file is distributed on an "AS IS" BASIS, *WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include namespace AZ { namespace RPI { static const char* MaterialExporterName = "Scene Material Builder"; void MaterialAssetDependenciesComponent::Reflect(ReflectContext* context) { if (auto* serialize = azrtti_cast(context)) { serialize->Class() ->Version(4) ->Attribute(Edit::Attributes::SystemComponentTags, AZStd::vector({ AssetBuilderSDK::ComponentTags::AssetBuilder })); } } void MaterialAssetDependenciesComponent::GetProvidedServices(AZ::ComponentDescriptor::DependencyArrayType& provided) { provided.push_back(AZ_CRC("MaterialAssetDependenciesService", 0x28bbd0f3)); } void MaterialAssetDependenciesComponent::GetIncompatibleServices(AZ::ComponentDescriptor::DependencyArrayType& incompatible) { incompatible.push_back(AZ_CRC("MaterialAssetDependenciesService", 0x28bbd0f3)); } void MaterialAssetDependenciesComponent::Activate() { SceneAPI::SceneBuilderDependencyBus::Handler::BusConnect(); } void MaterialAssetDependenciesComponent::Deactivate() { SceneAPI::SceneBuilderDependencyBus::Handler::BusDisconnect(); } void MaterialAssetDependenciesComponent::ReportJobDependencies(SceneAPI::JobDependencyList& jobDependencyList, const char* platformIdentifier) { AssetBuilderSDK::SourceFileDependency materialTypeSource; // Right now, FBX importing only supports a single material type, once that changes, this will have to be re-designed, see ATOM-3554 RPI::MaterialConverterBus::BroadcastResult(materialTypeSource.m_sourceFileDependencyPath, &RPI::MaterialConverterBus::Events::GetMaterialTypePath); AssetBuilderSDK::JobDependency jobDependency; jobDependency.m_jobKey = "Atom Material Builder"; jobDependency.m_sourceFile = materialTypeSource; jobDependency.m_platformIdentifier = platformIdentifier; jobDependency.m_type = AssetBuilderSDK::JobDependencyType::Order; jobDependencyList.push_back(jobDependency); } void MaterialAssetBuilderComponent::Reflect(ReflectContext* context) { if (auto* serialize = azrtti_cast(context)) { serialize->Class() ->Version(14); // [ATOM-13410] } } uint32_t MaterialAssetBuilderComponent::GetMaterialAssetSubId(uint64_t materialUid) { // [GFX TODO] I am suggesting we use the first two 16bits for different kind of assets generated from a Scene // For example, 0x10000 for mesh, 0x20000 for material, 0x30000 for animation, 0x40000 for scene graph and etc. // so the subid can be evaluated for reference across different assets generate within this fbx. /*const uint32_t materialPrefix = 0x20000; AZ_Assert(materialPrefix > materialId, "materialId should be smaller than materialPrefix"); return materialPrefix + materialId;*/ return static_cast(materialUid); } MaterialAssetBuilderComponent::MaterialAssetBuilderComponent() { BindToCall(&MaterialAssetBuilderComponent::BuildMaterials); } SceneAPI::Events::ProcessingResult MaterialAssetBuilderComponent::BuildMaterials(MaterialAssetBuilderContext& context) const { const auto& scene = context.m_scene; const Uuid sourceSceneUuid = scene.GetSourceGuid(); const auto& sceneGraph = scene.GetGraph(); auto names = sceneGraph.GetNameStorage(); auto content = sceneGraph.GetContentStorage(); auto pairView = SceneAPI::Containers::Views::MakePairView(names, content); auto view = SceneAPI::Containers::Views::MakeSceneGraphDownwardsView< SceneAPI::Containers::Views::BreadthFirst>( sceneGraph, sceneGraph.GetRoot(), pairView.cbegin(), true); struct NamedMaterialSourceData { MaterialSourceData m_data; AZStd::string m_name; }; AZStd::unordered_map materialSourceDataByUid; for (const auto& viewIt : view) { if (viewIt.second == nullptr) { continue; } if (azrtti_istypeof(viewIt.second.get())) { // Convert MaterialData to MaterialSourceData and add it to materialSourceDataByUid auto materialData = AZStd::static_pointer_cast(viewIt.second); uint64_t materialUid = materialData->GetUniqueId(); if (materialSourceDataByUid.find(materialUid) != materialSourceDataByUid.end()) { continue; } // The source data for generating material asset MaterialSourceData sourceData; // User hook to create their materials based on the data from Fbx pipeline bool result = false; RPI::MaterialConverterBus::BroadcastResult(result, &RPI::MaterialConverterBus::Events::ConvertMaterial, *materialData, sourceData); if (result) { materialSourceDataByUid[materialUid] = { AZStd::move(sourceData), materialData->GetMaterialName() }; } } } // Build material assets. for (auto& itr : materialSourceDataByUid) { const uint64_t materialUid = itr.first; Data::AssetId assetId(sourceSceneUuid, GetMaterialAssetSubId(materialUid)); auto materialSourceData = itr.second; Outcome> result = materialSourceData.m_data.CreateMaterialAsset(assetId, "", false); if (result.IsSuccess()) { context.m_outputMaterialsByUid[materialUid] = { result.GetValue(), materialSourceData.m_name }; } else { AZ_Error(MaterialExporterName, false, "Create material failed"); return SceneAPI::Events::ProcessingResult::Failure; } } return SceneAPI::Events::ProcessingResult::Success; } } // namespace RPI } // namespace AZ