2014-03-14 14:13:41 -04:00
// Copyright 1998-2014 Epic Games, Inc. All Rights Reserved.
# include "UnrealEd.h"
# include "RawMesh.h"
# include "MeshUtilities.h"
# include "SimplygonSDK.h"
# include "MeshBoneReduction.h"
# include "MaterialExportUtils.h"
2014-06-18 07:25:31 -04:00
# include "ComponentReregisterContext.h"
2014-03-14 14:13:41 -04:00
# define LOCTEXT_NAMESPACE "SimplygonMeshReduction"
class FSimplygonMeshReductionModule : public IMeshReductionModule
{
public :
// IModuleInterface interface.
2014-06-13 06:14:46 -04:00
virtual void StartupModule ( ) override ;
virtual void ShutdownModule ( ) override ;
2014-03-14 14:13:41 -04:00
// IMeshReductionModule interface.
2014-06-13 06:14:46 -04:00
virtual class IMeshReduction * GetMeshReductionInterface ( ) override ;
virtual class IMeshMerging * GetMeshMergingInterface ( ) override ;
2014-03-14 14:13:41 -04:00
} ;
DEFINE_LOG_CATEGORY_STATIC ( LogSimplygon , Log , All ) ;
IMPLEMENT_MODULE ( FSimplygonMeshReductionModule , SimplygonMeshReduction ) ;
# define SIMPLYGON_COLOR_CHANNEL "VertexColors"
/** Receives error messages generated by Simplygon. These errors are presented via a message box. */
class FDefaultErrorHandler : public SimplygonSDK : : rerrorhandler
{
public :
virtual void HandleError (
SimplygonSDK : : IObject * Object ,
const char * InterfaceName ,
const char * MethodName ,
SimplygonSDK : : rid ErrorType ,
const char * ErrorText )
{
FString ErrorString = FString : : Printf ( TEXT ( " Simplygon Error: \n \n Interface: %s \n Method: %s \n Error: (%d) %s " ) ,
ANSI_TO_TCHAR ( InterfaceName ) ,
ANSI_TO_TCHAR ( MethodName ) ,
ErrorType ,
ANSI_TO_TCHAR ( ErrorText )
) ;
UE_LOG ( LogSimplygon , Log , TEXT ( " %s " ) , * ErrorString ) ;
//FMessageDialog::Open(EAppMsgType::Ok, *ErrorString);
}
} ;
/** Receives progress events from Simplygon and updates the status window. */
class FDefaultEventHandler : public SimplygonSDK : : robserver
{
public :
virtual void Execute (
SimplygonSDK : : IObject * Object ,
SimplygonSDK : : rid EventId ,
void * EventParameterBlock ,
unsigned int EventParameterBlockSize )
{
if ( EventId = = SimplygonSDK : : SG_EVENT_PROGRESS )
{
check ( sizeof ( int32 ) = = EventParameterBlockSize ) ;
int32 ProgressPercent = * ( ( int32 * ) EventParameterBlock ) ;
GWarn - > UpdateProgress ( ProgressPercent , 100 ) ;
// We are required to pass '1' back through the EventParametersBlock for the process to continue.
* ( ( int32 * ) EventParameterBlock ) = 1 ;
}
}
} ;
/** Winding modes. */
enum EWindingMode
{
/** Maintain the winding of the mesh. */
WINDING_Keep ,
/** Reverse the winding of the mesh. */
WINDING_Reverse ,
WINDING_MAX
} ;
class FSimplygonMeshReduction
: public IMeshReduction
, public IMeshMerging
{
public :
2014-06-13 06:14:46 -04:00
virtual const FString & GetVersionString ( ) const override
2014-03-14 14:13:41 -04:00
{
return VersionString ;
}
virtual void Reduce (
FRawMesh & OutReducedMesh ,
float & OutMaxDeviation ,
const FRawMesh & InMesh ,
const FMeshReductionSettings & InSettings
)
{
SimplygonSDK : : spGeometryData GeometryData = CreateGeometryFromRawMesh ( InMesh ) ;
check ( GeometryData ) ;
SimplygonSDK : : spReductionProcessor ReductionProcessor = SDK - > CreateReductionProcessor ( ) ;
ReductionProcessor - > AddObserver ( & EventHandler , SimplygonSDK : : SG_EVENT_PROGRESS ) ;
ReductionProcessor - > SetGeometry ( GeometryData ) ;
SimplygonSDK : : spRepairSettings RepairSettings = ReductionProcessor - > GetRepairSettings ( ) ;
RepairSettings - > SetWeldDist ( InSettings . WeldingThreshold ) ;
RepairSettings - > SetTjuncDist ( InSettings . WeldingThreshold ) ;
SimplygonSDK : : spReductionSettings ReductionSettings = ReductionProcessor - > GetReductionSettings ( ) ;
SetReductionSettings ( ReductionSettings , InSettings , GeometryData - > GetTriangleCount ( ) ) ;
SimplygonSDK : : spNormalCalculationSettings NormalSettings = ReductionProcessor - > GetNormalCalculationSettings ( ) ;
SetNormalSettings ( NormalSettings , InSettings ) ;
ReductionProcessor - > RunProcessing ( ) ;
CreateRawMeshFromGeometry ( OutReducedMesh , GeometryData , WINDING_Keep ) ;
OutMaxDeviation = ReductionProcessor - > GetMaxDeviation ( ) ;
}
bool ReduceLODModel (
FStaticLODModel * SrcModel ,
FStaticLODModel * & OutModel ,
FBoxSphereBounds & Bounds ,
float & MaxDeviation ,
const FReferenceSkeleton & RefSkeleton ,
const FSkeletalMeshOptimizationSettings & Settings
)
{
const bool bUsingMaxDeviation = ( Settings . ReductionMethod = = SMOT_MaxDeviation & & Settings . MaxDeviationPercentage > 0.0f ) ;
const bool bUsingReductionRatio = ( Settings . ReductionMethod = = SMOT_NumOfTriangles & & Settings . NumOfTrianglesPercentage < 1.0f ) ;
const bool bProcessGeometry = ( bUsingMaxDeviation | | bUsingReductionRatio ) ;
const bool bProcessBones = ( Settings . BoneReductionRatio < 1.0f | | Settings . MaxBonesPerVertex < MAX_TOTAL_INFLUENCES ) ;
const bool bOptimizeMesh = ( bProcessGeometry | | bProcessBones ) ;
// We'll need to store the max deviation after optimization if we wish to recalculate the LOD's display distance
MaxDeviation = 0.0f ;
if ( bOptimizeMesh )
{
//Create a simplygon scene. The scene by default contains a bone table that is required for bone reduction.
SimplygonSDK : : spScene Scene = SDK - > CreateScene ( ) ;
check ( Scene ) ;
// Create bone hierarchy for simplygon.
TArray < SimplygonSDK : : rid > BoneTableIDs ;
CreateSkeletalHierarchy ( Scene , RefSkeleton , BoneTableIDs ) ;
// Create a new scene mesh object
SimplygonSDK : : spGeometryData GeometryData = CreateGeometryFromSkeletalLODModel ( Scene , * SrcModel , BoneTableIDs ) ;
FDefaultEventHandler SimplygonEventHandler ;
SimplygonSDK : : spReductionProcessor ReductionProcessor = SDK - > CreateReductionProcessor ( ) ;
ReductionProcessor - > AddObserver ( & EventHandler , SimplygonSDK : : SG_EVENT_PROGRESS ) ;
ReductionProcessor - > SetSceneRoot ( Scene - > GetRootNode ( ) ) ;
SimplygonSDK : : spRepairSettings RepairSettings = ReductionProcessor - > GetRepairSettings ( ) ;
RepairSettings - > SetWeldDist ( Settings . WeldingThreshold ) ;
RepairSettings - > SetTjuncDist ( Settings . WeldingThreshold ) ;
SimplygonSDK : : spReductionSettings ReductionSettings = ReductionProcessor - > GetReductionSettings ( ) ;
SetReductionSettings ( Settings , Bounds . SphereRadius , GeometryData - > GetTriangleCount ( ) , ReductionSettings ) ;
SimplygonSDK : : spNormalCalculationSettings NormalSettings = ReductionProcessor - > GetNormalCalculationSettings ( ) ;
SetNormalSettings ( Settings , NormalSettings ) ;
if ( bProcessBones )
{
SimplygonSDK : : spBoneSettings BoneSettings = ReductionProcessor - > GetBoneSettings ( ) ;
SetBoneSettings ( Settings , BoneSettings ) ;
}
ReductionProcessor - > RunProcessing ( ) ;
// We require the max deviation if we're calculating the LOD's display distance.
MaxDeviation = ReductionProcessor - > GetMaxDeviation ( ) ;
CreateSkeletalLODModelFromGeometry ( GeometryData , RefSkeleton , OutModel ) ;
}
return bOptimizeMesh ;
}
virtual bool ReduceSkeletalMesh (
USkeletalMesh * SkeletalMesh ,
int32 LODIndex ,
const FSkeletalMeshOptimizationSettings & Settings ,
bool bCalcLODDistance
)
{
check ( SkeletalMesh ) ;
check ( LODIndex > = 0 ) ;
check ( LODIndex < = SkeletalMesh - > LODInfo . Num ( ) ) ;
FSkeletalMeshResource * SkeletalMeshResource = SkeletalMesh - > GetImportedResource ( ) ;
check ( SkeletalMeshResource ) ;
check ( LODIndex < = SkeletalMeshResource - > LODModels . Num ( ) ) ;
FStaticLODModel * SrcModel = & SkeletalMesh - > PreModifyMesh ( ) ;
TComponentReregisterContext < USkinnedMeshComponent > ReregisterContext ;
SkeletalMesh - > ReleaseResources ( ) ;
SkeletalMesh - > ReleaseResourcesFence . Wait ( ) ;
// Insert a new LOD model entry if needed.
if ( LODIndex = = SkeletalMeshResource - > LODModels . Num ( ) )
{
SkeletalMeshResource - > LODModels . AddRawItem ( 0 ) ;
}
// We'll need to store the max deviation after optimization if we wish to recalculate the LOD's display distance
float MaxDeviation = 0.0f ;
// Swap in a new model, delete the old.
check ( LODIndex < SkeletalMeshResource - > LODModels . Num ( ) ) ;
FStaticLODModel * * LODModels = SkeletalMeshResource - > LODModels . GetTypedData ( ) ;
delete LODModels [ LODIndex ] ;
// Copy over LOD info from LOD0 if there is no previous info.
if ( LODIndex = = SkeletalMesh - > LODInfo . Num ( ) )
{
FSkeletalMeshLODInfo * NewLODInfo = new ( SkeletalMesh - > LODInfo ) FSkeletalMeshLODInfo ;
FSkeletalMeshLODInfo & OldLODInfo = SkeletalMesh - > LODInfo [ 0 ] ;
* NewLODInfo = OldLODInfo ;
2014-06-26 09:56:29 -04:00
// creates LOD Material map for a newly generated LOD model
int32 NumSections = LODModels [ 0 ] - > NumNonClothingSections ( ) ;
if ( NewLODInfo - > LODMaterialMap . Num ( ) ! = NumSections )
{
NewLODInfo - > LODMaterialMap . Empty ( NumSections ) ;
NewLODInfo - > LODMaterialMap . AddUninitialized ( NumSections ) ;
}
for ( int32 Index = 0 ; Index < NumSections ; Index + + )
{
NewLODInfo - > LODMaterialMap [ Index ] = Index ;
}
2014-03-14 14:13:41 -04:00
}
// now try bone reduction process if it's setup
TMap < FBoneIndexType , FBoneIndexType > BonesToRemove ;
IMeshBoneReductionModule & MeshBoneReductionModule = FModuleManager : : Get ( ) . LoadModuleChecked < IMeshBoneReductionModule > ( " MeshBoneReduction " ) ;
IMeshBoneReduction * MeshBoneReductionInterface = MeshBoneReductionModule . GetMeshBoneReductionInterface ( ) ;
// See if we'd like to remove extra bones first
if ( MeshBoneReductionInterface - > GetBoneReductionData ( SkeletalMesh , LODIndex , BonesToRemove ) )
{
// if we do, now create new model and make a copy of SrcMesh to cut the bone count
FStaticLODModel * NewSrcModel = new FStaticLODModel ( ) ;
// Bulk data arrays need to be locked before a copy can be made.
SrcModel - > RawPointIndices . Lock ( LOCK_READ_ONLY ) ;
SrcModel - > LegacyRawPointIndices . Lock ( LOCK_READ_ONLY ) ;
* NewSrcModel = * SrcModel ;
SrcModel - > RawPointIndices . Unlock ( ) ;
SrcModel - > LegacyRawPointIndices . Unlock ( ) ;
// The index buffer needs to be rebuilt on copy.
FMultiSizeIndexContainerData IndexBufferData ;
SrcModel - > MultiSizeIndexContainer . GetIndexBufferData ( IndexBufferData ) ;
NewSrcModel - > MultiSizeIndexContainer . RebuildIndexBuffer ( IndexBufferData ) ;
// now fix up SrcModel to NewSrcModel
SrcModel = NewSrcModel ;
// fix up chunks to remove the bones that set to be removed
for ( int32 ChunkIndex = 0 ; ChunkIndex < NewSrcModel - > Chunks . Num ( ) ; + + ChunkIndex )
{
MeshBoneReductionInterface - > FixUpChunkBoneMaps ( NewSrcModel - > Chunks [ ChunkIndex ] , BonesToRemove ) ;
}
}
FStaticLODModel * NewModel = new FStaticLODModel ( ) ;
LODModels [ LODIndex ] = NewModel ;
// Reduce LOD model with SrcMesh
if ( ReduceLODModel ( SrcModel , NewModel , SkeletalMesh - > Bounds , MaxDeviation , SkeletalMesh - > RefSkeleton , Settings ) )
{
if ( bCalcLODDistance )
{
float ViewDistance = CalculateViewDistance ( MaxDeviation ) ;
2014-07-17 05:14:00 -04:00
SkeletalMesh - > LODInfo [ LODIndex ] . ScreenSize = 2.0f * SkeletalMesh - > Bounds . SphereRadius / ViewDistance ;
2014-03-14 14:13:41 -04:00
}
// Flag this LOD as having been simplified.
SkeletalMesh - > LODInfo [ LODIndex ] . bHasBeenSimplified = true ;
SkeletalMesh - > bHasBeenSimplified = true ;
}
else
{
// Bulk data arrays need to be locked before a copy can be made.
SrcModel - > RawPointIndices . Lock ( LOCK_READ_ONLY ) ;
SrcModel - > LegacyRawPointIndices . Lock ( LOCK_READ_ONLY ) ;
* NewModel = * SrcModel ;
SrcModel - > RawPointIndices . Unlock ( ) ;
SrcModel - > LegacyRawPointIndices . Unlock ( ) ;
// The index buffer needs to be rebuilt on copy.
FMultiSizeIndexContainerData IndexBufferData ;
SrcModel - > MultiSizeIndexContainer . GetIndexBufferData ( IndexBufferData ) ;
NewModel - > MultiSizeIndexContainer . RebuildIndexBuffer ( IndexBufferData ) ;
// Required bones are recalculated later on.
NewModel - > RequiredBones . Empty ( ) ;
SkeletalMesh - > LODInfo [ LODIndex ] . bHasBeenSimplified = false ;
}
SkeletalMesh - > CalculateRequiredBones ( SkeletalMeshResource - > LODModels [ LODIndex ] , SkeletalMesh - > RefSkeleton , & BonesToRemove ) ;
SkeletalMesh - > PostEditChange ( ) ;
SkeletalMesh - > InitResources ( ) ;
if ( LODIndex > = SkeletalMesh - > OptimizationSettings . Num ( ) )
{
FSkeletalMeshOptimizationSettings DefaultSettings ;
const FSkeletalMeshOptimizationSettings SettingsToCopy =
SkeletalMesh - > OptimizationSettings . Num ( ) ? SkeletalMesh - > OptimizationSettings . Last ( ) : DefaultSettings ;
while ( LODIndex > = SkeletalMesh - > OptimizationSettings . Num ( ) )
{
SkeletalMesh - > OptimizationSettings . Add ( SettingsToCopy ) ;
}
}
check ( LODIndex < SkeletalMesh - > OptimizationSettings . Num ( ) ) ;
SkeletalMesh - > OptimizationSettings [ LODIndex ] = Settings ;
return true ;
}
bool IsSupported ( ) const
{
return true ;
}
static FSimplygonMeshReduction * Create ( )
{
2014-06-11 08:17:57 -04:00
FString DllPath ( FPaths : : Combine ( * FPaths : : EngineDir ( ) , TEXT ( " Binaries/ThirdParty/NotForLicensees/Simplygon " ) ) ) ;
FString DllFilename ( FPaths : : Combine ( * DllPath , TEXT ( " SimplygonSDKEpicUE4Releasex64.dll " ) ) ) ;
if ( ! FPaths : : FileExists ( DllFilename ) )
2014-03-17 11:05:33 -04:00
{
2014-06-11 08:17:57 -04:00
DllFilename = FPaths : : Combine ( * DllPath , TEXT ( " SimplygonSDKRuntimeReleasex64.dll " ) ) ;
}
// If the DLL just doesn't exist, fail gracefully. Licensees and Rocket users will not necessarily have Simplygon.
if ( ! FPaths : : FileExists ( DllFilename ) )
{
UE_LOG ( LogSimplygon , Warning , TEXT ( " Simplygon DLL not present - disabling. " ) ) ;
2014-03-17 11:05:33 -04:00
return NULL ;
}
2014-06-11 08:17:57 -04:00
// Otherwise fail
2014-03-14 14:13:41 -04:00
void * DLLHandle = FPlatformProcess : : GetDllHandle ( * DllFilename ) ;
if ( DLLHandle = = NULL )
{
int32 ErrorNum = FPlatformMisc : : GetLastError ( ) ;
TCHAR ErrorMsg [ 1024 ] ;
FPlatformMisc : : GetSystemErrorMessage ( ErrorMsg , 1024 , ErrorNum ) ;
2014-06-11 08:17:57 -04:00
UE_LOG ( LogSimplygon , Error , TEXT ( " Failed to get Simplygon DLL handle: %s (%d) " ) , ErrorMsg , ErrorNum ) ;
2014-03-14 14:13:41 -04:00
return NULL ;
}
2014-06-11 08:17:57 -04:00
// Get API function pointers of interest
typedef void ( * GetInterfaceVersionSimplygonSDKPtr ) ( ANSICHAR * ) ;
GetInterfaceVersionSimplygonSDKPtr GetInterfaceVersionSimplygonSDK = ( GetInterfaceVersionSimplygonSDKPtr ) FPlatformProcess : : GetDllExport ( DLLHandle , TEXT ( " GetInterfaceVersionSimplygonSDK " ) ) ;
typedef int ( * InitializeSimplygonSDKPtr ) ( const char * LicenseData , SimplygonSDK : : ISimplygonSDK * * OutInterfacePtr ) ;
InitializeSimplygonSDKPtr InitializeSimplygonSDK = ( InitializeSimplygonSDKPtr ) FPlatformProcess : : GetDllExport ( DLLHandle , TEXT ( " InitializeSimplygonSDK " ) ) ;
if ( ( GetInterfaceVersionSimplygonSDK = = NULL ) | | ( InitializeSimplygonSDK = = NULL ) )
{
// Couldn't find the functions we need.
UE_LOG ( LogSimplygon , Warning , TEXT ( " Failed to acquire Simplygon DLL exports. " ) ) ;
FPlatformProcess : : FreeDllHandle ( DLLHandle ) ;
return NULL ;
}
ANSICHAR VersionHash [ 200 ] ;
2014-03-14 14:13:41 -04:00
GetInterfaceVersionSimplygonSDK ( VersionHash ) ;
if ( FCStringAnsi : : Strcmp ( VersionHash , SimplygonSDK : : GetInterfaceVersionHash ( ) ) ! = 0 )
{
UE_LOG ( LogSimplygon , Warning , TEXT ( " Library version mismatch. Header=%s Lib=%s " ) , ANSI_TO_TCHAR ( SimplygonSDK : : GetInterfaceVersionHash ( ) ) , ANSI_TO_TCHAR ( VersionHash ) ) ;
return NULL ;
}
const char * LicenseData = NULL ;
TArray < uint8 > LicenseFileContents ;
if ( FFileHelper : : LoadFileToArray ( LicenseFileContents , * FPaths : : Combine ( * DllPath , TEXT ( " license.dat " ) ) , FILEREAD_Silent ) & & LicenseFileContents . Num ( ) > 0 )
{
LicenseData = ( const char * ) LicenseFileContents . GetTypedData ( ) ;
}
2014-06-11 08:17:57 -04:00
SimplygonSDK : : ISimplygonSDK * SDK = NULL ;
2014-03-14 14:13:41 -04:00
int32 Result = InitializeSimplygonSDK ( LicenseData , & SDK ) ;
if ( Result ! = SimplygonSDK : : SG_ERROR_NOERROR & & Result ! = SimplygonSDK : : SG_ERROR_ALREADYINITIALIZED )
{
UE_LOG ( LogSimplygon , Warning , TEXT ( " Failed to initialize Simplygon. Error: %d. " ) , Result ) ;
SDK = NULL ;
return NULL ;
}
return new FSimplygonMeshReduction ( SDK ) ;
}
struct FMaterialCastingProperties
{
bool bCastMaterials ;
bool bCastNormals ;
FMaterialCastingProperties ( )
: bCastNormals ( false )
, bCastMaterials ( false )
{
}
} ;
// IMeshMerging interface
virtual void BuildProxy (
const TArray < FRawMesh > & InputMeshes ,
const TArray < MaterialExportUtils : : FFlattenMaterial > & InputMaterials ,
const struct FMeshProxySettings & InProxySettings ,
FRawMesh & OutProxyMesh ,
2014-06-13 06:14:46 -04:00
MaterialExportUtils : : FFlattenMaterial & OutMaterial ) override
2014-03-14 14:13:41 -04:00
{
if ( InputMeshes . Num ( ) = = 0 )
{
return ;
}
//Create a Simplygon Scene
SimplygonSDK : : spScene Scene = SDK - > CreateScene ( ) ;
//Material table for the original materials
SimplygonSDK : : spMaterialTable OriginalMaterials = Scene - > GetMaterialTable ( ) ;
//Build simplygon materials from the original asset materials
FMaterialCastingProperties CastProperties ;
CastProperties . bCastMaterials = CreateSGMaterialFromFlattenMaterial ( InputMaterials , OriginalMaterials , CastProperties ) ;
//For each raw mesh in array create a scene mesh and populate with geometry data
for ( int32 MeshIndex = 0 ; MeshIndex < InputMeshes . Num ( ) ; + + MeshIndex )
{
SimplygonSDK : : spSceneMesh Mesh = SDK - > CreateSceneMesh ( ) ;
SimplygonSDK : : spGeometryData GeometryData = CreateGeometryFromRawMesh ( InputMeshes [ MeshIndex ] ) ;
check ( GeometryData )
# ifdef DEBUG_PROXY_MESH
SimplygonSDK : : spWavefrontExporter objexp = SDK - > CreateWavefrontExporter ( ) ;
objexp - > SetExportFilePath ( " d:/BeforeProxyMesh.obj " ) ;
objexp - > SetSingleGeometry ( GeometryData ) ;
objexp - > RunExport ( ) ;
# endif
Mesh - > SetGeometry ( GeometryData ) ;
Mesh - > SetName ( TCHAR_TO_ANSI ( * FString : : Printf ( TEXT ( " Mesh%d " ) , MeshIndex ) ) ) ;
Scene - > GetRootNode ( ) - > AddChild ( Mesh ) ;
}
//Create a remesher
SimplygonSDK : : spRemeshingProcessor RemeshingProcessor = SDK - > CreateRemeshingProcessor ( ) ;
//Setup the remesher
RemeshingProcessor - > AddObserver ( & EventHandler , SimplygonSDK : : SG_EVENT_PROGRESS ) ;
RemeshingProcessor - > GetRemeshingSettings ( ) - > SetOnScreenSize ( InProxySettings . ScreenSize ) ;
RemeshingProcessor - > GetRemeshingSettings ( ) - > SetMergeDistance ( InProxySettings . MergeDistance ) ;
RemeshingProcessor - > GetRemeshingSettings ( ) - > SetUseGroundPlane ( InProxySettings . bUseClippingPlane ) ;
RemeshingProcessor - > GetRemeshingSettings ( ) - > SetGroundPlaneAxisIndex ( InProxySettings . AxisIndex ) ; // 0:X-Axis, 1:Y-Axis, 2:Z-Axis
RemeshingProcessor - > GetRemeshingSettings ( ) - > SetGroundPlaneLevel ( InProxySettings . ClippingLevel ) ;
// Goal is: If user specifies negative clipping plane -> negative halfspace should be clipped
if ( InProxySettings . AxisIndex < = 1 ) // Invert X and Y axis
{
RemeshingProcessor - > GetRemeshingSettings ( ) - > SetGroundPlaneNegativeHalfspace ( ! InProxySettings . bPlaneNegativeHalfspace ) ;
}
else
{
RemeshingProcessor - > GetRemeshingSettings ( ) - > SetGroundPlaneNegativeHalfspace ( InProxySettings . bPlaneNegativeHalfspace ) ;
}
RemeshingProcessor - > GetRemeshingSettings ( ) - > SetTransferNormals ( false ) ;
RemeshingProcessor - > GetRemeshingSettings ( ) - > SetMergeDistance ( InProxySettings . MergeDistance ) ;
RemeshingProcessor - > GetRemeshingSettings ( ) - > SetHardEdgeAngle ( FMath : : DegreesToRadians ( InProxySettings . HardAngleThreshold ) ) ; //This should be a user settings in the popup dialog!
RemeshingProcessor - > SetSceneRoot ( Scene - > GetRootNode ( ) ) ;
//Setup the mapping image used for casting
SimplygonSDK : : spMappingImageSettings MappingSettings = RemeshingProcessor - > GetMappingImageSettings ( ) ;
MappingSettings - > SetGenerateMappingImage ( true ) ;
MappingSettings - > SetGenerateTexCoords ( true ) ;
MappingSettings - > SetGenerateTangents ( false ) ;
MappingSettings - > SetWidth ( InProxySettings . TextureWidth ) ;
MappingSettings - > SetHeight ( InProxySettings . TextureHeight ) ;
//Start remeshing the geometry
RemeshingProcessor - > RemeshGeometry ( ) ;
if ( CastProperties . bCastMaterials )
{
//Collect the mapping image from the remeshing process
SimplygonSDK : : spMappingImage MappingImage = RemeshingProcessor - > GetMappingImage ( ) ;
//Create a new material for the proxy geometry
SimplygonSDK : : spMaterial OutputMaterialLOD = SDK - > CreateMaterial ( ) ;
//Create Image data where the diffuse data is stored
SimplygonSDK : : spImageData OutputDiffuseData = SDK - > CreateImageData ( ) ;
//Cast diffuse texture data
{
// Cast the data using a color caster
SimplygonSDK : : spColorCaster cast = SDK - > CreateColorCaster ( ) ;
cast - > SetColorType ( SimplygonSDK : : SG_MATERIAL_CHANNEL_DIFFUSE ) ;
cast - > SetSourceMaterials ( OriginalMaterials ) ;
cast - > SetMappingImage ( MappingImage ) ; // The mapping image we got from the remeshing process.
cast - > SetOutputChannels ( 4 ) ; // RGB, 3 channels! (1 would be for grey scale, and 4 would be for RGBA.)
cast - > SetOutputChannelBitDepth ( 8 ) ; // 8 bits per channel. So in this case we will have 24bit colors RGB.
cast - > SetDilation ( 10 ) ; // To avoid mip-map artifacts, the empty pixels on the map needs to be filled to a degree aswell.
cast - > SetOutputImage ( OutputDiffuseData ) ;
cast - > CastMaterials ( ) ; // Fetch!
// set the material properties
// Set the diffuse multiplier for the texture. 1 means it will not differ from original texture,
// For example: 0 would ignore a specified color and 2 would make a color twice as pronounced as the others.
OutputMaterialLOD - > SetDiffuseRed ( 1 ) ;
OutputMaterialLOD - > SetDiffuseGreen ( 1 ) ;
OutputMaterialLOD - > SetDiffuseBlue ( 1 ) ;
OutputMaterialLOD - > SetLayeredTextureImage ( SimplygonSDK : : SG_MATERIAL_CHANNEL_DIFFUSE , 0 , OutputDiffuseData ) ;
OutputMaterialLOD - > SetLayeredTextureLevel ( SimplygonSDK : : SG_MATERIAL_CHANNEL_DIFFUSE , 0 , 0 ) ;
}
//Cast normal texture data
if ( CastProperties . bCastNormals )
{
//Create Image data where the normal data is stored
SimplygonSDK : : spImageData OutputNormalData = SDK - > CreateImageData ( ) ;
// Cast the data using a normal caster
SimplygonSDK : : spNormalCaster cast = SDK - > CreateNormalCaster ( ) ;
cast - > SetSourceMaterials ( OriginalMaterials ) ;
cast - > SetMappingImage ( MappingImage ) ; // The mapping image we got from the remeshing process.
cast - > SetOutputChannels ( 3 ) ; // RGB, 3 channels! (1 would be for grey scale, and 4 would be for RGBA.)
cast - > SetOutputChannelBitDepth ( 8 ) ; // 8 bits per channel. So in this case we will have 24bit colors RGB.
cast - > SetDilation ( 10 ) ; // To avoid mip-map artifacts, the empty pixels on the map needs to be filled to a degree aswell.
cast - > SetFlipBackfacingNormals ( false ) ;
cast - > SetGenerateTangentSpaceNormals ( true ) ;
cast - > SetOutputImage ( OutputNormalData ) ;
cast - > CastMaterials ( ) ; // Fetch!
OutputMaterialLOD - > SetLayeredTextureImage ( SimplygonSDK : : SG_MATERIAL_CHANNEL_NORMALS , 0 , OutputNormalData ) ;
OutputMaterialLOD - > SetLayeredTextureLevel ( SimplygonSDK : : SG_MATERIAL_CHANNEL_NORMALS , 0 , 0 ) ;
}
//Create a new material table for the new materials
SimplygonSDK : : spMaterialTable OutputTable = SDK - > CreateMaterialTable ( ) ;
OutputTable - > AddMaterial ( OutputMaterialLOD ) ;
//Convert the simplygon material to unreal materials
CreateFlattenMaterialFromSGMaterial ( OutputTable , OutMaterial ) ;
}
//Collect the proxy mesh
SimplygonSDK : : spSceneMesh ProxyMesh = SimplygonSDK : : Cast < SimplygonSDK : : ISceneMesh > ( Scene - > GetRootNode ( ) - > GetChild ( 0 ) ) ;
# ifdef DEBUG_PROXY_MESH
SimplygonSDK : : spWavefrontExporter objexp = SDK - > CreateWavefrontExporter ( ) ;
objexp - > SetExportFilePath ( " d:/AfterProxyMesh.obj " ) ;
objexp - > SetSingleGeometry ( ProxyMesh - > GetGeometry ( ) ) ;
objexp - > RunExport ( ) ;
# endif
//Convert geometry data to raw mesh data
SimplygonSDK : : spGeometryData outGeom = ProxyMesh - > GetGeometry ( ) ;
CreateRawMeshFromGeometry ( OutProxyMesh , ProxyMesh - > GetGeometry ( ) , WINDING_Keep ) ;
// Since mesh proxies have 1 texture channel
// put copy to channel 1 for lightmaps
OutProxyMesh . WedgeTexCoords [ 1 ] . Empty ( ) ;
OutProxyMesh . WedgeTexCoords [ 1 ] . Append ( OutProxyMesh . WedgeTexCoords [ 0 ] ) ;
// Default smoothing
OutProxyMesh . FaceSmoothingMasks . SetNum ( OutProxyMesh . FaceMaterialIndices . Num ( ) ) ;
for ( uint32 & SmoothingMask : OutProxyMesh . FaceSmoothingMasks )
{
SmoothingMask = 1 ;
}
}
private :
SimplygonSDK : : ISimplygonSDK * SDK ;
FDefaultErrorHandler ErrorHandler ;
FDefaultEventHandler EventHandler ;
FString VersionString ;
explicit FSimplygonMeshReduction ( SimplygonSDK : : ISimplygonSDK * InSDK )
: SDK ( InSDK )
{
check ( SDK ) ;
SDK - > SetErrorHandler ( & ErrorHandler ) ;
SDK - > SetGlobalSetting ( " DefaultTBNType " , SimplygonSDK : : SG_TANGENTSPACEMETHOD_ORTHONORMAL_LEFTHANDED ) ;
const TCHAR * LibraryVersion = TEXT ( " Simplygon_5_5_2156 " ) ;
const TCHAR * UnrealVersionGuid = TEXT ( " 18f808c3cf724e5a994f57de5c83cc4b " ) ;
VersionString = FString : : Printf ( TEXT ( " %s_%s " ) , LibraryVersion , UnrealVersionGuid ) ;
}
SimplygonSDK : : spGeometryData CreateGeometryFromRawMesh ( const FRawMesh & RawMesh )
{
int32 NumVertices = RawMesh . VertexPositions . Num ( ) ;
int32 NumWedges = RawMesh . WedgeIndices . Num ( ) ;
int32 NumTris = NumWedges / 3 ;
if ( NumWedges = = 0 )
{
return NULL ;
}
SimplygonSDK : : spGeometryData GeometryData = SDK - > CreateGeometryData ( ) ;
GeometryData - > SetVertexCount ( NumVertices ) ;
GeometryData - > SetTriangleCount ( NumTris ) ;
SimplygonSDK : : spRealArray Positions = GeometryData - > GetCoords ( ) ;
for ( int32 VertexIndex = 0 ; VertexIndex < NumVertices ; + + VertexIndex )
{
FVector TempPos = RawMesh . VertexPositions [ VertexIndex ] ;
TempPos . Z = - TempPos . Z ;
Positions - > SetTuple ( VertexIndex , ( float * ) & TempPos ) ;
}
SimplygonSDK : : spRidArray Indices = GeometryData - > GetVertexIds ( ) ;
for ( int32 WedgeIndex = 0 ; WedgeIndex < NumWedges ; + + WedgeIndex )
{
Indices - > SetItem ( WedgeIndex , RawMesh . WedgeIndices [ WedgeIndex ] ) ;
}
for ( int32 TexCoordIndex = 0 ; TexCoordIndex < MAX_MESH_TEXTURE_COORDS ; + + TexCoordIndex )
{
if ( RawMesh . WedgeTexCoords [ TexCoordIndex ] . Num ( ) = = NumWedges )
{
GeometryData - > AddTexCoords ( TexCoordIndex ) ;
SimplygonSDK : : spRealArray TexCoords = GeometryData - > GetTexCoords ( TexCoordIndex ) ;
check ( TexCoords - > GetTupleSize ( ) = = 2 ) ;
for ( int32 WedgeIndex = 0 ; WedgeIndex < NumWedges ; + + WedgeIndex )
{
TexCoords - > SetTuple ( WedgeIndex , ( float * ) & RawMesh . WedgeTexCoords [ TexCoordIndex ] [ WedgeIndex ] ) ;
}
}
}
if ( RawMesh . WedgeColors . Num ( ) = = NumWedges )
{
GeometryData - > AddColors ( 0 ) ;
SimplygonSDK : : spRealArray LinearColors = GeometryData - > GetColors ( 0 ) ;
check ( LinearColors ) ;
check ( LinearColors - > GetTupleSize ( ) = = 4 ) ;
for ( int32 WedgeIndex = 0 ; WedgeIndex < NumWedges ; + + WedgeIndex )
{
FLinearColor LinearColor ( RawMesh . WedgeColors [ WedgeIndex ] ) ;
LinearColors - > SetTuple ( WedgeIndex , ( float * ) & LinearColor ) ;
}
}
if ( RawMesh . WedgeTangentZ . Num ( ) = = NumWedges )
{
if ( RawMesh . WedgeTangentX . Num ( ) = = NumWedges & & RawMesh . WedgeTangentY . Num ( ) = = NumWedges )
{
GeometryData - > AddTangents ( 0 ) ;
SimplygonSDK : : spRealArray Tangents = GeometryData - > GetTangents ( 0 ) ;
for ( int32 WedgeIndex = 0 ; WedgeIndex < NumWedges ; + + WedgeIndex )
{
FVector TempTangent = RawMesh . WedgeTangentX [ WedgeIndex ] ;
TempTangent . Z = - TempTangent . Z ;
Tangents - > SetTuple ( WedgeIndex , ( float * ) & TempTangent ) ;
}
GeometryData - > AddBitangents ( 0 ) ;
SimplygonSDK : : spRealArray Bitangents = GeometryData - > GetBitangents ( 0 ) ;
for ( int32 WedgeIndex = 0 ; WedgeIndex < NumWedges ; + + WedgeIndex )
{
FVector TempBitangent = RawMesh . WedgeTangentY [ WedgeIndex ] ;
TempBitangent . Z = - TempBitangent . Z ;
Bitangents - > SetTuple ( WedgeIndex , ( float * ) & TempBitangent ) ;
}
}
GeometryData - > AddNormals ( ) ;
SimplygonSDK : : spRealArray Normals = GeometryData - > GetNormals ( ) ;
for ( int32 WedgeIndex = 0 ; WedgeIndex < NumWedges ; + + WedgeIndex )
{
FVector TempNormal = RawMesh . WedgeTangentZ [ WedgeIndex ] ;
TempNormal . Z = - TempNormal . Z ;
Normals - > SetTuple ( WedgeIndex , ( float * ) & TempNormal ) ;
}
}
// Per-triangle data.
GeometryData - > AddMaterialIds ( ) ;
SimplygonSDK : : spRidArray MaterialIndices = GeometryData - > GetMaterialIds ( ) ;
for ( int32 TriIndex = 0 ; TriIndex < NumTris ; + + TriIndex )
{
MaterialIndices - > SetItem ( TriIndex , RawMesh . FaceMaterialIndices [ TriIndex ] ) ;
}
GeometryData - > AddGroupIds ( ) ;
SimplygonSDK : : spRidArray GroupIds = GeometryData - > GetGroupIds ( ) ;
for ( int32 TriIndex = 0 ; TriIndex < NumTris ; + + TriIndex )
{
GroupIds - > SetItem ( TriIndex , RawMesh . FaceSmoothingMasks [ TriIndex ] ) ;
}
return GeometryData ;
}
void CreateRawMeshFromGeometry ( FRawMesh & OutRawMesh , const SimplygonSDK : : spGeometryData & GeometryData , EWindingMode WindingMode )
{
check ( GeometryData ) ;
SimplygonSDK : : spRealArray Positions = GeometryData - > GetCoords ( ) ;
SimplygonSDK : : spRidArray Indices = GeometryData - > GetVertexIds ( ) ;
SimplygonSDK : : spRidArray MaterialIndices = GeometryData - > GetMaterialIds ( ) ;
SimplygonSDK : : spRidArray GroupIds = GeometryData - > GetGroupIds ( ) ;
SimplygonSDK : : spRealArray LinearColors = GeometryData - > GetColors ( 0 ) ;
SimplygonSDK : : spRealArray Normals = GeometryData - > GetNormals ( ) ;
SimplygonSDK : : spRealArray Tangents = GeometryData - > GetTangents ( 0 ) ;
SimplygonSDK : : spRealArray Bitangents = GeometryData - > GetBitangents ( 0 ) ;
check ( Positions ) ;
check ( Indices ) ;
FRawMesh & RawMesh = OutRawMesh ;
const bool bReverseWinding = ( WindingMode = = WINDING_Reverse ) ;
int32 NumTris = GeometryData - > GetTriangleCount ( ) ;
int32 NumWedges = NumTris * 3 ;
int32 NumVertices = GeometryData - > GetVertexCount ( ) ;
RawMesh . VertexPositions . Empty ( NumVertices ) ;
RawMesh . VertexPositions . AddUninitialized ( NumVertices ) ;
for ( int32 VertexIndex = 0 ; VertexIndex < NumVertices ; + + VertexIndex )
{
Positions - > GetTuple ( VertexIndex , ( float * ) & RawMesh . VertexPositions [ VertexIndex ] ) ;
RawMesh . VertexPositions [ VertexIndex ] . Z = - RawMesh . VertexPositions [ VertexIndex ] . Z ;
}
RawMesh . WedgeIndices . Empty ( NumWedges ) ;
RawMesh . WedgeIndices . AddUninitialized ( NumWedges ) ;
for ( int32 TriIndex = 0 ; TriIndex < NumTris ; + + TriIndex )
{
for ( int32 CornerIndex = 0 ; CornerIndex < 3 ; + + CornerIndex )
{
const uint32 DestIndex = bReverseWinding ? ( 2 - CornerIndex ) : CornerIndex ;
RawMesh . WedgeIndices [ TriIndex * 3 + DestIndex ] = Indices - > GetItem ( TriIndex * 3 + CornerIndex ) ;
}
}
for ( int32 TexCoordIndex = 0 ; TexCoordIndex < MAX_MESH_TEXTURE_COORDS ; + + TexCoordIndex )
{
SimplygonSDK : : spRealArray TexCoords = GeometryData - > GetTexCoords ( TexCoordIndex ) ;
if ( TexCoords )
{
RawMesh . WedgeTexCoords [ TexCoordIndex ] . Empty ( NumWedges ) ;
RawMesh . WedgeTexCoords [ TexCoordIndex ] . AddUninitialized ( NumWedges ) ;
for ( int32 TriIndex = 0 ; TriIndex < NumTris ; + + TriIndex )
{
for ( int32 CornerIndex = 0 ; CornerIndex < 3 ; + + CornerIndex )
{
const uint32 DestIndex = bReverseWinding ? ( 2 - CornerIndex ) : CornerIndex ;
TexCoords - > GetTuple ( TriIndex * 3 + CornerIndex , ( float * ) & RawMesh . WedgeTexCoords [ TexCoordIndex ] [ TriIndex * 3 + DestIndex ] ) ;
}
}
}
}
if ( LinearColors )
{
RawMesh . WedgeColors . Empty ( NumWedges ) ;
RawMesh . WedgeColors . AddUninitialized ( NumWedges ) ;
for ( int32 WedgeIndex = 0 ; WedgeIndex < NumWedges ; + + WedgeIndex )
{
FLinearColor LinearColor ;
LinearColors - > GetTuple ( WedgeIndex , ( float * ) & LinearColor ) ;
RawMesh . WedgeColors [ WedgeIndex ] = LinearColor . ToFColor ( true ) ;
}
}
if ( Normals )
{
if ( Tangents & & Bitangents )
{
RawMesh . WedgeTangentX . Empty ( NumWedges ) ;
RawMesh . WedgeTangentX . AddUninitialized ( NumWedges ) ;
for ( int32 WedgeIndex = 0 ; WedgeIndex < NumWedges ; + + WedgeIndex )
{
Tangents - > GetTuple ( WedgeIndex , ( float * ) & RawMesh . WedgeTangentX [ WedgeIndex ] ) ;
RawMesh . WedgeTangentX [ WedgeIndex ] . Z = - RawMesh . WedgeTangentX [ WedgeIndex ] . Z ;
}
RawMesh . WedgeTangentY . Empty ( NumWedges ) ;
RawMesh . WedgeTangentY . AddUninitialized ( NumWedges ) ;
for ( int32 WedgeIndex = 0 ; WedgeIndex < NumWedges ; + + WedgeIndex )
{
Bitangents - > GetTuple ( WedgeIndex , ( float * ) & RawMesh . WedgeTangentY [ WedgeIndex ] ) ;
RawMesh . WedgeTangentY [ WedgeIndex ] . Z = - RawMesh . WedgeTangentY [ WedgeIndex ] . Z ;
}
}
RawMesh . WedgeTangentZ . Empty ( NumWedges ) ;
RawMesh . WedgeTangentZ . AddUninitialized ( NumWedges ) ;
for ( int32 WedgeIndex = 0 ; WedgeIndex < NumWedges ; + + WedgeIndex )
{
Normals - > GetTuple ( WedgeIndex , ( float * ) & RawMesh . WedgeTangentZ [ WedgeIndex ] ) ;
RawMesh . WedgeTangentZ [ WedgeIndex ] . Z = - RawMesh . WedgeTangentZ [ WedgeIndex ] . Z ;
}
}
RawMesh . FaceMaterialIndices . Empty ( NumTris ) ;
RawMesh . FaceMaterialIndices . AddZeroed ( NumTris ) ;
if ( MaterialIndices )
{
for ( int32 TriIndex = 0 ; TriIndex < NumTris ; + + TriIndex )
{
RawMesh . FaceMaterialIndices [ TriIndex ] = MaterialIndices - > GetItem ( TriIndex ) ;
}
}
RawMesh . FaceSmoothingMasks . Empty ( NumTris ) ;
RawMesh . FaceSmoothingMasks . AddZeroed ( NumTris ) ;
if ( GroupIds )
{
for ( int32 TriIndex = 0 ; TriIndex < NumTris ; + + TriIndex )
{
RawMesh . FaceSmoothingMasks [ TriIndex ] = GroupIds - > GetItem ( TriIndex ) ;
}
}
}
void SetReductionSettings ( SimplygonSDK : : spReductionSettings ReductionSettings , const FMeshReductionSettings & Settings , int32 NumTris )
{
float MaxDeviation = Settings . MaxDeviation > 0.0f ? Settings . MaxDeviation : FLT_MAX ;
float MinReductionRatio = FMath : : Max < float > ( 1.0f / NumTris , 0.05f ) ;
float MaxReductionRatio = ( Settings . MaxDeviation > 0.0f & & Settings . PercentTriangles = = 1.0f ) ? MinReductionRatio : 1.0f ;
float ReductionRatio = FMath : : Clamp ( Settings . PercentTriangles , MinReductionRatio , MaxReductionRatio ) ;
unsigned int FeatureFlagsMask = SimplygonSDK : : SG_FEATUREFLAGS_GROUP ;
if ( Settings . TextureImportance ! = EMeshFeatureImportance : : Off )
{
FeatureFlagsMask | = ( SimplygonSDK : : SG_FEATUREFLAGS_TEXTURE0 | SimplygonSDK : : SG_FEATUREFLAGS_MATERIAL ) ;
}
if ( Settings . ShadingImportance ! = EMeshFeatureImportance : : Off )
{
FeatureFlagsMask | = SimplygonSDK : : SG_FEATUREFLAGS_SHADING ;
}
const float ImportanceTable [ ] =
{
0.0f , // OFF
0.125f , // Lowest
0.35f , // Low,
1.0f , // Normal
2.8f , // High
8.0f , // Highest
} ;
2014-06-16 08:04:54 -04:00
static_assert ( ARRAY_COUNT ( ImportanceTable ) = = ( EMeshFeatureImportance : : Highest + 1 ) , " Importance table size mismatch. " ) ; // -1 because of TEMP_BROKEN(?)
2014-03-14 14:13:41 -04:00
check ( Settings . SilhouetteImportance < EMeshFeatureImportance : : Highest + 1 ) ; // -1 because of TEMP_BROKEN(?)
check ( Settings . TextureImportance < EMeshFeatureImportance : : Highest + 1 ) ; // -1 because of TEMP_BROKEN(?)
check ( Settings . ShadingImportance < EMeshFeatureImportance : : Highest + 1 ) ; // -1 because of TEMP_BROKEN(?)
ReductionSettings - > SetFeatureFlags ( FeatureFlagsMask ) ;
ReductionSettings - > SetMaxDeviation ( MaxDeviation ) ;
ReductionSettings - > SetReductionRatio ( ReductionRatio ) ;
ReductionSettings - > SetGeometryImportance ( ImportanceTable [ Settings . SilhouetteImportance ] ) ;
ReductionSettings - > SetTextureImportance ( ImportanceTable [ Settings . TextureImportance ] ) ;
ReductionSettings - > SetMaterialImportance ( ImportanceTable [ Settings . TextureImportance ] ) ;
ReductionSettings - > SetShadingImportance ( ImportanceTable [ Settings . ShadingImportance ] ) ;
ReductionSettings - > SetAllowDirectX ( false ) ;
}
void SetNormalSettings ( SimplygonSDK : : spNormalCalculationSettings NormalSettings , const FMeshReductionSettings & Settings )
{
NormalSettings - > SetReplaceNormals ( Settings . bRecalculateNormals ) ;
NormalSettings - > SetScaleByArea ( false ) ;
NormalSettings - > SetScaleByAngle ( false ) ;
NormalSettings - > SetHardEdgeAngle ( Settings . HardAngleThreshold ) ;
}
/**
* Creates a Simplygon scene representation of the skeletal hierarchy .
* @ param InScene - The Simplygon scene .
* @ param InSkeleton - The skeletal hierarchy from which to create the Simplygon representation .
* @ param OutBoneTableIDs - A mapping of Bone IDs from RefSkeleton to Simplygon Bone Table IDs
*/
void CreateSkeletalHierarchy ( SimplygonSDK : : spScene & InScene , const FReferenceSkeleton & InSkeleton , TArray < SimplygonSDK : : rid > & OutBoneTableIDs )
{
TArray < SimplygonSDK : : spSceneBone > BoneArray ;
//Create Simplygon scene nodes for each bone in our Skeletal Hierarchy
for ( int32 BoneIndex = 0 ; BoneIndex < InSkeleton . GetNum ( ) ; + + BoneIndex )
{
SimplygonSDK : : spSceneBone SceneBone = SDK - > CreateSceneBone ( ) ;
BoneArray . Add ( SceneBone ) ;
}
SimplygonSDK : : spSceneBoneTable BoneTable = InScene - > GetBoneTable ( ) ;
for ( int32 BoneIndex = 0 ; BoneIndex < InSkeleton . GetNum ( ) ; + + BoneIndex )
{
int32 ParentIndex = InSkeleton . GetParentIndex ( BoneIndex ) ;
SimplygonSDK : : spSceneBone CurrentBone = BoneArray [ BoneIndex ] ;
//We add the bone to the scene's bone table. This returns a uid that we must apply to the geometry data.
SimplygonSDK : : rid BoneID = BoneTable - > AddBone ( CurrentBone ) ;
OutBoneTableIDs . Add ( BoneID ) ;
//Handle root bone. Add to Scene root.
if ( BoneIndex = = 0 )
{
InScene - > GetRootNode ( ) - > AddChild ( CurrentBone ) ;
}
else
{
SimplygonSDK : : spSceneBone ParentBone = BoneArray [ ParentIndex ] ;
ParentBone - > AddChild ( CurrentBone ) ;
}
}
}
/**
* Creates a Simplygon geometry representation from a skeletal mesh LOD model .
* @ param Scene - The Simplygon scene .
* @ param LODModel - The skeletal mesh LOD model from which to create the geometry data .
* @ param BoneIDs - A maps of Bone IDs from RefSkeleton to Simplygon BoneTable IDs
* @ returns a Simplygon geometry data representation of the skeletal mesh LOD .
*/
SimplygonSDK : : spGeometryData CreateGeometryFromSkeletalLODModel ( SimplygonSDK : : spScene & Scene , const FStaticLODModel & LODModel , const TArray < SimplygonSDK : : rid > & BoneIDs )
{
TArray < FSoftSkinVertex > Vertices ;
FMultiSizeIndexContainerData IndexData ;
LODModel . GetVertices ( Vertices ) ;
LODModel . MultiSizeIndexContainer . GetIndexBufferData ( IndexData ) ;
const uint32 VertexCount = LODModel . NumVertices ;
const uint32 TexCoordCount = LODModel . NumTexCoords ;
check ( TexCoordCount < = MAX_TEXCOORDS ) ;
uint32 TriCount = 0 ;
# if WITH_APEX_CLOTHING
const uint32 SectionCount = ( uint32 ) LODModel . NumNonClothingSections ( ) ;
# else
const uint32 SectionCount = LODModel . Sections . Num ( ) ;
# endif // #if WITH_APEX_CLOTHING
for ( uint32 SectionIndex = 0 ; SectionIndex < SectionCount ; + + SectionIndex )
{
TriCount + = LODModel . Sections [ SectionIndex ] . NumTriangles ;
}
SimplygonSDK : : spGeometryData GeometryData = SDK - > CreateGeometryData ( ) ;
GeometryData - > SetVertexCount ( VertexCount ) ;
GeometryData - > SetTriangleCount ( TriCount ) ;
// Per-vertex data.
GeometryData - > AddBoneIds ( MAX_TOTAL_INFLUENCES ) ;
GeometryData - > AddBoneWeights ( MAX_TOTAL_INFLUENCES ) ;
SimplygonSDK : : spRealArray Positions = GeometryData - > GetCoords ( ) ;
SimplygonSDK : : spRidArray BoneIds = GeometryData - > GetBoneIds ( ) ;
SimplygonSDK : : spRealArray BoneWeights = GeometryData - > GetBoneWeights ( ) ;
// Per-corner per-triangle data.
SimplygonSDK : : spRidArray Indices = GeometryData - > GetVertexIds ( ) ;
SimplygonSDK : : spRealArray TexCoords [ MAX_TEXCOORDS ] ;
for ( uint32 TexCoordIndex = 0 ; TexCoordIndex < TexCoordCount ; + + TexCoordIndex )
{
GeometryData - > AddTexCoords ( TexCoordIndex ) ;
TexCoords [ TexCoordIndex ] = GeometryData - > GetTexCoords ( TexCoordIndex ) ;
check ( TexCoords [ TexCoordIndex ] - > GetTupleSize ( ) = = 2 ) ;
}
GeometryData - > AddNormals ( ) ;
GeometryData - > AddTangents ( 0 ) ;
GeometryData - > AddBitangents ( 0 ) ;
SimplygonSDK : : spRealArray Normals = GeometryData - > GetNormals ( ) ;
SimplygonSDK : : spRealArray Tangents = GeometryData - > GetTangents ( 0 ) ;
SimplygonSDK : : spRealArray Bitangents = GeometryData - > GetBitangents ( 0 ) ;
SimplygonSDK : : spUnsignedCharArray Colors ;
if ( LODModel . ColorVertexBuffer . GetNumVertices ( ) = = VertexCount )
{
GeometryData - > AddBaseTypeUserTriangleVertexField ( SimplygonSDK : : TYPES_ID_UCHAR , SIMPLYGON_COLOR_CHANNEL , 4 ) ;
SimplygonSDK : : spValueArray ColorValues = GeometryData - > GetUserTriangleVertexField ( SIMPLYGON_COLOR_CHANNEL ) ;
check ( ColorValues ) ;
Colors = SimplygonSDK : : IUnsignedCharArray : : SafeCast ( ColorValues ) ;
check ( Colors ) ;
}
// Per-triangle data.
GeometryData - > AddMaterialIds ( ) ;
SimplygonSDK : : spRidArray MaterialIndices = GeometryData - > GetMaterialIds ( ) ;
// Add per-vertex data. This data needs to be added per-chunk so that we can properly map bones.
# if WITH_APEX_CLOTHING
const int32 ChunkCount = LODModel . NumNonClothingSections ( ) ;
# else
const int32 ChunkCount = LODModel . Chunks . Num ( ) ;
# endif // #if WITH_APEX_CLOTHING
uint32 FirstVertex = 0 ;
for ( int32 ChunkIndex = 0 ; ChunkIndex < ChunkCount ; + + ChunkIndex )
{
const FSkelMeshChunk & Chunk = LODModel . Chunks [ ChunkIndex ] ;
const uint32 LastVertex = FirstVertex + ( uint32 ) Chunk . RigidVertices . Num ( ) + ( uint32 ) Chunk . SoftVertices . Num ( ) ;
for ( uint32 VertexIndex = FirstVertex ; VertexIndex < LastVertex ; + + VertexIndex )
{
FSoftSkinVertex & Vertex = Vertices [ VertexIndex ] ;
SimplygonSDK : : rid VertexBoneIds [ MAX_TOTAL_INFLUENCES ] ;
SimplygonSDK : : real VertexBoneWeights [ MAX_TOTAL_INFLUENCES ] ;
uint32 TotalInfluence = 0 ;
for ( uint32 InfluenceIndex = 0 ; InfluenceIndex < MAX_TOTAL_INFLUENCES ; + + InfluenceIndex )
{
int32 BoneIndex = Vertex . InfluenceBones [ InfluenceIndex ] ;
const uint8 BoneInfluence = Vertex . InfluenceWeights [ InfluenceIndex ] ;
TotalInfluence + = BoneInfluence ;
if ( BoneInfluence > 0 )
{
check ( BoneIndex < Chunk . BoneMap . Num ( ) ) ;
uint32 BoneID = BoneIDs [ Chunk . BoneMap [ BoneIndex ] ] ;
VertexBoneIds [ InfluenceIndex ] = BoneID ;
VertexBoneWeights [ InfluenceIndex ] = BoneInfluence / 255.0f ;
}
else
{
//Set BoneID and BoneWeight to -1 and 0 respectively as required by simplygon.
VertexBoneIds [ InfluenceIndex ] = - 1 ;
VertexBoneWeights [ InfluenceIndex ] = 0 ;
}
}
check ( TotalInfluence = = 255 ) ;
Positions - > SetTuple ( VertexIndex , ( float * ) & Vertex . Position ) ;
BoneIds - > SetTuple ( VertexIndex , VertexBoneIds ) ;
BoneWeights - > SetTuple ( VertexIndex , VertexBoneWeights ) ;
}
FirstVertex = LastVertex ;
}
// Add per-vertex per-triangle data.
for ( uint32 SectionIndex = 0 ; SectionIndex < SectionCount ; + + SectionIndex )
{
const FSkelMeshSection & Section = LODModel . Sections [ SectionIndex ] ;
const uint32 FirstIndex = Section . BaseIndex ;
const uint32 LastIndex = FirstIndex + Section . NumTriangles * 3 ;
for ( uint32 Index = FirstIndex ; Index < LastIndex ; + + Index )
{
uint32 VertexIndex = IndexData . Indices [ Index ] ;
FSoftSkinVertex & Vertex = Vertices [ VertexIndex ] ;
FVector Normal = Vertex . TangentZ ;
FVector Tangent = Vertex . TangentX ;
FVector Bitangent = Vertex . TangentY ;
Indices - > SetItem ( Index , VertexIndex ) ;
Normals - > SetTuple ( Index , ( float * ) & Normal ) ;
Tangents - > SetTuple ( Index , ( float * ) & Tangent ) ;
Bitangents - > SetTuple ( Index , ( float * ) & Bitangent ) ;
for ( uint32 TexCoordIndex = 0 ; TexCoordIndex < TexCoordCount ; + + TexCoordIndex )
{
FVector2D TexCoord = Vertex . UVs [ TexCoordIndex ] ;
TexCoords [ TexCoordIndex ] - > SetTuple ( Index , ( float * ) & TexCoord ) ;
}
if ( Colors )
{
FColor Color = LODModel . ColorVertexBuffer . VertexColor ( VertexIndex ) ;
Colors - > SetTuple ( Index , ( UCHAR * ) & Color ) ;
}
}
}
// Add per-triangle data.
for ( uint32 SectionIndex = 0 ; SectionIndex < SectionCount ; + + SectionIndex )
{
const FSkelMeshSection & Section = LODModel . Sections [ SectionIndex ] ;
const uint32 FirstTriIndex = Section . BaseIndex / 3 ;
const uint32 LastTriIndex = FirstTriIndex + Section . NumTriangles - 1 ;
const uint16 MaterialIndex = Section . MaterialIndex ;
for ( uint32 TriIndex = FirstTriIndex ; TriIndex < = LastTriIndex ; + + TriIndex )
{
MaterialIndices - > SetItem ( TriIndex , MaterialIndex ) ;
check ( MaterialIndices - > GetItem ( TriIndex ) = = MaterialIndex ) ;
}
}
// Create a new simplygon scene mesh object
SimplygonSDK : : spSceneMesh Mesh = SDK - > CreateSceneMesh ( ) ;
// Assign the geometry data to the mesh
Mesh - > SetGeometry ( GeometryData ) ;
// Add Mesh to the scene
Scene - > GetRootNode ( ) - > AddChild ( Mesh ) ;
return GeometryData ;
}
/**
* Holds data needed to create skeletal mesh skinning streams .
*/
struct FSkeletalMeshData
{
TArray < FVertInfluence > Influences ;
TArray < FMeshWedge > Wedges ;
TArray < FMeshFace > Faces ;
TArray < FVector > Points ;
uint32 TexCoordCount ;
} ;
/**
* Extracts mesh data from the Simplygon geometry representation in to a set of data usable by skeletal meshes .
* @ param GeometryData - the Simplygon geometry .
* @ param MeshData - the skeletal mesh output data .
*/
void ExtractSkeletalDataFromGeometry ( const SimplygonSDK : : spGeometryData & GeometryData , FSkeletalMeshData & MeshData )
{
TArray < FVector > PointNormals ;
TArray < uint32 > PointList ;
TArray < uint32 > PointInfluenceMap ;
check ( GeometryData ) ;
SimplygonSDK : : spRealArray Positions = GeometryData - > GetCoords ( ) ;
SimplygonSDK : : spRidArray Indices = GeometryData - > GetVertexIds ( ) ;
SimplygonSDK : : spRidArray MaterialIndices = GeometryData - > GetMaterialIds ( ) ;
SimplygonSDK : : spValueArray VertexColorValues = GeometryData - > GetUserTriangleVertexField ( SIMPLYGON_COLOR_CHANNEL ) ;
SimplygonSDK : : spUnsignedCharArray VertexColors = SimplygonSDK : : IUnsignedCharArray : : SafeCast ( VertexColorValues ) ;
SimplygonSDK : : spRealArray Normals = GeometryData - > GetNormals ( ) ;
SimplygonSDK : : spRealArray Tangents = GeometryData - > GetTangents ( 0 ) ;
SimplygonSDK : : spRealArray Bitangents = GeometryData - > GetBitangents ( 0 ) ;
SimplygonSDK : : spRidArray BoneIds = GeometryData - > GetBoneIds ( ) ;
SimplygonSDK : : spRealArray BoneWeights = GeometryData - > GetBoneWeights ( ) ;
SimplygonSDK : : spRealArray TexCoords [ MAX_TEXCOORDS ] ;
uint32 TexCoordCount = 0 ;
for ( uint32 TexCoordIndex = 0 ; TexCoordIndex < MAX_TEXCOORDS ; + + TexCoordIndex )
{
TexCoords [ TexCoordIndex ] = GeometryData - > GetTexCoords ( TexCoordIndex ) ;
if ( TexCoords [ TexCoordIndex ] = = NULL )
{
break ;
}
TexCoordCount + + ;
}
MeshData . TexCoordCount = TexCoordCount ;
check ( Positions ) ;
check ( Indices ) ;
check ( MaterialIndices ) ;
check ( Normals ) ;
check ( Tangents ) ;
check ( Bitangents ) ;
check ( BoneIds ) ;
check ( BoneWeights ) ;
const bool bHaveColors = ( VertexColors ! = NULL ) ;
const uint32 VertexCount = GeometryData - > GetVertexCount ( ) ;
const uint32 TriCount = GeometryData - > GetTriangleCount ( ) ;
// Initialize the lists of points, wedges, and faces.
MeshData . Points . AddZeroed ( VertexCount ) ;
PointNormals . AddZeroed ( VertexCount ) ;
PointList . Reserve ( VertexCount ) ;
PointInfluenceMap . Reserve ( VertexCount ) ;
for ( uint32 PointIndex = 0 ; PointIndex < VertexCount ; + + PointIndex )
{
PointList . Add ( INDEX_NONE ) ;
PointInfluenceMap . Add ( INDEX_NONE ) ;
}
MeshData . Wedges . AddZeroed ( TriCount * 3 ) ;
MeshData . Faces . AddZeroed ( TriCount ) ;
//The number of influences may have changed if we have specified a max number of bones per vertex.
uint32 NumOfInfluences = FMath : : Min < uint32 > ( BoneIds - > GetTupleSize ( ) , MAX_TOTAL_INFLUENCES ) ;
// Per-vertex data.
for ( uint32 VertexIndex = 0 ; VertexIndex < VertexCount ; + + VertexIndex )
{
FVector & Point = MeshData . Points [ VertexIndex ] ;
SimplygonSDK : : rid VertexBoneIds [ MAX_TOTAL_INFLUENCES ] ;
SimplygonSDK : : real VertexBoneWeights [ MAX_TOTAL_INFLUENCES ] ;
Positions - > GetTuple ( VertexIndex , ( float * ) & Point ) ;
BoneIds - > GetTuple ( VertexIndex , VertexBoneIds ) ;
BoneWeights - > GetTuple ( VertexIndex , VertexBoneWeights ) ;
PointInfluenceMap [ VertexIndex ] = ( uint32 ) MeshData . Influences . Num ( ) ;
for ( uint32 InfluenceIndex = 0 ; InfluenceIndex < NumOfInfluences ; + + InfluenceIndex )
{
const uint16 BoneIndex = VertexBoneIds [ InfluenceIndex ] ;
const float BoneWeight = VertexBoneWeights [ InfluenceIndex ] ;
if ( InfluenceIndex = = 0 | | BoneWeight > 0.0f )
{
FVertInfluence * VertInfluence = new ( MeshData . Influences ) FVertInfluence ;
VertInfluence - > BoneIndex = BoneIndex ;
VertInfluence - > Weight = BoneWeight ;
VertInfluence - > VertIndex = VertexIndex ;
}
}
}
// Per-triangle and per-corner data.
for ( uint32 TriIndex = 0 ; TriIndex < TriCount ; + + TriIndex )
{
// Per-triangle data.
FMeshFace & Face = MeshData . Faces [ TriIndex ] ;
Face . MeshMaterialIndex = MaterialIndices - > GetItem ( TriIndex ) ;
// Per-corner data.
for ( uint32 CornerIndex = 0 ; CornerIndex < 3 ; + + CornerIndex )
{
const uint32 WedgeIndex = TriIndex * 3 + CornerIndex ;
const uint32 BasePointIndex = ( uint32 ) Indices - > GetItem ( WedgeIndex ) ;
uint32 PointIndex = BasePointIndex ;
check ( BasePointIndex < ( uint32 ) PointList . Num ( ) ) ;
// Duplicate points where needed to create hard edges.
FVector WedgeNormal ;
Normals - > GetTuple ( WedgeIndex , ( float * ) & WedgeNormal ) ;
WedgeNormal . Normalize ( ) ;
FVector PointNormal = PointNormals [ PointIndex ] ;
if ( PointNormal . SizeSquared ( ) < KINDA_SMALL_NUMBER )
{
PointNormals [ PointIndex ] = WedgeNormal ;
}
else
{
while ( ( PointNormal | WedgeNormal ) - 1.0f < - KINDA_SMALL_NUMBER )
{
PointIndex = PointList [ PointIndex ] ;
if ( PointIndex = = INDEX_NONE )
{
break ;
}
check ( PointIndex < ( uint32 ) PointList . Num ( ) ) ;
PointNormal = PointNormals [ PointIndex ] ;
}
if ( PointIndex = = INDEX_NONE )
{
FVector Point = MeshData . Points [ BasePointIndex ] ;
PointIndex = MeshData . Points . Add ( Point ) ;
check ( PointIndex = = ( uint32 ) PointList . Num ( ) ) ;
check ( PointIndex = = ( uint32 ) PointInfluenceMap . Num ( ) ) ;
check ( PointIndex = = ( uint32 ) PointNormals . Num ( ) ) ;
PointNormals . Add ( WedgeNormal ) ;
uint32 NextPointIndex = PointList [ BasePointIndex ] ;
check ( NextPointIndex < ( uint32 ) PointList . Num ( ) | | NextPointIndex = = INDEX_NONE ) ;
PointList [ BasePointIndex ] = PointIndex ;
PointList . Add ( NextPointIndex ) ;
PointInfluenceMap . Add ( ( uint32 ) MeshData . Influences . Num ( ) ) ;
int32 InfluenceIndex = PointInfluenceMap [ BasePointIndex ] ;
while ( MeshData . Influences [ InfluenceIndex ] . VertIndex = = BasePointIndex )
{
FVertInfluence * NewVertInfluence = new ( MeshData . Influences ) FVertInfluence ;
NewVertInfluence - > BoneIndex = MeshData . Influences [ InfluenceIndex ] . BoneIndex ;
NewVertInfluence - > Weight = MeshData . Influences [ InfluenceIndex ] . Weight ;
NewVertInfluence - > VertIndex = PointIndex ;
InfluenceIndex + + ;
}
check ( PointNormals . Num ( ) = = MeshData . Points . Num ( ) ) ;
check ( PointList . Num ( ) = = MeshData . Points . Num ( ) ) ;
check ( PointInfluenceMap . Num ( ) = = MeshData . Points . Num ( ) ) ;
}
}
check ( PointIndex ! = INDEX_NONE ) ;
check ( ( MeshData . Points [ PointIndex ] - MeshData . Points [ BasePointIndex ] ) . SizeSquared ( ) = = 0.0f ) ;
FMeshWedge & Wedge = MeshData . Wedges [ WedgeIndex ] ;
Wedge . iVertex = PointIndex ;
for ( uint32 TexCoordIndex = 0 ; TexCoordIndex < TexCoordCount ; + + TexCoordIndex )
{
TexCoords [ TexCoordIndex ] - > GetTuple ( WedgeIndex , ( float * ) & Wedge . UVs [ TexCoordIndex ] ) ;
}
if ( bHaveColors )
{
VertexColors - > GetTuple ( WedgeIndex , ( uint8 * ) & Wedge . Color ) ;
}
else
{
Wedge . Color = FColor ( 255 , 255 , 255 , 255 ) ;
}
Face . iWedge [ CornerIndex ] = WedgeIndex ;
}
}
}
/**
* Creates a skeletal mesh LOD model from the Simplygon geometry representation .
* @ param GeometryData - the Simplygon geometry representation from which to create a skeletal mesh LOD .
* @ param SkeletalMesh - the skeletal mesh in to which the LOD model will be added .
* @ param NewModel - the LOD model in to which the geometry will be stored .
*/
void CreateSkeletalLODModelFromGeometry ( const SimplygonSDK : : spGeometryData & GeometryData , const FReferenceSkeleton & RefSkeleton , FStaticLODModel * NewModel )
{
check ( GeometryData ) ;
FSkeletalMeshData MeshData ;
ExtractSkeletalDataFromGeometry ( GeometryData , MeshData ) ;
// Create dummy map of 'point to original'
TArray < int32 > DummyMap ;
DummyMap . AddUninitialized ( MeshData . Points . Num ( ) ) ;
for ( int32 PointIdx = 0 ; PointIdx < MeshData . Points . Num ( ) ; PointIdx + + )
{
DummyMap [ PointIdx ] = PointIdx ;
}
IMeshUtilities & MeshUtilities = FModuleManager : : Get ( ) . LoadModuleChecked < IMeshUtilities > ( " MeshUtilities " ) ;
// Create skinning streams for NewModel.
MeshUtilities . BuildSkeletalMesh (
* NewModel ,
RefSkeleton ,
MeshData . Influences ,
MeshData . Wedges ,
MeshData . Faces ,
MeshData . Points ,
DummyMap
) ;
// Set texture coordinate count on the new model.
NewModel - > NumTexCoords = MeshData . TexCoordCount ;
NewModel - > Size = 0 ;
}
/**
* Sets reduction settings for Simplygon .
* @ param Settings - The skeletal mesh optimization settings .
* @ param ReductionSettings - The reduction settings to set for Simplygon .
*/
void SetReductionSettings ( const FSkeletalMeshOptimizationSettings & Settings , float BoundsRadius , int32 SourceTriCount , SimplygonSDK : : spReductionSettings ReductionSettings )
{
2014-07-07 08:45:49 -04:00
// Compute max deviation from quality.
float MaxDeviation = Settings . MaxDeviationPercentage > 0.0f ? Settings . MaxDeviationPercentage * BoundsRadius : SimplygonSDK : : REAL_MAX ;
// Set the reduction ratio such that at least 1 triangle or 5% of the original triangles remain, whichever is larger.
float MinReductionRatio = FMath : : Max < float > ( 1.0f / SourceTriCount , 0.05f ) ;
float MaxReductionRatio = ( Settings . MaxDeviationPercentage > 0.0f & & Settings . NumOfTrianglesPercentage = = 1.0f ) ? MinReductionRatio : 1.0f ;
float ReductionRatio = FMath : : Clamp ( Settings . NumOfTrianglesPercentage , MinReductionRatio , MaxReductionRatio ) ;
2014-03-14 14:13:41 -04:00
//Enable feature flags for those features where we have set an importance
unsigned int FeatureFlagsMask = SimplygonSDK : : SG_FEATUREFLAGS_GROUP ;
if ( Settings . TextureImportance ! = SMOI_Off )
{
FeatureFlagsMask | = ( SimplygonSDK : : SG_FEATUREFLAGS_TEXTURE0 | SimplygonSDK : : SG_FEATUREFLAGS_MATERIAL ) ;
}
if ( Settings . ShadingImportance ! = SMOI_Off )
{
FeatureFlagsMask | = SimplygonSDK : : SG_FEATUREFLAGS_SHADING ;
}
const float ImportanceTable [ ] =
{
0.0f , // OFF
0.125f , // Lowest
0.35f , // Low,
1.0f , // Normal
2.8f , // High
8.0f , // Highest
} ;
2014-06-16 08:04:54 -04:00
static_assert ( ARRAY_COUNT ( ImportanceTable ) = = SMOI_MAX , " Bad importance table size. " ) ;
2014-03-14 14:13:41 -04:00
check ( Settings . SilhouetteImportance < SMOI_MAX ) ;
check ( Settings . TextureImportance < SMOI_MAX ) ;
check ( Settings . ShadingImportance < SMOI_MAX ) ;
check ( Settings . SkinningImportance < SMOI_MAX ) ;
ReductionSettings - > SetFeatureFlags ( FeatureFlagsMask ) ;
ReductionSettings - > SetMaxDeviation ( MaxDeviation ) ;
ReductionSettings - > SetReductionRatio ( ReductionRatio ) ;
ReductionSettings - > SetGeometryImportance ( ImportanceTable [ Settings . SilhouetteImportance ] ) ;
ReductionSettings - > SetTextureImportance ( ImportanceTable [ Settings . TextureImportance ] ) ;
ReductionSettings - > SetMaterialImportance ( ImportanceTable [ Settings . TextureImportance ] ) ;
ReductionSettings - > SetShadingImportance ( ImportanceTable [ Settings . ShadingImportance ] ) ;
ReductionSettings - > SetSkinningImportance ( ImportanceTable [ Settings . SkinningImportance ] ) ;
}
/**
* Sets vertex normal settings for Simplygon .
* @ param Settings - The skeletal mesh optimization settings .
* @ param NormalSettings - The normal settings to set for Simplygon .
*/
void SetNormalSettings ( const FSkeletalMeshOptimizationSettings & Settings , SimplygonSDK : : spNormalCalculationSettings NormalSettings )
{
NormalSettings - > SetReplaceNormals ( Settings . bRecalcNormals ) ;
NormalSettings - > SetScaleByArea ( false ) ;
NormalSettings - > SetScaleByAngle ( false ) ;
NormalSettings - > SetHardEdgeAngle ( Settings . NormalsThreshold ) ;
}
/**
* Sets Bone Lod settings for Simplygon .
* @ param Settings - The skeletal mesh optimization settings .
* @ param NormalSettings - The Bone LOD to set for Simplygon .
*/
void SetBoneSettings ( const FSkeletalMeshOptimizationSettings & Settings , SimplygonSDK : : spBoneSettings BoneSettings )
{
BoneSettings - > SetBoneLodProcess ( SimplygonSDK : : SG_BONEPROCESSING_RATIO_PROCESSING ) ;
BoneSettings - > SetBoneLodRatio ( Settings . BoneReductionRatio ) ;
BoneSettings - > SetMaxBonePerVertex ( Settings . MaxBonesPerVertex ) ;
}
/**
* Calculates the view distance that a mesh should be displayed at .
* @ param MaxDeviation - The maximum surface - deviation between the reduced geometry and the original . This value should be acquired from Simplygon
* @ returns The calculated view distance
*/
float CalculateViewDistance ( float MaxDeviation )
{
// We want to solve for the depth in world space given the screen space distance between two pixels
//
// Assumptions:
// 1. There is no scaling in the view matrix.
// 2. The horizontal FOV is 90 degrees.
// 3. The backbuffer is 1920x1080.
//
// If we project two points at (X,Y,Z) and (X',Y,Z) from view space, we get their screen
// space positions: (X/Z, Y'/Z) and (X'/Z, Y'/Z) where Y' = Y * AspectRatio.
//
// The distance in screen space is then sqrt( (X'-X)^2/Z^2 + (Y'-Y')^2/Z^2 )
// or (X'-X)/Z. This is in clip space, so PixelDist = 1280 * 0.5 * (X'-X)/Z.
//
// Solving for Z: ViewDist = (X'-X * 640) / PixelDist
const float ViewDistance = ( MaxDeviation * 960.0f ) ;
return ViewDistance ;
}
/**
* ProxyLOD Related Methods
*/
void SetMaterialChannel (
const TArray < FColor > & InSamples ,
FIntPoint InTextureSize ,
SimplygonSDK : : spMaterial & InSGMaterial ,
const char * SGMaterialChannelName )
{
int32 NumTexels = InTextureSize . X * InTextureSize . Y ;
check ( NumTexels = = InSamples . Num ( ) )
if ( NumTexels > 1 )
{
SimplygonSDK : : spImageData ImageData = SDK - > CreateImageData ( ) ;
ImageData - > AddColors ( SimplygonSDK : : TYPES_ID_UCHAR , SimplygonSDK : : SG_IMAGEDATA_FORMAT_RGBA ) ;
ImageData - > Set2DSize ( InTextureSize . X , InTextureSize . Y ) ;
SimplygonSDK : : spUnsignedCharArray ImageColors = SimplygonSDK : : SafeCast < SimplygonSDK : : IUnsignedCharArray > ( ImageData - > GetColors ( ) ) ;
//Set the texture data to simplygon color data texel per texel
ImageColors - > SetTupleCount ( NumTexels ) ;
for ( int32 TexelIndex = 0 ; TexelIndex < NumTexels ; TexelIndex + + )
{
// BGRA -> RGBA
uint8 Texel [ 4 ] ;
Texel [ 0 ] = InSamples [ TexelIndex ] . R ;
Texel [ 1 ] = InSamples [ TexelIndex ] . G ;
Texel [ 2 ] = InSamples [ TexelIndex ] . B ;
Texel [ 3 ] = InSamples [ TexelIndex ] . A ;
ImageColors - > SetTuple ( TexelIndex , Texel ) ;
}
InSGMaterial - > SetLayeredTextureImage ( SGMaterialChannelName , 0 , ImageData ) ;
InSGMaterial - > SetLayeredTextureLevel ( SGMaterialChannelName , 0 , 0 ) ;
}
else
{
// handle uniform value
}
}
//Material conversions
bool CreateSGMaterialFromFlattenMaterial (
const TArray < MaterialExportUtils : : FFlattenMaterial > & InputMaterials ,
SimplygonSDK : : spMaterialTable & OutSGMaterialTable ,
FMaterialCastingProperties & OutCastProperties )
{
if ( InputMaterials . Num ( ) = = 0 )
{
//If there are no materials, feed Simplygon with a default material instead.
UE_LOG ( LogSimplygon , Log , TEXT ( " Input meshes do not contain any materials. A proxy without material will be generated. " ) ) ;
return false ;
}
for ( int32 MaterialIndex = 0 ; MaterialIndex < InputMaterials . Num ( ) ; MaterialIndex + + )
{
SimplygonSDK : : spMaterial SGMaterial = SDK - > CreateMaterial ( ) ;
const MaterialExportUtils : : FFlattenMaterial & FlattenMaterial = InputMaterials [ MaterialIndex ] ;
//Create UE4 Channels
//Simplygon 5.5 has three new channels already present called base color metallic roughness
//To conform with older simplygon versions:
if ( ! SGMaterial - > HasUserChannel ( SimplygonSDK : : SG_MATERIAL_CHANNEL_BASECOLOR ) )
SGMaterial - > AddUserChannel ( SimplygonSDK : : SG_MATERIAL_CHANNEL_BASECOLOR ) ;
if ( ! SGMaterial - > HasUserChannel ( SimplygonSDK : : SG_MATERIAL_CHANNEL_METALLIC ) )
SGMaterial - > AddUserChannel ( SimplygonSDK : : SG_MATERIAL_CHANNEL_METALLIC ) ;
if ( ! SGMaterial - > HasUserChannel ( SimplygonSDK : : SG_MATERIAL_CHANNEL_ROUGHNESS ) )
SGMaterial - > AddUserChannel ( SimplygonSDK : : SG_MATERIAL_CHANNEL_ROUGHNESS ) ;
SGMaterial - > SetName ( TCHAR_TO_ANSI ( * FString : : Printf ( TEXT ( " Material%d " ) , MaterialIndex ) ) ) ;
// Does current material have BaseColor?
if ( FlattenMaterial . DiffuseSamples . Num ( ) )
{
SetMaterialChannel ( FlattenMaterial . DiffuseSamples , FlattenMaterial . DiffuseSize , SGMaterial , SimplygonSDK : : SG_MATERIAL_CHANNEL_DIFFUSE ) ;
}
//Does current material have a normalmap?
if ( FlattenMaterial . NormalSamples . Num ( ) )
{
OutCastProperties . bCastNormals = true ;
SetMaterialChannel ( FlattenMaterial . NormalSamples , FlattenMaterial . NormalSize , SGMaterial , SimplygonSDK : : SG_MATERIAL_CHANNEL_NORMALS ) ;
}
OutSGMaterialTable - > AddMaterial ( SGMaterial ) ;
}
return true ;
}
void CreateFlattenMaterialFromSGMaterial (
SimplygonSDK : : spMaterialTable & InSGMaterialTable ,
MaterialExportUtils : : FFlattenMaterial & OutMaterial )
{
//Get the diffuse data from SGMaterial
SimplygonSDK : : spImageData SGDiffuseData = InSGMaterialTable - > GetMaterial ( 0 ) - > GetLayeredTextureImage ( SimplygonSDK : : SG_MATERIAL_CHANNEL_DIFFUSE , 0 ) ;
{
SimplygonSDK : : spUnsignedCharArray DiffuseImageColors = SimplygonSDK : : SafeCast < SimplygonSDK : : IUnsignedCharArray > ( SGDiffuseData - > GetColors ( ) ) ;
OutMaterial . DiffuseSize . X = SGDiffuseData - > GetXSize ( ) ;
OutMaterial . DiffuseSize . Y = SGDiffuseData - > GetYSize ( ) ;
int32 TexelsCount = OutMaterial . DiffuseSize . X * OutMaterial . DiffuseSize . Y ;
//Fill diffuse texture with color data collected from simplygon
OutMaterial . DiffuseSamples . SetNumUninitialized ( TexelsCount ) ;
for ( int32 TexelIndex = 0 ; TexelIndex < TexelsCount ; + + TexelIndex )
{
uint8 DiffuseData [ 4 ] ;
DiffuseImageColors - > GetTuple ( TexelIndex , ( unsigned char * ) & DiffuseData ) ;
OutMaterial . DiffuseSamples [ TexelIndex ] . R = DiffuseData [ 0 ] ;
OutMaterial . DiffuseSamples [ TexelIndex ] . G = DiffuseData [ 1 ] ;
OutMaterial . DiffuseSamples [ TexelIndex ] . B = DiffuseData [ 2 ] ;
OutMaterial . DiffuseSamples [ TexelIndex ] . A = DiffuseData [ 3 ] ;
}
}
//Get the normal data from SGMaterial
SimplygonSDK : : spImageData SGNormalData = InSGMaterialTable - > GetMaterial ( 0 ) - > GetLayeredTextureImage ( SimplygonSDK : : SG_MATERIAL_CHANNEL_NORMALS , 0 ) ;
if ( SGNormalData )
{
SimplygonSDK : : spUnsignedCharArray NormalImageColors = SimplygonSDK : : SafeCast < SimplygonSDK : : IUnsignedCharArray > ( SGNormalData - > GetColors ( ) ) ;
OutMaterial . NormalSize . X = SGNormalData - > GetXSize ( ) ;
OutMaterial . NormalSize . Y = SGNormalData - > GetYSize ( ) ;
int32 TexelsCount = OutMaterial . NormalSize . X * OutMaterial . NormalSize . Y ;
//Fill normal texture with color data collected from simplygon
OutMaterial . NormalSamples . SetNumUninitialized ( TexelsCount ) ;
for ( int32 TexelIndex = 0 ; TexelIndex < TexelsCount ; + + TexelIndex )
{
uint8 NormalData [ 3 ] ;
NormalImageColors - > GetTuple ( TexelIndex , ( unsigned char * ) & NormalData ) ;
OutMaterial . NormalSamples [ TexelIndex ] . R = NormalData [ 0 ] ;
OutMaterial . NormalSamples [ TexelIndex ] . G = NormalData [ 1 ] ;
OutMaterial . NormalSamples [ TexelIndex ] . B = NormalData [ 2 ] ;
OutMaterial . NormalSamples [ TexelIndex ] . A = FColor : : White . A ;
}
}
}
} ;
TScopedPointer < FSimplygonMeshReduction > GSimplygonMeshReduction ;
void FSimplygonMeshReductionModule : : StartupModule ( )
{
GSimplygonMeshReduction = FSimplygonMeshReduction : : Create ( ) ;
}
void FSimplygonMeshReductionModule : : ShutdownModule ( )
{
GSimplygonMeshReduction = NULL ;
}
IMeshReduction * FSimplygonMeshReductionModule : : GetMeshReductionInterface ( )
{
return GSimplygonMeshReduction ;
}
IMeshMerging * FSimplygonMeshReductionModule : : GetMeshMergingInterface ( )
{
return GSimplygonMeshReduction ;
}
# undef LOCTEXT_NAMESPACE