Commit 50b233c3 by RobertPoncelet Committed by GitHub

Uploaded necessary files

parent 3c061530
{
"Changelist" : 3013449,
"BuildId" : "521bff43-3bc1-4230-8558-29af88fc728e",
"Modules" :
{
"GLTFLoader" : "UE4Editor-GLTFLoader.dll"
}
}
\ No newline at end of file
{
"FileVersion": 3,
"Version": 1,
"VersionName": "1.0",
"FriendlyName": "GLTFLoader",
"Description": "",
"Category": "Other",
"CreatedBy": "",
"CreatedByURL": "",
"DocsURL": "",
"MarketplaceURL": "",
"SupportURL": "",
"Modules": [
{
"Name": "GLTFLoader",
"Type": "Developer",
"LoadingPhase": "Default"
}
],
"EnabledByDefault": false,
"CanContainContent": false,
"IsBetaVersion": false,
"Installed": false
}
\ No newline at end of file
# Unreal Engine glTF Loader Plugin
Overview
------
This plugin makes use of Tiny glTF Loader [(link)](https://github.com/syoyo/tinygltfloader) to allow the user to import glTF files as static meshes. It has been tested with Unreal Engine version 4.12.3.
Installation and Usage
------
To install, simply copy the repository folder to "Plugins" in your project root. You may need to recompile your project if your engine version differs from 4.12.3.
To use, firstly enable the plugin in your settings if you don't see the glTF button in the top toolbar. Clicking it will open the plugin window, where you can modify transformation settings applied to the mesh before importing. The "Import File" button here will open a browser to import a glTF file as a static mesh to the current folder in the content browser.
// Some copyright should be here...
using UnrealBuildTool;
public class GLTFLoader : ModuleRules
{
public GLTFLoader(TargetInfo Target)
{
PublicIncludePaths.AddRange(
new string[] {
"GLTFLoader/Public"
// ... add public include paths required here ...
}
);
PrivateIncludePaths.AddRange(
new string[] {
"GLTFLoader/Private",
// ... add other private include paths required here ...
}
);
PublicDependencyModuleNames.AddRange(
new string[]
{
"Core",
"CoreUObject",
"Engine",
"UnrealEd",
"RawMesh",
"RenderCore", // For FPackedNormal
"MaterialUtilities",
"MeshUtilities",
"AssetTools"
// ... add other public dependencies that you statically link with here ...
}
);
PrivateDependencyModuleNames.AddRange(
new string[]
{
"Projects",
"InputCore",
"UnrealEd",
"LevelEditor",
"CoreUObject",
"Engine",
"Slate",
"SlateCore",
"RawMesh",
"RenderCore", // For FPackedNormal
"MaterialUtilities",
"MeshUtilities",
"AssetTools",
"PropertyEditor",
"EditorStyle",
"EditorWidgets"
// ... add private dependencies that you statically link with here ...
}
);
DynamicallyLoadedModuleNames.AddRange(
new string[]
{
// ... add any modules that your module loads dynamically here ...
}
);
}
}
// Fill out your copyright notice in the Description page of Project Settings.
#include "GLTFLoaderPrivatePCH.h"
#include "GLTFFactory.h"
#include "Engine.h"
#include "Editor/UnrealEd/Public/Editor.h"
#include "GLTFMeshBuilder.h"
#include "UnrealEd.h"
#include "Factories.h"
#include "BusyCursor.h"
#include "SSkeletonWidget.h"
#include "AssetRegistryModule.h"
#include "Engine/StaticMesh.h"
#include "FbxErrors.h"
#define LOCTEXT_NAMESPACE "GLTFFactory"
UGLTFFactory::UGLTFFactory(const FObjectInitializer& ObjectInitializer)
: Super(ObjectInitializer)
{
SupportedClass = UStaticMesh::StaticClass();
Formats.Add(TEXT("gltf;GLTF meshes"));
bCreateNew = false;
bText = false;
bEditorImport = true;
bOperationCanceled = false;
bDetectImportTypeOnImport = false;
}
//This function is adapted from UFbxFactory::CreateBinary()
UObject* UGLTFFactory::FactoryCreateBinary
(
UClass* Class,
UObject* InParent,
FName Name,
EObjectFlags Flags,
UObject* Context,
const TCHAR* Type,
const uint8*& Buffer,
const uint8* BufferEnd,
FFeedbackContext* Warn,
bool& bOutOperationCanceled
)
{
if (bOperationCanceled)
{
bOutOperationCanceled = true;
FEditorDelegates::OnAssetPostImport.Broadcast(this, NULL);
return NULL;
}
FEditorDelegates::OnAssetPreImport.Broadcast(this, Class, InParent, Name, Type);
UObject* NewObject = NULL;
GLTFMeshBuilder Builder(*UFactory::CurrentFilename);
bool bShowImportDialog = bShowOption && !GIsAutomationTesting;
bool bImportAll = false;
auto ImportOptions = FGLTFLoaderModule::ImportOptions;
bOutOperationCanceled = bOperationCanceled;
if (bImportAll)
{
// If the user chose to import all, we don't show the dialog again and use the same settings for each object until importing another set of files
bShowOption = false;
}
// For multiple files, use the same settings
bDetectImportTypeOnImport = false;
Warn->BeginSlowTask(NSLOCTEXT("GLTFFactory", "BeginImportingGLTFMeshTask", "Importing GLTF mesh"), true);
if (!Builder.LoadedSuccessfully())
{
// Log the error message and fail the import.
Warn->Log(ELogVerbosity::Error, Builder.GetError());
}
else
{
// Log the import message and import the mesh.
const FString errorMessage = Builder.GetError();
if (errorMessage.Len() > 0)
{
Warn->Log(errorMessage);
}
FString RootNodeToImport = "";
RootNodeToImport = Builder.GetRootNode();
// For animation and static mesh we assume there is at lease one interesting node by default
int32 InterestingNodeCount = 1;
bool bImportStaticMeshLODs = /*ImportUI->StaticMeshImportData->bImportMeshLODs*/ false;
bool bCombineMeshes = /*ImportUI->bCombineMeshes*/ true;
if (bCombineMeshes && !bImportStaticMeshLODs)
{
// If Combine meshes and dont import mesh LODs, the interesting node count should be 1 so all the meshes are grouped together into one static mesh
InterestingNodeCount = 1;
}
else
{
// count meshes in lod groups if we dont care about importing LODs
bool bCountLODGroupMeshes = !bImportStaticMeshLODs;
int32 NumLODGroups = 0;
InterestingNodeCount = Builder.GetMeshCount(RootNodeToImport/*, bCountLODGroupMeshes, NumLODGroups*/);
// if there were LODs in the file, do not combine meshes even if requested
if (bImportStaticMeshLODs && bCombineMeshes)
{
bCombineMeshes = NumLODGroups == 0;
}
}
const FString Filename(UFactory::CurrentFilename);
if (RootNodeToImport.Len() != 0 && InterestingNodeCount > 0)
{
int32 NodeIndex = 0;
int32 ImportedMeshCount = 0;
UStaticMesh* NewStaticMesh = NULL;
if (bCombineMeshes)
{
auto MeshNames = Builder.GetMeshNames(RootNodeToImport);
if (MeshNames.Num() > 0)
{
NewStaticMesh = Builder.ImportStaticMeshAsSingle(InParent, MeshNames, Name, Flags/*, ImportUI->StaticMeshImportData*/, NULL/*, 0*/);
for (auto Mesh : MeshNames)
{
Warn->Log(FString("Found mesh: ") + Mesh);
}
}
ImportedMeshCount = NewStaticMesh ? 1 : 0;
}
NewObject = NewStaticMesh;
}
else
{
if (RootNodeToImport == "")
{
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);
}
}
}
if (NewObject == NULL)
{
// Import fail error message
Builder.AddTokenizedErrorMessage(FTokenizedMessage::Create(EMessageSeverity::Error, LOCTEXT("FailedToImport_NoObject", "Import failed.")), FFbxErrors::Generic_ImportingNewObjectFailed);
Warn->Log(ELogVerbosity::Warning, "Failed to import GLTF mesh");
}
Warn->EndSlowTask();
FEditorDelegates::OnAssetPostImport.Broadcast(this, NewObject);
return NewObject;
}
bool UGLTFFactory::DoesSupportClass(UClass * Class)
{
return (Class == UStaticMesh::StaticClass());
}
bool UGLTFFactory::FactoryCanImport(const FString& Filename)
{
const FString Extension = FPaths::GetExtension(Filename);
if (Extension == TEXT("gltf"))
{
return true;
}
return false;
}
#undef LOCTEXT_NAMESPACE
\ No newline at end of file
/// @file GLTFFactory.h by Robert Poncelet
#pragma once
#include "Factories/Factory.h"
#include "GLTFFactory.generated.h"
UCLASS()
/// The class instantiated by the AssetToolsModule for importing the chosen UAsset into the content browser. Adapted from UFbxFactory.
class UGLTFFactory : public UFactory
{
GENERATED_BODY()
UGLTFFactory(const FObjectInitializer& ObjectInitializer);
/// @name UFactory Implementation
///@{
virtual bool DoesSupportClass(UClass * Class) override;
virtual UObject* FactoryCreateBinary(UClass* InClass, UObject* InParent, FName InName, EObjectFlags Flags, UObject* Context, const TCHAR* Type, const uint8*& Buffer, const uint8* BufferEnd, FFeedbackContext* Warn, bool& bOutOperationCanceled) override;
virtual bool FactoryCanImport(const FString& Filename) override;
///@}
bool bShowOption;
bool bDetectImportTypeOnImport;
/** true if the import operation was canceled. */
bool bOperationCanceled;
};
// Some copyright should be here...
#include "GLTFLoaderPrivatePCH.h"
#include "SlateBasics.h"
#include "SlateExtras.h"
#include "Developer/DesktopPlatform/Public/DesktopPlatformModule.h"
#include "Developer/AssetTools/Public/AssetToolsModule.h"
#include "GLTFLoaderStyle.h"
#include "GLTFLoaderCommands.h"
#include "GLTFFactory.h"
#include "LevelEditor.h"
static const FName GLTFLoaderTabName("GLTFLoader");
GLTFImportOptions FGLTFLoaderModule::ImportOptions = GLTFImportOptions::Default();
#define LOCTEXT_NAMESPACE "FGLTFLoaderModule"
void FGLTFLoaderModule::StartupModule()
{
FGLTFLoaderStyle::Initialize();
FGLTFLoaderStyle::ReloadTextures();
FGLTFLoaderCommands::Register();
PluginCommands = MakeShareable(new FUICommandList);
PluginCommands->MapAction(
FGLTFLoaderCommands::Get().OpenPluginWindow,
FExecuteAction::CreateRaw(this, &FGLTFLoaderModule::PluginButtonClicked),
FCanExecuteAction());
PluginCommands->MapAction(
FGLTFLoaderCommands::Get().OpenImportWindow,
FExecuteAction::CreateRaw(this, &FGLTFLoaderModule::OpenImportWindow),
FCanExecuteAction());
FLevelEditorModule& LevelEditorModule = FModuleManager::LoadModuleChecked<FLevelEditorModule>("LevelEditor");
{
TSharedPtr<FExtender> MenuExtender = MakeShareable(new FExtender());
MenuExtender->AddMenuExtension("WindowLayout", EExtensionHook::After, PluginCommands, FMenuExtensionDelegate::CreateRaw(this, &FGLTFLoaderModule::AddMenuExtension));
LevelEditorModule.GetMenuExtensibilityManager()->AddExtender(MenuExtender);
}
{
TSharedPtr<FExtender> ToolbarExtender = MakeShareable(new FExtender);
ToolbarExtender->AddToolBarExtension("Settings", EExtensionHook::After, PluginCommands, FToolBarExtensionDelegate::CreateRaw(this, &FGLTFLoaderModule::AddToolbarExtension));
LevelEditorModule.GetToolBarExtensibilityManager()->AddExtender(ToolbarExtender);
}
FGlobalTabmanager::Get()->RegisterNomadTabSpawner(GLTFLoaderTabName, FOnSpawnTab::CreateRaw(this, &FGLTFLoaderModule::OnSpawnPluginTab))
.SetDisplayName(LOCTEXT("FGLTFLoaderTabTitle", "GLTFLoader"))
.SetMenuType(ETabSpawnerMenuType::Hidden);
UE_LOG(LogInit, Warning, TEXT("GLTFLoader module started successfully."));
}
void FGLTFLoaderModule::ShutdownModule()
{
FGLTFLoaderStyle::Shutdown();
FGLTFLoaderCommands::Unregister();
FGlobalTabmanager::Get()->UnregisterNomadTabSpawner(GLTFLoaderTabName);
}
TSharedRef<SDockTab> FGLTFLoaderModule::OnSpawnPluginTab(const FSpawnTabArgs& SpawnTabArgs)
{
return SNew(SDockTab)
.TabRole(ETabRole::NomadTab)
[
SNew(SVerticalBox)
+ SVerticalBox::Slot()
.Padding(1.0f)
.HAlign(HAlign_Center)
.VAlign(VAlign_Top)
[
SNew(STextBlock)
.Text(LOCTEXT("TopText", "Import a glTF file"))
]
+ SVerticalBox::Slot()
.Padding(1.0f)
.HAlign(HAlign_Fill)
.VAlign(VAlign_Center)
[
SNew(SHorizontalBox)
+ SHorizontalBox::Slot()
.Padding(1.0f)
.HAlign(HAlign_Center)
.VAlign(VAlign_Center)
[
SNew(STextBlock)
.Text(LOCTEXT("ImportTranslation", "Import Translation"))
]
+ SHorizontalBox::Slot()
.Padding(1.0f)
.HAlign(HAlign_Center)
.VAlign(VAlign_Center)
[
SNew(SVectorInputBox)
.X_Raw(this, &FGLTFLoaderModule::GetImportTX)
.Y_Raw(this, &FGLTFLoaderModule::GetImportTY)
.Z_Raw(this, &FGLTFLoaderModule::GetImportTZ)
.bColorAxisLabels(true)
.AllowResponsiveLayout(true)
.OnXChanged_Raw(this, &FGLTFLoaderModule::SetImportTX)
.OnYChanged_Raw(this, &FGLTFLoaderModule::SetImportTY)
.OnZChanged_Raw(this, &FGLTFLoaderModule::SetImportTZ)
]
]
+ SVerticalBox::Slot()
.Padding(1.0f)
.HAlign(HAlign_Fill)
.VAlign(VAlign_Center)
[
SNew(SHorizontalBox)
+ SHorizontalBox::Slot()
.Padding(1.0f)
.HAlign(HAlign_Center)
.VAlign(VAlign_Center)
[
SNew(STextBlock)
.Text(LOCTEXT("ImportRotation", "Import Rotation"))
]
+ SHorizontalBox::Slot()
.Padding(1.0f)
.HAlign(HAlign_Center)
.VAlign(VAlign_Center)
[
SNew(SRotatorInputBox)
.Pitch_Raw(this, &FGLTFLoaderModule::GetImportRPitch)
.Yaw_Raw(this, &FGLTFLoaderModule::GetImportRYaw)
.Roll_Raw(this, &FGLTFLoaderModule::GetImportRRoll)
.bColorAxisLabels(true)
.AllowResponsiveLayout(true)
.OnPitchChanged_Raw(this, &FGLTFLoaderModule::SetImportRPitch)
.OnYawChanged_Raw(this, &FGLTFLoaderModule::SetImportRYaw)
.OnRollChanged_Raw(this, &FGLTFLoaderModule::SetImportRRoll)
]
]
+ SVerticalBox::Slot()
.Padding(1.0f)
.HAlign(HAlign_Fill)
.VAlign(VAlign_Center)
[
SNew(SHorizontalBox)
+ SHorizontalBox::Slot()
.Padding(1.0f)
.HAlign(HAlign_Center)
.VAlign(VAlign_Center)
[
SNew(STextBlock)
.Text(LOCTEXT("ImportScale", "Import Scale"))
]
+ SHorizontalBox::Slot()
.Padding(1.0f)
.HAlign(HAlign_Center)
.VAlign(VAlign_Center)
[
SNew(SNumericEntryBox<float>)
.Value_Raw(this, &FGLTFLoaderModule::GetImportScale)
.OnValueChanged_Raw(this, &FGLTFLoaderModule::SetImportScale)
]
]
+ SVerticalBox::Slot()
.Padding(1.0f)
.HAlign(HAlign_Fill)
.VAlign(VAlign_Center)
[
SNew(SHorizontalBox)
+ SHorizontalBox::Slot()
.Padding(1.0f)
.HAlign(HAlign_Center)
.VAlign(VAlign_Center)
[
SNew(STextBlock)
.Text(LOCTEXT("CorrectUp", "Correct Y up to Z up"))
]
+ SHorizontalBox::Slot()
.Padding(1.0f)
.HAlign(HAlign_Center)
.VAlign(VAlign_Center)
[
SNew(SCheckBox)
.IsChecked_Raw(this, &FGLTFLoaderModule::GetCorrectUp)
.OnCheckStateChanged_Raw(this, &FGLTFLoaderModule::SetCorrectUp)
]
]
+ SVerticalBox::Slot()
.Padding(1.0f)
.HAlign(HAlign_Center)
[
SNew(SBox)
.HAlign(HAlign_Center)
.VAlign(VAlign_Center)
[
SNew(SButton)
.OnClicked_Raw(this, &FGLTFLoaderModule::OpenImportWindowDelegateFunc)
.Content()
[
SNew(STextBlock)
.Text(LOCTEXT("ImportWindow", "Import File"))
]
]
]
];
}
void FGLTFLoaderModule::OpenImportWindow()
{
TArray<FString> Filenames;
if (FDesktopPlatformModule::Get()->OpenFileDialog(nullptr,
TEXT("Choose a GLTF file to import"),
TEXT(""),
TEXT(""),
TEXT("GL Transmission Format files (*.gltf)|*.gltf"),
EFileDialogFlags::None,
Filenames))
{
for (FString File : Filenames)
{
UE_LOG(LogTemp, Log, TEXT("File: %s"), *File);
}
FAssetToolsModule& AssetToolsModule = FModuleManager::Get().LoadModuleChecked<FAssetToolsModule>("AssetTools");
AssetToolsModule.Get().ImportAssets(Filenames, FString("/Game/Content"));
}
}
void FGLTFLoaderModule::PluginButtonClicked()
{
FGlobalTabmanager::Get()->InvokeTab(GLTFLoaderTabName);
}
void FGLTFLoaderModule::AddMenuExtension(FMenuBuilder& Builder)
{
Builder.AddMenuEntry(FGLTFLoaderCommands::Get().OpenPluginWindow);
}
void FGLTFLoaderModule::AddToolbarExtension(FToolBarBuilder& Builder)
{
Builder.AddToolBarButton(FGLTFLoaderCommands::Get().OpenPluginWindow);
}
// Delegate setters
void FGLTFLoaderModule::SetImportTX(float Value) { ImportOptions.ImportTranslation.X = Value; }
void FGLTFLoaderModule::SetImportTY(float Value) { ImportOptions.ImportTranslation.Y = Value; }
void FGLTFLoaderModule::SetImportTZ(float Value) { ImportOptions.ImportTranslation.Z = Value; }
void FGLTFLoaderModule::SetImportRPitch(float Value) { ImportOptions.ImportRotation.Pitch = Value; }
void FGLTFLoaderModule::SetImportRYaw(float Value) { ImportOptions.ImportRotation.Yaw = Value; }
void FGLTFLoaderModule::SetImportRRoll(float Value) { ImportOptions.ImportRotation.Roll = Value; }
void FGLTFLoaderModule::SetImportScale(float Value) { ImportOptions.ImportUniformScale = Value; }
void FGLTFLoaderModule::SetCorrectUp(ECheckBoxState Value) { ImportOptions.bCorrectUpDirection = (Value == ECheckBoxState::Checked); }
// Delegate getters
TOptional<float> FGLTFLoaderModule::GetImportTX() const { return ImportOptions.ImportTranslation.X; }
TOptional<float> FGLTFLoaderModule::GetImportTY() const { return ImportOptions.ImportTranslation.Y; }
TOptional<float> FGLTFLoaderModule::GetImportTZ() const { return ImportOptions.ImportTranslation.Z; }
TOptional<float> FGLTFLoaderModule::GetImportRPitch() const { return ImportOptions.ImportRotation.Pitch; }
TOptional<float> FGLTFLoaderModule::GetImportRYaw() const { return ImportOptions.ImportRotation.Yaw; }
TOptional<float> FGLTFLoaderModule::GetImportRRoll() const { return ImportOptions.ImportRotation.Roll; }
TOptional<float> FGLTFLoaderModule::GetImportScale() const { return ImportOptions.ImportUniformScale; }
ECheckBoxState FGLTFLoaderModule::GetCorrectUp() const { return ImportOptions.bCorrectUpDirection ? ECheckBoxState::Checked : ECheckBoxState::Unchecked; }
#undef LOCTEXT_NAMESPACE
IMPLEMENT_MODULE(FGLTFLoaderModule, GLTFLoader)
\ No newline at end of file
// Some copyright should be here...
#include "SlateBasics.h"
#include "GLTFLoader.h"
// You should place include statements to your module's private header files here. You only need to
// add includes for headers that are used in most of your module's source files though.
\ No newline at end of file
// Some copyright should be here...
#include "GLTFLoaderPrivatePCH.h"
#include "GLTFLoaderStyle.h"
#include "SlateGameResources.h"
#include "IPluginManager.h"
TSharedPtr< FSlateStyleSet > FGLTFLoaderStyle::StyleInstance = NULL;
void FGLTFLoaderStyle::Initialize()
{
if (!StyleInstance.IsValid())
{
StyleInstance = Create();
FSlateStyleRegistry::RegisterSlateStyle(*StyleInstance);
}
}
void FGLTFLoaderStyle::Shutdown()
{
FSlateStyleRegistry::UnRegisterSlateStyle(*StyleInstance);
ensure(StyleInstance.IsUnique());
StyleInstance.Reset();
}
FName FGLTFLoaderStyle::GetStyleSetName()
{
static FName StyleSetName(TEXT("GLTFLoaderStyle"));
return StyleSetName;
}
#define IMAGE_BRUSH( RelativePath, ... ) FSlateImageBrush( Style->RootToContentDir( RelativePath, TEXT(".png") ), __VA_ARGS__ )
#define BOX_BRUSH( RelativePath, ... ) FSlateBoxBrush( Style->RootToContentDir( RelativePath, TEXT(".png") ), __VA_ARGS__ )
#define BORDER_BRUSH( RelativePath, ... ) FSlateBorderBrush( Style->RootToContentDir( RelativePath, TEXT(".png") ), __VA_ARGS__ )
#define TTF_FONT( RelativePath, ... ) FSlateFontInfo( Style->RootToContentDir( RelativePath, TEXT(".ttf") ), __VA_ARGS__ )
#define OTF_FONT( RelativePath, ... ) FSlateFontInfo( Style->RootToContentDir( RelativePath, TEXT(".otf") ), __VA_ARGS__ )
const FVector2D Icon16x16(16.0f, 16.0f);
const FVector2D Icon20x20(20.0f, 20.0f);
const FVector2D Icon40x40(40.0f, 40.0f);
TSharedRef< FSlateStyleSet > FGLTFLoaderStyle::Create()
{
TSharedRef< FSlateStyleSet > Style = MakeShareable(new FSlateStyleSet("GLTFLoaderStyle"));
Style->SetContentRoot(IPluginManager::Get().FindPlugin("GLTFLoader")->GetBaseDir() / TEXT("Resources"));
Style->Set("GLTFLoader.OpenPluginWindow", new IMAGE_BRUSH(TEXT("ButtonIcon_40x"), Icon40x40));
return Style;
}
#undef IMAGE_BRUSH
#undef BOX_BRUSH
#undef BORDER_BRUSH
#undef TTF_FONT
#undef OTF_FONT
void FGLTFLoaderStyle::ReloadTextures()
{
FSlateApplication::Get().GetRenderer()->ReloadTextureResources();
}
const ISlateStyle& FGLTFLoaderStyle::Get()
{
return *StyleInstance;
}
/// @file GLTFMeshBuilder.h by Robert Poncelet
#pragma once
#include "UnrealString.h"
#include "TokenizedMessage.h"
#include "GLTFImportOptions.h"
#include <string>
#include <vector>
class UStaticMesh;
class UMaterialInterface;
struct FRawMesh;
/// 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.
namespace tinygltf
{
class TinyGLTFLoader;
class Scene;
class Node;
struct ACCESSOR;
typedef struct ACCESSOR Accessor;
struct PRIMITIVE;
typedef struct PRIMITIVE Primitive;
struct MESH;
typedef struct MESH Mesh;
struct MATERIAL;
typedef struct MATERIAL Material;
}
/// 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.
class GLTFMeshBuilder
{
public:
GLTFMeshBuilder(FString FilePath);
~GLTFMeshBuilder();
/// Returns whether we have a valid glTF scene loaded up. For a new MeshBuilder, this should always be queried before calling other functions.
bool LoadedSuccessfully() { return LoadSuccess; }
/// Returns the number of meshes owned by a given node.
int32 GetMeshCount(FString NodeName);
/// Returns the name of the scene's root node.
FString GetRootNode();
/// Obtains the mesh names of a node (and optionally its children); useful as an argument to <B>ImportStaticMeshAsSingle()</B>.
TArray<FString> GetMeshNames(FString NodeName, bool GetChildren = true);
/// Organises materials and builds the StaticMesh using a RawMesh filled with data using <B>BuildStaticMeshFromGeometry()</B>.
/// This function mirrors that in FFbxImporter of the same name.
/// @param InParent A pointer provided by the system importing the file (i.e. probably AssetImportModule) so we know where the saved package goes.
/// @param MeshNameArray An array of strings used as keys to obtain the actual meshes from the glTF scene.
/// @param InName The name of the package to be saved.
/// @param Flags Metadata used for the creation of the new package.
/// @param InStaticMesh A pointer to the StaticMesh to be built and have this new geometry added to it.
UStaticMesh* ImportStaticMeshAsSingle(UObject* InParent, TArray<FString>& MeshNameArray, const FName InName, EObjectFlags Flags, UStaticMesh* InStaticMesh);
/// Obtains the geometry data from the file and adds it to the RawMesh ready to be built for the StaticMesh.
/// This function mirrors that in FFbxImporter of the same name.
/// @param Mesh The glTF mesh to grab the data from.
/// @param StaticMesh The asset the mesh will be built for. This will eventually be the object serialised and saved in the import process.
/// @param MeshMaterials An array of materials to convert to those used by the engine and send to the build process.
/// @param LODIndex Level of detail for this mesh - currently unused i.e. always 0.
/// @param RawMesh The intermediate container for the data between the external format (glTF in our case) and the built StaticMesh.
bool BuildStaticMeshFromGeometry(tinygltf::Mesh* Mesh, UStaticMesh* StaticMesh, int LODIndex, FRawMesh& RawMesh);
/// Material/texture system does nothing currently.
UMaterialInterface* ToUMaterial(tinygltf::Material* Material);
void CreateUnrealMaterial(tinygltf::Material* Material, TArray<UMaterialInterface*>& OutMaterials) { return; };
int32 CreateNodeMaterials(tinygltf::Node* Node, TArray<UMaterialInterface*>& OutMaterials) { return 0; };
void ImportTexturesFromNode(tinygltf::Node* Node) { return; }
/// Logs an error message.
void AddTokenizedErrorMessage(TSharedRef<FTokenizedMessage> Error, FName ErrorName);
/// Returns the error message left by TinyGLTFLoader, if any.
FString GetError();
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).
template <typename T> bool ConvertAttrib(TArray<T> &OutArray, tinygltf::Mesh* Mesh, std::string AttribName, bool UseWedgeIndices = true, bool AutoSetArraySize = false);
///@}
/// @name Level 3: GetBufferData
///@{
/// Fills a TArray with typed data; works at the glTF Accessor level and figures out which arguments to send to <B>BufferCopy()</B>.
/// @param OutArray The array to fill with data from the imported file.
/// @param Accessor A pointer to a glTF Accessor containing the type data for the geometry attribute.
/// @param Append Whether to add to the array or overwrite the elements currently in it.
template <typename T> bool GetBufferData (TArray<T> &OutArray, tinygltf::Accessor* Accessor, bool Append = true);
template <> bool GetBufferData<FVector2D> (TArray<FVector2D> &OutArray, tinygltf::Accessor* Accessor, bool Append );
template <> bool GetBufferData<FVector> (TArray<FVector> &OutArray, tinygltf::Accessor* Accessor, bool Append );
template <> bool GetBufferData<FVector4> (TArray<FVector4> &OutArray, tinygltf::Accessor* Accessor, bool Append );
///@}
/// @name Level 2: BufferCopy
///@{
/// Handles filling the TArray at the data type level.
/// @param OutArray The array to fill with data from the imported file.
/// @param Data A pointer to the raw data to use as the argument to <B>BufferValue()</B>.
/// @param Count The number of elements to add to the array i.e. the number of calls to <B>BufferValue()</B>.
/// @param Stride The number of bytes between the first byte of each element - usually the size of one element.
template <typename SrcType, typename DstType> void BufferCopy(TArray<DstType> &OutArray, unsigned char* Data, int32 Count, size_t Stride);
template <typename SrcType> void BufferCopy(TArray<FVector2D> &OutArray, unsigned char* Data, int32 Count, size_t Stride);
template <typename SrcType> void BufferCopy(TArray<FVector> &OutArray, unsigned char* Data, int32 Count, size_t Stride);
template <typename SrcType> void BufferCopy(TArray<FVector4> &OutArray, unsigned char* Data, int32 Count, size_t Stride);
template <typename SrcType> void BufferCopy(TArray<FColor> &OutArray, int Type, unsigned char* Data, int32 Count, size_t Stride);
///@}
/// @name Level 1: BufferValue
///@{
/// Obtains a single value from the geometry data buffer, accounting for endianness.
/// Adapted from http://stackoverflow.com/questions/13001183/how-to-read-little-endian-integers-from-file-in-c
/// @param Data A pointer to the raw data to cast to the desired type.
/// @return The typed data value.
template <typename T> T BufferValue(void* Data);
///@}
/// Separate function to obtain material indices since it is not stored as a buffer. Should be called after MeshMaterials has been filled in.
void GetMaterialIndices(TArray<int32>& OutArray, tinygltf::Mesh& Mesh);
// Miscellaneous helper functions
/// Reverses the order of every group of 3 elements.
template<typename T> void ReverseTriDirection(TArray<T>& OutArray);
/// Whether a mesh's geometry has a specified attribute.
bool HasAttribute(tinygltf::Mesh* Mesh, std::string AttribName) const;
/// Similar to TArray's Find() function; returns the array index if the specified object was found, -1 otherwise.
template <typename T> int32 FindInStdVector(const std::vector<T> &InVector, const T &InElement) const;
/// Returns the transform of a node relative to its parent.
FMatrix GetNodeTransform(tinygltf::Node* Node);
/// Returns the size of the C++ data type given the corresponding glTF type.
size_t TypeSize(int Type) const;
/// Returns the number of triangle corners given a glTF primitive, taking into account its draw mode.
int32 GetNumWedges(tinygltf::Primitive* Prim) const;
/// Returns the owning node of a given mesh.
tinygltf::Node* GetMeshParentNode(tinygltf::Mesh* InMesh);
/// @name String Conversion
///@{
/// Helper functions for converting between Unreal's and STL's strings.
static FString ToFString(std::string InString);
static std::string ToStdString(FString InString);
///@}
///
TWeakObjectPtr<UObject> Parent;
tinygltf::TinyGLTFLoader* Loader;
tinygltf::Scene* Scene;
TArray<FString> MeshMaterials;
bool LoadSuccess;
FString Error;
};
This source diff could not be displayed because it is too large. You can view the blob instead.
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.
\ No newline at end of file
/// @file GLTFImportOptions.h by Robert Poncelet
#pragma once
//#include "Editor/UnrealEd/Classes/Factories/FbxStaticMeshImportData.h"
#include "UnrealString.h"
#include "Vector.h"
#include "Rotator.h"
#include "Color.h"
#include "NameTypes.h"
/// Used to store the information passed from the user to the import process - some of which is unused. This struct is adapted from FBXImportOptions.
struct GLTFImportOptions
{
// General options
bool bImportMaterials;
bool bInvertNormalMap;
bool bImportTextures;
bool bImportLOD;
bool bUsedAsFullName;
bool bConvertScene;
bool bRemoveNameSpace;
bool bPreserveLocalTransform;
FVector ImportTranslation;
FRotator ImportRotation;
float ImportUniformScale;
bool bCorrectUpDirection;
// Static Mesh options
bool bCombineToSingle;
FColor VertexOverrideColor;
bool bRemoveDegenerates;
bool bBuildAdjacencyBuffer;
bool bGenerateLightmapUVs;
bool bOneConvexHullPerUCX;
bool bAutoGenerateCollision;
FName StaticMeshLODGroup;
static GLTFImportOptions Default()
{
GLTFImportOptions ImportOptions;
ImportOptions.bAutoGenerateCollision = false;
ImportOptions.bBuildAdjacencyBuffer = true;
ImportOptions.bCombineToSingle = true;
ImportOptions.bConvertScene = false;
ImportOptions.bGenerateLightmapUVs = false;
ImportOptions.bImportLOD = false;
ImportOptions.bImportMaterials = false;
ImportOptions.bImportTextures = false;
ImportOptions.bInvertNormalMap = false;
ImportOptions.bOneConvexHullPerUCX = true;
ImportOptions.bPreserveLocalTransform = true;
ImportOptions.bRemoveDegenerates = false;
ImportOptions.bRemoveNameSpace = true;
ImportOptions.bUsedAsFullName = false;
ImportOptions.ImportRotation = FRotator(0.0f, 0.0f, 0.0f);
ImportOptions.ImportTranslation = FVector::ZeroVector;
ImportOptions.ImportUniformScale = 1.0f;
ImportOptions.StaticMeshLODGroup = NAME_None;
ImportOptions.VertexOverrideColor = FColor::White;
ImportOptions.bCorrectUpDirection = true;
return ImportOptions;
}
};
/// @file GLTFLoader.h by Robert Poncelet
#pragma once
#include "ModuleManager.h"
#include "SlateBasics.h"
#include "GLTFImportOptions.h"
class FToolBarBuilder;
class FMenuBuilder;
///
/// \brief The top-level class in the plugin module.
///
/// This class handles the UI and the corresponding actions to set off the importing
/// process. Functions/members provided as boilerplate by Unreal's plugin creation
/// wizard are marked with \"<B>(Boilerplate)</B>\".
///
class FGLTFLoaderModule : public IModuleInterface
{
public:
///@name <B>(Boilerplate)</B> IModuleInterface implementation.
///@{
virtual void StartupModule() override;
virtual void ShutdownModule() override;
///@}
/// <B>(Boilerplate)</B> This function will be bound to a TCommand to bring up the plugin window.
void PluginButtonClicked();
/// Opens the file browser for the user to select a file to import.
void OpenImportWindow();
/// Since this class doesn't instantiate the Factory directly, the import options are provided statically and publicly so that GLTFFactory can access them itself.
static GLTFImportOptions ImportOptions;
private:
/// Boilerplate
void AddToolbarExtension(FToolBarBuilder& Builder);
void AddMenuExtension(FMenuBuilder& Builder);
/// Bound to the import button's OnClicked event which expects an FReply; OpenImportWindow() itself is used for FGLTFLoaderCommands which expects a void.
FReply OpenImportWindowDelegateFunc() { OpenImportWindow(); return FReply::Handled(); }
/// @name UI Setters
///@{
/// These functions are bound to the UI elements when they are created and called to update the options' data when the user modifies the values.
void SetImportTX (float Value);
void SetImportTY (float Value);
void SetImportTZ (float Value);
void SetImportRPitch (float Value);
void SetImportRYaw (float Value);
void SetImportRRoll (float Value);
void SetImportScale (float Value);
void SetCorrectUp (ECheckBoxState Value);
///@}
/// @name UI Getters
///@{
/// These functions are bound to the UI elements when they are created and called to validate the displayed UI values once the options' data is updated.
TOptional<float> GetImportTX() const;
TOptional<float> GetImportTY() const;
TOptional<float> GetImportTZ() const;
TOptional<float> GetImportRPitch() const;
TOptional<float> GetImportRYaw() const;
TOptional<float> GetImportRRoll() const;
TOptional<float> GetImportScale() const;
ECheckBoxState GetCorrectUp() const;
///@}
/// <B>(Boilerplate)</B> Brings up the main plugin window.
TSharedRef<class SDockTab> OnSpawnPluginTab(const class FSpawnTabArgs& SpawnTabArgs);
private:
/// <B>(Boilerplate)</B> Used to link with FGLTFLoaderCommands.
TSharedPtr<class FUICommandList> PluginCommands;
};
\ No newline at end of file
// Some copyright should be here...
#include "GLTFLoaderPrivatePCH.h"
#include "GLTFLoaderCommands.h"
#define LOCTEXT_NAMESPACE "FGLTFLoaderModule"
void FGLTFLoaderCommands::RegisterCommands()
{
UI_COMMAND(OpenPluginWindow, "GLTFLoader", "Bring up GLTFLoader window", EUserInterfaceActionType::Button, FInputGesture());
UI_COMMAND(OpenImportWindow, "GLTF Import Window", "Choose a GLTF file to import", EUserInterfaceActionType::Button, FInputGesture());
}
#undef LOCTEXT_NAMESPACE
/// @file GLTFLoaderCommands.h by Robert Poncelet
#pragma once
#include "SlateBasics.h"
#include "GLTFLoaderStyle.h"
/// Boilerplate class provided by Unreal.
class FGLTFLoaderCommands : public TCommands<FGLTFLoaderCommands>
{
public:
FGLTFLoaderCommands()
: TCommands<FGLTFLoaderCommands>(TEXT("GLTFLoader"), NSLOCTEXT("Contexts", "GLTFLoader", "GLTFLoader Plugin"), NAME_None, FGLTFLoaderStyle::GetStyleSetName())
{
}
// TCommands<> interface
virtual void RegisterCommands() override;
public:
TSharedPtr< FUICommandInfo > OpenPluginWindow;
TSharedPtr< FUICommandInfo > OpenImportWindow;
};
\ No newline at end of file
/// @file GLTFLoaderStyle.h by Robert Poncelet
#pragma once
#include "SlateBasics.h"
/// Boilerplate class provided by Unreal.
class FGLTFLoaderStyle
{
public:
static void Initialize();
static void Shutdown();
/** reloads textures used by slate renderer */
static void ReloadTextures();
/** @return The Slate style set for the Shooter game */
static const ISlateStyle& Get();
static FName GetStyleSetName();
private:
static TSharedRef< class FSlateStyleSet > Create();
private:
static TSharedPtr< class FSlateStyleSet > StyleInstance;
};
\ No newline at end of file
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment