/* * 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 SceneAPI { namespace FbxSceneBuilder { struct QueueNode { std::shared_ptr m_node; Containers::SceneGraph::NodeIndex m_parent; QueueNode() = delete; QueueNode(std::shared_ptr&& node, Containers::SceneGraph::NodeIndex parent) : m_node(std::move(node)) , m_parent(parent) { } }; FbxImporter::FbxImporter() : m_sceneWrapper(new FbxSDKWrapper::FbxSceneWrapper()) , m_sceneSystem(new FbxSceneSystem()) { BindToCall(&FbxImporter::ImportProcessing); } void FbxImporter::Reflect(ReflectContext* context) { SerializeContext* serializeContext = azrtti_cast(context); if (serializeContext) { serializeContext->Class()->Version(1); } } Events::ProcessingResult FbxImporter::ImportProcessing(Events::ImportEventContext& context) { m_sceneWrapper->Clear(); if (!m_sceneWrapper->LoadSceneFromFile(context.GetInputDirectory().c_str())) { return Events::ProcessingResult::Failure; } m_sceneSystem->Set(*m_sceneWrapper); if (ConvertFbxSceneContext(context.GetScene())) { return Events::ProcessingResult::Success; } else { return Events::ProcessingResult::Failure; } } bool FbxImporter::ConvertFbxSceneContext(Containers::Scene& scene) const { std::shared_ptr fbxRoot = m_sceneWrapper->GetRootNode(); if (!fbxRoot) { return false; } int sign = 0; FbxSDKWrapper::FbxAxisSystemWrapper::UpVector upVector = m_sceneWrapper->GetAxisSystem()->GetUpVector(sign); AZ_Assert(sign != 0, "sign failed to populate which is a failure in GetUpVector"); if (upVector == FbxSDKWrapper::FbxAxisSystemWrapper::UpVector::Z) { if (sign > 0) { scene.SetOriginalSceneOrientation(Containers::Scene::SceneOrientation::ZUp); } else { scene.SetOriginalSceneOrientation(Containers::Scene::SceneOrientation::NegZUp); AZ_Assert(false, "Negative Z Up scene orientation is not a currently supported orientation."); AZ_TracePrintf(SceneAPI::Utilities::ErrorWindow, "Negative Z Up scene orientation is not a currently supported orientation."); } } else if (upVector == FbxSDKWrapper::FbxAxisSystemWrapper::UpVector::Y) { if (sign > 0) { scene.SetOriginalSceneOrientation(Containers::Scene::SceneOrientation::YUp); } else { scene.SetOriginalSceneOrientation(Containers::Scene::SceneOrientation::NegYUp); AZ_Assert(false, "Negative Y Up scene orientation is not a currently supported orientation."); AZ_TracePrintf(SceneAPI::Utilities::ErrorWindow, "Negative Y Up scene orientation is not a currently supported orientation."); } } else if (upVector == FbxSDKWrapper::FbxAxisSystemWrapper::UpVector::X) { if (sign > 0) { scene.SetOriginalSceneOrientation(Containers::Scene::SceneOrientation::XUp); AZ_Assert(false, "Positive X Up scene orientation is not a currently supported orientation."); AZ_TracePrintf(SceneAPI::Utilities::ErrorWindow, "Positive X Up scene orientation is not a currently supported orientation."); } else { scene.SetOriginalSceneOrientation(Containers::Scene::SceneOrientation::NegXUp); AZ_Assert(false, "Negative X Up scene orientation is not a currently supported orientation."); AZ_TracePrintf(SceneAPI::Utilities::ErrorWindow, "Negative X Up scene orientation is not a currently supported orientation."); } } AZStd::queue nodes; nodes.emplace(AZStd::move(fbxRoot), scene.GetGraph().GetRoot()); RenamedNodesMap nodeNameMap; while (!nodes.empty()) { FbxSceneBuilder::QueueNode& node = nodes.front(); AZ_Assert(node.m_node, "Empty fbx node queued"); if (!nodeNameMap.RegisterNode(node.m_node, scene.GetGraph(), node.m_parent)) { AZ_TracePrintf(Utilities::ErrorWindow, "Failed to register fbx node in name table."); continue; } AZStd::string nodeName = nodeNameMap.GetNodeName(node.m_node); AZ_TraceContext("SceneAPI Node Name", nodeName); Containers::SceneGraph::NodeIndex newNode = scene.GetGraph().AddChild(node.m_parent, nodeName.c_str()); AZ_Assert(newNode.IsValid(), "Failed to add node to scene graph"); if (!newNode.IsValid()) { continue; } FbxNodeEncounteredContext sourceNodeEncountered(scene, newNode, *m_sceneWrapper, *m_sceneSystem, nodeNameMap, *node.m_node); Events::ProcessingResultCombiner nodeResult; nodeResult += Events::Process(sourceNodeEncountered); // If no importer created data, we still create an empty node that may eventually contain a transform if (sourceNodeEncountered.m_createdData.empty()) { AZ_Assert(nodeResult.GetResult() != Events::ProcessingResult::Success, "Importers returned success but no data was created"); AZStd::shared_ptr nullData(nullptr); sourceNodeEncountered.m_createdData.emplace_back(nullData); nodeResult += Events::ProcessingResult::Success; } // Create single node since only one piece of graph data was created if (sourceNodeEncountered.m_createdData.size() == 1) { AZ_Assert(nodeResult.GetResult() != Events::ProcessingResult::Ignored, "An importer created data, but did not return success"); if (nodeResult.GetResult() == Events::ProcessingResult::Failure) { AZ_TracePrintf(Utilities::ErrorWindow, "One or more importers failed to create data."); } SceneDataPopulatedContext dataProcessed(sourceNodeEncountered, sourceNodeEncountered.m_createdData[0], nodeName.c_str()); Events::ProcessingResult result = AddDataNodeWithContexts(dataProcessed); if (result != Events::ProcessingResult::Failure) { newNode = dataProcessed.m_currentGraphPosition; } } // Create an empty parent node and place all data under it. The remaining // tree will be built off of this as the logical parent else { AZ_Assert(nodeResult.GetResult() != Events::ProcessingResult::Ignored, "%i importers created data, but did not return success", sourceNodeEncountered.m_createdData.size()); if (nodeResult.GetResult() == Events::ProcessingResult::Failure) { AZ_TracePrintf(Utilities::ErrorWindow, "One or more importers failed to create data."); } size_t offset = nodeName.length(); for (size_t i = 0; i < sourceNodeEncountered.m_createdData.size(); ++i) { nodeName += '_'; nodeName += AZStd::to_string(aznumeric_cast(i + 1)); Containers::SceneGraph::NodeIndex subNode = scene.GetGraph().AddChild(newNode, nodeName.c_str()); AZ_Assert(subNode.IsValid(), "Failed to create new scene sub node"); SceneDataPopulatedContext dataProcessed(sourceNodeEncountered, sourceNodeEncountered.m_createdData[i], nodeName); dataProcessed.m_currentGraphPosition = subNode; AddDataNodeWithContexts(dataProcessed); // Remove the temporary extension again. nodeName.erase(offset, nodeName.length() - offset); } } AZ_Assert(nodeResult.GetResult() == Events::ProcessingResult::Success, "No importers successfully added processed scene data."); AZ_Assert(newNode != node.m_parent, "Failed to update current graph position during data processing."); int childCount = node.m_node->GetChildCount(); for (int i = 0; i < childCount; ++i) { std::shared_ptr child = node.m_node->GetChild(i); if (child) { nodes.emplace(AZStd::move(child), newNode); } } nodes.pop(); } Events::ProcessingResult result = Events::Process(scene, *m_sceneWrapper, *m_sceneSystem, nodeNameMap); if (result == Events::ProcessingResult::Failure) { return false; } return true; } } // namespace FbxSceneBuilder } // namespace SceneAPI } // namespace AZ