Builder.AddTokenizedErrorMessage(FTokenizedMessage::Create(EMessageSeverity::Error,LOCTEXT("FailedToImport_InvalidRoot","Could not find root node.")),FFbxErrors::SkeletalMesh_InvalidRoot);
}
else
{
Builder.AddTokenizedErrorMessage(FTokenizedMessage::Create(EMessageSeverity::Error,LOCTEXT("FailedToImport_InvalidNode","Could not find any node.")),FFbxErrors::SkeletalMesh_InvalidNode);
Builder.AddTokenizedErrorMessage(FTokenizedMessage::Create(EMessageSeverity::Error,LOCTEXT("FailedToImport_InvalidRoot","Could not find root node.")),FFbxErrors::SkeletalMesh_InvalidRoot);
}
else
{
Builder.AddTokenizedErrorMessage(FTokenizedMessage::Create(EMessageSeverity::Error,LOCTEXT("FailedToImport_InvalidNode","Could not find any node.")),FFbxErrors::SkeletalMesh_InvalidNode);
UE_LOG(LogTemp,Log,TEXT("%s"),*(FText::Format(FText::FromString("Importing data for attribute \"{0}\""),FText::FromString(ToFString(AttribName)))).ToString());
if(AutoSetArraySize)// This should always be false since for now we are just extending the array each time we want to add an element
{
int32Size=0;
if(UseWedgeIndices)
{
for(autoPrim:Mesh->primitives)
{
Size+=GetNumWedges(&Prim);// Number of wedges
}
}
else
{
for(autoPrim:Mesh->primitives)
{
Size+=Scene->accessors[Prim.attributes.begin()->second].count;// Number of vertices
}
}
OutArray.SetNumUninitialized(Size);
}
// Getting an attribute for individual triangle corners ("wedges")
elseif(UseWedgeIndices&&AttribName!="__WedgeIndices")// Make sure we don't try to access indices for the index array itself!
// Force GC so we can cleanly create a new asset (and not do an 'in place' replacement)
CollectGarbage(GARBAGE_COLLECTION_KEEPFLAGS);
// Create a package for each mesh
Package=CreatePackage(NULL,*NewPackageName);
// Require the parent because it will have been invalidated from the garbage collection
Parent=Package;
}
else
{
// failed to delete
AddTokenizedErrorMessage(FTokenizedMessage::Create(EMessageSeverity::Error,FText::Format(FText::FromString(FString("{0} wasn't created.\n\nThe asset is referenced by other content.")),FText::FromString(MeshName))),FFbxErrors::Generic_CannotDeleteReferenced);
FText::Format(FText::FromString(FString("StaticMesh has a large number({1}) of materials and may render inefficently. Consider breaking up the mesh into multiple Static Mesh Assets.")),
AddTokenizedErrorMessage(FTokenizedMessage::Create(EMessageSeverity::Error,FText::Format(FText::FromString(FString("Error_NoGeometryInMesh","There is no geometry information in mesh '{0}'")),FText::FromString(ToFString(Mesh->name)))),FFbxErrors::Generic_Mesh_NoGeometry);
AddTokenizedErrorMessage(FTokenizedMessage::Create(EMessageSeverity::Error,FText::Format(FText::FromString(FString("Error_NoTrianglesFoundInMesh","No triangles were found on mesh '{0}'")),FText::FromString(ToFString(Mesh->name)))),FFbxErrors::StaticMesh_NoTriangles);
UE_LOG(LogTemp,Log,TEXT("%s"),*(FText::Format(FText::FromString("Importing data for attribute \"{0}\""),FText::FromString(ToFString(AttribName)))).ToString());
if(AutoSetArraySize)// This should always be false since for now we are just extending the array each time we want to add an element
{
int32Size=0;
if(UseWedgeIndices)
{
for(autoPrim:Mesh->primitives)
{
Size+=GetNumWedges(&Prim);// Number of wedges
}
}
else
{
for(autoPrim:Mesh->primitives)
{
Size+=Scene->accessors[Prim.attributes.begin()->second].count;// Number of vertices
}
}
OutArray.SetNumUninitialized(Size);
}
// Getting an attribute for individual triangle corners ("wedges")
elseif(UseWedgeIndices&&AttribName!="__WedgeIndices")// Make sure we don't try to access indices for the index array itself!
// Force GC so we can cleanly create a new asset (and not do an 'in place' replacement)
CollectGarbage(GARBAGE_COLLECTION_KEEPFLAGS);
// Create a package for each mesh
Package=CreatePackage(NULL,*NewPackageName);
// Require the parent because it will have been invalidated from the garbage collection
Parent=Package;
}
else
{
// failed to delete
AddTokenizedErrorMessage(FTokenizedMessage::Create(EMessageSeverity::Error,FText::Format(FText::FromString(FString("{0} wasn't created.\n\nThe asset is referenced by other content.")),FText::FromString(MeshName))),FFbxErrors::Generic_CannotDeleteReferenced);
FText::Format(FText::FromString(FString("StaticMesh has a large number({1}) of materials and may render inefficently. Consider breaking up the mesh into multiple Static Mesh Assets.")),
AddTokenizedErrorMessage(FTokenizedMessage::Create(EMessageSeverity::Error,FText::Format(FText::FromString(FString("Error_NoGeometryInMesh","There is no geometry information in mesh '{0}'")),FText::FromString(ToFString(Mesh->name)))),FFbxErrors::Generic_Mesh_NoGeometry);
AddTokenizedErrorMessage(FTokenizedMessage::Create(EMessageSeverity::Error,FText::Format(FText::FromString(FString("Error_NoTrianglesFoundInMesh","No triangles were found on mesh '{0}'")),FText::FromString(ToFString(Mesh->name)))),FFbxErrors::StaticMesh_NoTriangles);
/// Forward-declared TinyGLTF types since its header can only be #included in one source file.
/// This also means that we must use pointers to these types outside of GLTFMeshBuilder.cpp.
namespacetinygltf
{
classTinyGLTFLoader;
classScene;
classNode;
structACCESSOR;
typedefstructACCESSORAccessor;
structPRIMITIVE;
typedefstructPRIMITIVEPrimitive;
structMESH;
typedefstructMESHMesh;
structMATERIAL;
typedefstructMATERIALMaterial;
}
/// Works in conjunction with TinyGLTF and Unreal's Static Mesh build system to return a UStaticMesh to the factory. This class is adapted from FbxImporter.
classGLTFMeshBuilder
{
public:
GLTFMeshBuilder(FStringFilePath);
~GLTFMeshBuilder();
/// Returns whether we have a valid glTF scene loaded up. For a new MeshBuilder, this should always be queried before calling other functions.
boolLoadedSuccessfully(){returnLoadSuccess;}
/// Returns the number of meshes owned by a given node.
int32GetMeshCount(FStringNodeName);
/// Returns the name of the scene's root node.
FStringGetRootNode();
/// Obtains the mesh names of a node (and optionally its children); useful as an argument to <B>ImportStaticMeshAsSingle()</B>.
/// Returns the error message left by TinyGLTFLoader, if any.
FStringGetError();
private:
// Templated data copy functions, from highest to lowest level:
/// @name Level 4: ConvertAttrib
///@{
/// Fills a TArray with a particular vertex attribute. Set InAttribName to "__WedgeIndex" to use the "indices" accessor for each primitive, or "__MaterialIndices" to obtain the material index.
/// @param OutArray The array to fill with data from the imported file.
/// @param Mesh The glTF from which to convert the specified attribute.
/// @param AttribName The name of the attribute to convert.
/// @param UseWedgeIndices Whether to copy data for each triangle corner ("wedge") or each vertex.
/// @param AutoSetArraySize Whether to resize the array to the number of elements in this attribute (usually false since we may be adding to data from another mesh).
/// Helper functions for converting between Unreal's and STL's strings.
staticFStringToFString(std::stringInString);
staticstd::stringToStdString(FStringInString);
///@}
///
TWeakObjectPtr<UObject>Parent;
tinygltf::TinyGLTFLoader*Loader;
tinygltf::Scene*Scene;
TArray<FString>MeshMaterials;
boolLoadSuccess;
FStringError;
};
/// @file GLTFMeshBuilder.h by Robert Poncelet
#pragma once
#include "UnrealString.h"
#include "TokenizedMessage.h"
#include "GLTFImportOptions.h"
#include <string>
#include <vector>
#include "GLTFMeshBuilder.generated.h"
classUStaticMesh;
classUMaterialInterface;
structFRawMesh;
/// Forward-declared TinyGLTF types since its header can only be #included in one source file.
/// This also means that we must use pointers to these types outside of GLTFMeshBuilder.cpp.
namespacetinygltf
{
classTinyGLTFLoader;
classScene;
classNode;
structACCESSOR;
typedefstructACCESSORAccessor;
structPRIMITIVE;
typedefstructPRIMITIVEPrimitive;
structMESH;
typedefstructMESHMesh;
structMATERIAL;
typedefstructMATERIALMaterial;
}
/// Works in conjunction with TinyGLTF and Unreal's Static Mesh build system to return a UStaticMesh to the factory. This class is adapted from FbxImporter.
UCLASS()
classGLTFLOADER_APIUGLTFMeshBuilder:publicUObject
{
GENERATED_BODY()
public:
UGLTFMeshBuilder();
UGLTFMeshBuilder(FStringFilePath);
~UGLTFMeshBuilder();
/// Returns whether we have a valid glTF scene loaded up. For a new MeshBuilder, this should always be queried before calling other functions.
boolLoadedSuccessfully(){returnLoadSuccess;}
/// Returns the number of meshes owned by a given node.
int32GetMeshCount(FStringNodeName);
/// Returns the name of the scene's root node.
FStringGetRootNode();
/// Obtains the mesh names of a node (and optionally its children); useful as an argument to <B>ImportStaticMeshAsSingle()</B>.
/// Returns the error message left by TinyGLTFLoader, if any.
FStringGetError();
private:
// Templated data copy functions, from highest to lowest level:
/// @name Level 4: ConvertAttrib
///@{
/// Fills a TArray with a particular vertex attribute. Set InAttribName to "__WedgeIndex" to use the "indices" accessor for each primitive, or "__MaterialIndices" to obtain the material index.
/// @param OutArray The array to fill with data from the imported file.
/// @param Mesh The glTF from which to convert the specified attribute.
/// @param AttribName The name of the attribute to convert.
/// @param UseWedgeIndices Whether to copy data for each triangle corner ("wedge") or each vertex.
/// @param AutoSetArraySize Whether to resize the array to the number of elements in this attribute (usually false since we may be adding to data from another mesh).
Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
Copyright (c) 2016, Syoyo Fujita
All rights reserved.
Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.