2019-01-17 18:54:05 -05:00
// Copyright 1998-2019 Epic Games, Inc. All Rights Reserved.
2017-06-30 12:21:06 -04:00
# include "MeshMergeHelpers.h"
# include "Engine/MapBuildDataRegistry.h"
# include "Engine/MeshMerging.h"
# include "MaterialOptions.h"
2019-01-17 18:54:05 -05:00
# include "MeshDescription.h"
# include "MeshAttributes.h"
# include "MeshAttributeArray.h"
# include "MeshDescriptionOperations.h"
2017-06-30 12:21:06 -04:00
# include "Misc/PackageName.h"
# include "MaterialUtilities.h"
# include "Components/SkeletalMeshComponent.h"
# include "Components/SplineMeshComponent.h"
# include "Components/SkinnedMeshComponent.h"
2018-02-14 14:13:42 -05:00
# include "Rendering/SkeletalMeshModel.h"
2017-06-30 12:21:06 -04:00
# include "SkeletalMeshTypes.h"
# include "SkeletalRenderPublic.h"
# include "UObject/UObjectBaseUtility.h"
# include "UObject/Package.h"
# include "Materials/Material.h"
# include "Misc/ScopedSlowTask.h"
# include "Modules/ModuleManager.h"
# include "HierarchicalLODUtilitiesModule.h"
# include "MeshMergeData.h"
# include "IHierarchicalLODUtilities.h"
# include "Engine/MeshMergeCullingVolume.h"
# include "Landscape.h"
# include "LandscapeProxy.h"
# include "Editor.h"
# include "Engine/StaticMesh.h"
# include "PhysicsEngine/ConvexElem.h"
# include "PhysicsEngine/BodySetup.h"
# include "MeshUtilities.h"
# include "ImageUtils.h"
# include "LandscapeHeightfieldCollisionComponent.h"
# include "IMeshReductionManagerModule.h"
# include "LayoutUV.h"
2018-03-06 13:26:20 -05:00
# include "Components/InstancedStaticMeshComponent.h"
2017-06-30 12:21:06 -04:00
//DECLARE_LOG_CATEGORY_CLASS(LogMeshMerging, Verbose, All);
void FMeshMergeHelpers : : ExtractSections ( const UStaticMeshComponent * Component , int32 LODIndex , TArray < FSectionInfo > & OutSections )
{
2017-09-11 10:43:35 -04:00
static UMaterialInterface * DefaultMaterial = UMaterial : : GetDefaultMaterial ( MD_Surface ) ;
Copying //UE4/Dev-AnimPhys to //UE4/Dev-Main (Source: //UE4/Dev-AnimPhys @ 4062005)
#lockdown Nick.Penwarden
============================
MAJOR FEATURES & CHANGES
============================
Change 4005617 by Danny.Bouimad
Fixing TM-AnimPhys lighting so it works on all platforms
#jira UEENGQA-19924
Change 4014898 by Aaron.McLeran
Adding simple delay feature
Change 4025071 by Lina.Halper
Fix and more potential fix for invalid bone index issue
http://crashreporter/Buggs/Show/2052839
http://crashreporter/Crashes/Show/46656562
#jira: UE-51931
Change 4042493 by Lina.Halper
Fix issue with sequence evaluator to handle properly when jumps from end to front or front to end
#jira: UE-58429
Change 4042892 by Lina.Halper
Fix issue with being able to drag/drop montage onto anim track in sequencer
#jira: UE-57863
Change 4043553 by Ethan.Geller
#jira UE-58340 Handle calls to FVoiceCaptureWindows::GetVoiceData outside of existing data calls. #rb none
Change 4043613 by Lina.Halper
Fix issue with incorrect usage of staticclass
#jira: UE-54413
Change 4044069 by James.Golding
PR #4455: Add FAnimNode_StateMachine subclassing support. (Contributed by redfeatherplusplus)
#jira UE-54599
Change 4044070 by James.Golding
PR #4349: Final points on a line test were broken, changed Plane.PlaneDot to FM. (Contributed by DSDambuster)
#jira UE-53554
Change 4044072 by James.Golding
Add ENGINE_API to UPhysicsHandleComponent so it can be subclassed
#jira UE-56397
Change 4044073 by James.Golding
PR #4611: Expose a few API's so it's possible to make custom anim graph nodes using these objects. (Contributed by ill)
#jira UE-57004
Change 4044075 by James.Golding
PR #4618: Bugfix: typo in path for CustomMeshComponent (case error) (Contributed by malavon)
#jira UE-57077
Change 4044077 by James.Golding
Add ClassGroup to some components
#jira UE-57587, UE-57609
Change 4044080 by James.Golding
PR #4515: Adding API export macro to ACableActor (Contributed by maxtunel)
#jira UE-55515
Change 4044082 by James.Golding
Remove unused CopySkinnedModelData function
#jira UE-57623
Change 4044083 by James.Golding
Fix per-poly collision for skel meshes. Make sure to call UpdateKinematicBonesToAnim if bEnablePerPolyCollision is set, even if no bodies
Integration of CL 3971421 from Release-4.19 stream
#jira UE-56405
Change 4044084 by James.Golding
Add option to preview 'fixed bounds' in SkelMesh editors.
Change 4044086 by James.Golding
Remove unused RigidInfluenceIndex from CPU skinning code
Change 4044310 by James.Golding
Roll back changes to make PhysX cool fails a log instead of warning (CL 3995372, UE-56466), now that content is fixed
Change 4044416 by Lina.Halper
Provide BP interface to get curve list of names
#jira: UE-52623
Change 4044419 by Lina.Halper
added notification for updating pose asset
#jira: UE-56233
Change 4046929 by Ethan.Geller
#jira none add my developer folder to QAGame. #fyi dan.reynolds
Change 4047064 by Ethan.Geller
[Dev-AnimPhys] #jira UE-57890 add additional binaries for Steam Audio to LibPhonon.Build.cs. #rb none
Change 4047564 by Lina.Halper
Fix issue of not regenerating when reimport mesh
#jira: UE-58284
Change 4047630 by Ethan.Geller
Fix syntax error in libPhonon. #jira none #rb none
Change 4048050 by Thomas.Sarkanen
Allowed "Follow Bone" to be popped out of the menu into the viewport
This allows for quick re-selection of the bone to follow, avoiding multiple clicks
Tweaks and extends the "pinned command list" system to allow dynamic text in labels and labels to be hidden.
#jira UE-53070 - Follow bone - Follow selected bone
Change 4048064 by Thomas.Sarkanen
Validate any bone references during compilation
Bone references that are set to something other than NAME_None will be verified against the skeleton.
Updated various anim nodes to call the base class ValidateAnimNodeDuringCompilation
#jira UE-55680 - Anim graph nodes that use FBoneReference all need validation in ValidateAnimNodeDuringCompilation
Change 4048468 by James.Golding
PR #4319: Allow UAnimNotify_PlayMontageNotify to be inherited by other dlls (Contributed by DSDambuster)
#jira UE-53390
Change 4048470 by James.Golding
Implement ApplyWorldOffset to CableComponent, to handle origin shifting
#jira UE-53560
Change 4048471 by James.Golding
PR #4396: fix cachebones for subclasses of FAnimNode_SkeletalControlBase (Contributed by tmiv)
#jira UE-53799
Change 4048474 by James.Golding
PR #4423: Rename confusing argument in LineBoxIntersection (Contributed by Hybrid0)
#jira UE-54145
Change 4048485 by James.Golding
Fix compile error display from PoseDriver node
#jira UE-58306
Change 4048489 by James.Golding
Finish support for ProceduralMeshComponent supporting multiple UV channels
#jira UE-54049
Change 4048678 by Thomas.Sarkanen
Allowing blend space samples to be optionally moved off-grid
Grid samples are now each optionally snapped.
#jira UE-56116 - Allow blend spaces to optionally use off-grid sample points
Change 4048773 by Lina.Halper
Support pose factory with name input
#jira: UE-55859
Change 4048844 by David.Hill
Material Proxy Settings
Updating the max on the material proxy texture size - old value could cause int32 overflow.
#jira: UE-55441
Change 4049464 by Lina.Halper
update curve is expensive, and we're doing multiple times with same curve sets. I'm changing it so that it only updates main, and copy from main instance to sub/post.
#jira: UE-58459
Change 4050939 by Aaron.McLeran
PR #4649: Activated reverbs will now take priority when world settings are used (i.e. no volume proxy is in use) (Contributed by Brandon-Wilson)
#jira UE-57546
Change 4050954 by Aaron.McLeran
PR #4594: Added class type to allow inherited versions of UAudioComponents to be created (Contributed by korypostma)
#jira UE-56454
Change 4050960 by Aaron.McLeran
Attempt to fix linux build.
Change 4051247 by James.Golding
Fix ProcMeshComp UpdateSection not copying all UV sets
Add test case for ProcMeshComp with multiple UVs
#jira UE-54049
Change 4051250 by James.Golding
Add bUseHighPrecisionTangentBasis option to SkeletalMesh
Change SkeletalMesh source data to store tangents at higher precision
#jira UE-58525
Change 4051616 by Thomas.Sarkanen
Mass scale is no longer incorrectly clamped
This now allows mass scales below 0.01 and above 100.
#jira UE-49572 - MassScale has some edge cases for skeletal mesh component and small numbers
Change 4051619 by Thomas.Sarkanen
Fixed notify drag/drop on high DPI displays
#jira UE-55690 - Animation Notifies Do Not Move Past the Center of Timeline On a High DPI Display
Change 4051626 by Thomas.Sarkanen
Fix anim dynamics debug rendering
#jira UE-53902 - Anim Dynamics node is missing wireframe simulation box in preview
#jira UE-57983 - GitHub 4674 : UE-57910 Fix the angular limits display issue while selecting the AnimDynamics node
Change 4051628 by Thomas.Sarkanen
Constraints and bodies now rotate in their own local space in the physics asset editor
When local coordinate system is applied
#jira UE-50345 - rotating constraints or bodies in Phat with local axis
Change 4051634 by Thomas.Sarkanen
Automatic rules for state transitions are now shown in tooltips
#jira UE-57689 - Animation State Machine Transitions that use bAutomaticRuleBasedOnSequencePlayerInState, should indicate that in the transition
Change 4051636 by Thomas.Sarkanen
NotifyTriggerChance is now hidden for nodify states as it has no effect
#jira UE-55351 - NotifyTriggerChance should be grayed out for UAnimNotifyState
Change 4051669 by Thomas.Sarkanen
Fixed accidental operation of pinned commands when closing them
#jira UE-54051 - Unpinning settings will toggle the next setting
Change 4051671 by Thomas.Sarkanen
Fix crash importing skeletal mesh with no vertices
Not a fix for the jira, but found while investigating
#jira UE-56330 - FBX Files Do Not Import After Using the Facial Anim Importer Unless Project is Reopened
Change 4051684 by James.Golding
Fix high precision tangents when CPU skinning and mesh merging
Remember bExistingUseHighPrecisionTangentBasis when re-importing SkelMesh
#jira UE-58525
Change 4051686 by James.Golding
PR #4297: Output animation name with ensure() - useful when debugging (Contributed by DSDambuster)
#jira UE-53259
Change 4051801 by Jurre.deBaare
A BlendSpace that puts the same asset on samples can stop its own animation on Switch
#fix Ensure that we don't cause divide-by-zero situations when sampling blendspace data
#jira UE-54030
Change 4051806 by Jurre.deBaare
Fix geometry cache reimport + serialization issues
Change 4051807 by Jurre.deBaare
Currently, it's not possible to assigned a material to a Geometry Cache .uasset
#fix EditAnywhere rather than VisibleAnywhere
#jira UE-58212
Change 4051809 by Jurre.deBaare
GeomCache: Crash/Bug: When importing file
#fix Ensure that we have a valid first frame when trying to import a sequence, if not error-out
#jira UE-58285
Change 4051813 by Jurre.deBaare
GeomCache: Bug: Normals Broken
#jira UE-58287
GeomCache - Normals are Bad on Import
#jira UE-58283
#fix ensure that we triangulate mesh attributes when necessary
#misc per-attribute indices check
Change 4051816 by Jurre.deBaare
Alembic QOL
- Fix issue with reimport object flags not being applied
- Now also store sampling data as part of Alembic asset import data
Change 4051817 by Jurre.deBaare
PR #4550: Fixes bug where "Merge Actors" or HLOD proxies result in too many mesh sections (Contributed by trond)
#fix Integrated pull-request in different form
#jira UE-55976
Change 4051818 by Jurre.deBaare
Emissive isn't baked correctly in TM-MeshbakeMap
#fix ensure that we OR and Max the material flags and emissive scale
#jira UE-54889
Change 4051819 by Jurre.deBaare
Crash on project load when GeometryCache plugin is disabled
#fix No longer force-load the geometry cache module as it was moved to be a plugin
#jira UE-57875
Change 4051820 by Jurre.deBaare
CLONE - Editor crash when Propagating Vertex Colors to Asset's source mesh
#fix IsValidIndex check
#jira UE-57127
Vertex painting
Change 4051828 by Jurre.deBaare
Merging negative-scaled actors breaks materials
#fix Make sure we also reverse the section indices when a static mesh has a mirrored transform
#jira UE-56953
Change 4051834 by Jurre.deBaare
Unclear warnings when generating clusters in persistent level when sublevels have HLOD disabled
#fix improved warning text + added uobject link to level in content browser
#jira UE-55734
Change 4051993 by Jurre.deBaare
Update Alembic automated test ground truth
#jira none
Change 4052937 by James.Golding
Remove now-unused version (merged change to skel source data from Main instead)
Change 4053291 by Aaron.McLeran
Fix for CIS
#jira none
Change 4053375 by Aaron.McLeran
#jira UE-58716 Allow ability to bypass volume-weighting with using sound wave priority
Change 4057170 by Thomas.Sarkanen
Fix shadow variable warning
#jira UE-58806 - Linux: Shadow Variable Warnings building Editor - PhysicsAssetEditorEditMode.cpp
Change 4057653 by Lina.Halper
Fix the issue with showing same item multiple times when opening control rig blueprint many times
#jira: UE-58107
Change 4057701 by Jurre.deBaare
//UE4/Dev-AnimPhys - Step 'Run Automated Tests' has completed with 13 Errors
#fix reupdate alembic ground truths, little bit of a weird state
#jira UE-58818
Change 4057710 by Ethan.Geller
[Dev-AnimPhys] #jira UE-58004 Early exit if finish was called before StartSubmixRecording. #rb Aaron.McLeran
Change 4059295 by Ethan.Geller
#jira UE-58004 Reduce logs from fatal to error, fix serialize crash. #rb aaron.mcleran
Change 4061061 by Aaron.McLeran
Fixing animphys build from recent merge from main.
#jira UE-58909
Change 4053154 by Aaron.McLeran
#jira UE-58708 Fix to mic component to reduce clicks/pops on mic input.
Fix was to simplify the way audio is copied from mic input. This change was used on the GDC demo floor for a number of features.
[CL 4062611 by Aaron McLeran in Main branch]
2018-05-09 18:45:58 -04:00
2017-06-30 12:21:06 -04:00
const UStaticMesh * StaticMesh = Component - > GetStaticMesh ( ) ;
2018-04-03 18:35:54 -04:00
TArray < FName > MaterialSlotNames ;
for ( const FStaticMaterial & StaticMaterial : StaticMesh - > StaticMaterials )
{
# if WITH_EDITOR
MaterialSlotNames . Add ( StaticMaterial . ImportedMaterialSlotName ) ;
# else
MaterialSlotNames . Add ( StaticMaterial . MaterialSlotName ) ;
# endif
}
2017-06-30 12:21:06 -04:00
for ( const FStaticMeshSection & MeshSection : StaticMesh - > RenderData - > LODResources [ LODIndex ] . Sections )
{
// Retrieve material for this section
UMaterialInterface * StoredMaterial = Component - > GetMaterial ( MeshSection . MaterialIndex ) ;
// Make sure the resource actual exists, otherwise use default material
StoredMaterial = ( StoredMaterial ! = nullptr ) & & StoredMaterial - > GetMaterialResource ( GMaxRHIFeatureLevel ) ? StoredMaterial : DefaultMaterial ;
// Populate section data
FSectionInfo SectionInfo ;
SectionInfo . Material = StoredMaterial ;
SectionInfo . MaterialIndex = MeshSection . MaterialIndex ;
2017-09-11 10:43:35 -04:00
SectionInfo . MaterialSlotName = MaterialSlotNames . IsValidIndex ( MeshSection . MaterialIndex ) ? MaterialSlotNames [ MeshSection . MaterialIndex ] : NAME_None ;
2017-06-30 12:21:06 -04:00
SectionInfo . StartIndex = MeshSection . FirstIndex / 3 ;
SectionInfo . EndIndex = SectionInfo . StartIndex + MeshSection . NumTriangles ;
if ( MeshSection . bEnableCollision )
{
SectionInfo . EnabledProperties . Add ( GET_MEMBER_NAME_CHECKED ( FStaticMeshSection , bEnableCollision ) ) ;
}
if ( MeshSection . bCastShadow & & Component - > CastShadow )
{
SectionInfo . EnabledProperties . Add ( GET_MEMBER_NAME_CHECKED ( FStaticMeshSection , bCastShadow ) ) ;
}
OutSections . Add ( SectionInfo ) ;
}
}
void FMeshMergeHelpers : : ExtractSections ( const USkeletalMeshComponent * Component , int32 LODIndex , TArray < FSectionInfo > & OutSections )
{
2017-09-11 10:43:35 -04:00
static UMaterialInterface * DefaultMaterial = UMaterial : : GetDefaultMaterial ( MD_Surface ) ;
2018-02-14 14:13:42 -05:00
FSkeletalMeshModel * Resource = Component - > SkeletalMesh - > GetImportedModel ( ) ;
2017-06-30 12:21:06 -04:00
checkf ( Resource - > LODModels . IsValidIndex ( LODIndex ) , TEXT ( " Invalid LOD Index " ) ) ;
2017-09-11 10:43:35 -04:00
TArray < FName > MaterialSlotNames = Component - > GetMaterialSlotNames ( ) ;
2018-02-14 14:13:42 -05:00
const FSkeletalMeshLODModel & Model = Resource - > LODModels [ LODIndex ] ;
2017-06-30 12:21:06 -04:00
for ( const FSkelMeshSection & MeshSection : Model . Sections )
{
// Retrieve material for this section
UMaterialInterface * StoredMaterial = Component - > GetMaterial ( MeshSection . MaterialIndex ) ;
// Make sure the resource actual exists, otherwise use default material
StoredMaterial = ( StoredMaterial ! = nullptr ) & & StoredMaterial - > GetMaterialResource ( GMaxRHIFeatureLevel ) ? StoredMaterial : DefaultMaterial ;
FSectionInfo SectionInfo ;
SectionInfo . Material = StoredMaterial ;
2017-09-11 10:43:35 -04:00
SectionInfo . MaterialSlotName = MaterialSlotNames . IsValidIndex ( MeshSection . MaterialIndex ) ? MaterialSlotNames [ MeshSection . MaterialIndex ] : NAME_None ;
2017-06-30 12:21:06 -04:00
if ( MeshSection . bCastShadow & & Component - > CastShadow )
{
SectionInfo . EnabledProperties . Add ( GET_MEMBER_NAME_CHECKED ( FSkelMeshSection , bCastShadow ) ) ;
}
if ( MeshSection . bRecomputeTangent )
{
SectionInfo . EnabledProperties . Add ( GET_MEMBER_NAME_CHECKED ( FSkelMeshSection , bRecomputeTangent ) ) ;
}
OutSections . Add ( SectionInfo ) ;
}
}
void FMeshMergeHelpers : : ExtractSections ( const UStaticMesh * StaticMesh , int32 LODIndex , TArray < FSectionInfo > & OutSections )
{
2017-09-11 10:43:35 -04:00
static UMaterialInterface * DefaultMaterial = UMaterial : : GetDefaultMaterial ( MD_Surface ) ;
2017-06-30 12:21:06 -04:00
for ( const FStaticMeshSection & MeshSection : StaticMesh - > RenderData - > LODResources [ LODIndex ] . Sections )
{
// Retrieve material for this section
UMaterialInterface * StoredMaterial = StaticMesh - > GetMaterial ( MeshSection . MaterialIndex ) ;
// Make sure the resource actual exists, otherwise use default material
StoredMaterial = ( StoredMaterial ! = nullptr ) & & StoredMaterial - > GetMaterialResource ( GMaxRHIFeatureLevel ) ? StoredMaterial : DefaultMaterial ;
// Populate section data
FSectionInfo SectionInfo ;
SectionInfo . Material = StoredMaterial ;
SectionInfo . MaterialIndex = MeshSection . MaterialIndex ;
2018-04-03 18:35:54 -04:00
# if WITH_EDITOR
SectionInfo . MaterialSlotName = StaticMesh - > StaticMaterials . IsValidIndex ( MeshSection . MaterialIndex ) ? StaticMesh - > StaticMaterials [ MeshSection . MaterialIndex ] . ImportedMaterialSlotName : NAME_None ;
# else
2017-09-11 10:43:35 -04:00
SectionInfo . MaterialSlotName = StaticMesh - > StaticMaterials . IsValidIndex ( MeshSection . MaterialIndex ) ? StaticMesh - > StaticMaterials [ MeshSection . MaterialIndex ] . MaterialSlotName : NAME_None ;
2018-04-03 18:35:54 -04:00
# endif
2017-06-30 12:21:06 -04:00
if ( MeshSection . bEnableCollision )
{
SectionInfo . EnabledProperties . Add ( GET_MEMBER_NAME_CHECKED ( FStaticMeshSection , bEnableCollision ) ) ;
}
if ( MeshSection . bCastShadow )
{
SectionInfo . EnabledProperties . Add ( GET_MEMBER_NAME_CHECKED ( FStaticMeshSection , bCastShadow ) ) ;
}
OutSections . Add ( SectionInfo ) ;
}
}
2019-01-17 18:54:05 -05:00
void FMeshMergeHelpers : : ExpandInstances ( const UInstancedStaticMeshComponent * InInstancedStaticMeshComponent , FMeshDescription & InOutRawMesh , TArray < FSectionInfo > & InOutSections )
2018-03-06 13:26:20 -05:00
{
2019-01-17 18:54:05 -05:00
FMeshDescription CombinedRawMesh ;
2018-03-06 13:26:20 -05:00
for ( const FInstancedStaticMeshInstanceData & InstanceData : InInstancedStaticMeshComponent - > PerInstanceSMData )
{
2019-01-17 18:54:05 -05:00
FMeshDescription InstanceRawMesh = InOutRawMesh ;
2018-03-06 13:26:20 -05:00
FMeshMergeHelpers : : TransformRawMeshVertexData ( FTransform ( InstanceData . Transform ) , InstanceRawMesh ) ;
FMeshMergeHelpers : : AppendRawMesh ( CombinedRawMesh , InstanceRawMesh ) ;
}
InOutRawMesh = CombinedRawMesh ;
}
2019-01-17 18:54:05 -05:00
void FMeshMergeHelpers : : RetrieveMesh ( const UStaticMeshComponent * StaticMeshComponent , int32 LODIndex , FMeshDescription & RawMesh , bool bPropagateVertexColours )
2017-06-30 12:21:06 -04:00
{
const UStaticMesh * StaticMesh = StaticMeshComponent - > GetStaticMesh ( ) ;
const FStaticMeshSourceModel & StaticMeshModel = StaticMesh - > SourceModels [ LODIndex ] ;
const bool bIsSplineMeshComponent = StaticMeshComponent - > IsA < USplineMeshComponent > ( ) ;
2019-01-17 18:54:05 -05:00
// Imported meshes will have a valid mesh description
const bool bImportedMesh = StaticMesh - > IsMeshDescriptionValid ( LODIndex ) ;
2017-09-11 10:43:35 -04:00
// Export the raw mesh data using static mesh render data
2019-01-17 18:54:05 -05:00
ExportStaticMeshLOD ( StaticMesh - > RenderData - > LODResources [ LODIndex ] , RawMesh , StaticMesh - > StaticMaterials ) ;
2017-06-30 12:21:06 -04:00
// Make sure the raw mesh is not irreparably malformed.
2019-01-17 18:54:05 -05:00
if ( RawMesh . VertexInstances ( ) . Num ( ) < = 0 )
2017-06-30 12:21:06 -04:00
{
return ;
}
// Use build settings from base mesh for LOD entries that was generated inside Editor.
const FMeshBuildSettings & BuildSettings = bImportedMesh ? StaticMeshModel . BuildSettings : StaticMesh - > SourceModels [ 0 ] . BuildSettings ;
// Transform raw mesh to world space
2017-09-11 10:43:35 -04:00
FTransform ComponentToWorldTransform = StaticMeshComponent - > GetComponentTransform ( ) ;
2017-06-30 12:21:06 -04:00
// Handle spline mesh deformation
if ( bIsSplineMeshComponent )
{
const USplineMeshComponent * SplineMeshComponent = Cast < USplineMeshComponent > ( StaticMeshComponent ) ;
// Deform raw mesh data according to the Spline Mesh Component's data
PropagateSplineDeformationToRawMesh ( SplineMeshComponent , RawMesh ) ;
}
// If specified propagate painted vertex colors into our raw mesh
if ( bPropagateVertexColours )
{
PropagatePaintedColorsToRawMesh ( StaticMeshComponent , LODIndex , RawMesh ) ;
}
// Transform raw mesh vertex data by the Static Mesh Component's component to world transformation
TransformRawMeshVertexData ( ComponentToWorldTransform , RawMesh ) ;
2019-01-17 18:54:05 -05:00
if ( RawMesh . VertexInstances ( ) . Num ( ) < = 0 )
2017-06-30 12:21:06 -04:00
{
return ;
}
// Figure out if we should recompute normals and tangents. By default generated LODs should not recompute normals
2019-01-17 18:54:05 -05:00
uint32 TangentOptions = FMeshDescriptionOperations : : ETangentOptions : : BlendOverlappingNormals ;
if ( BuildSettings . bRemoveDegenerates )
2017-06-30 12:21:06 -04:00
{
2019-01-17 18:54:05 -05:00
// If removing degenerate triangles, ignore them when computing tangents.
TangentOptions | = FMeshDescriptionOperations : : ETangentOptions : : IgnoreDegenerateTriangles ;
2017-06-30 12:21:06 -04:00
}
2019-03-29 17:00:56 -04:00
FMeshDescriptionOperations : : CreatePolygonNTB ( RawMesh , 0.0f ) ;
2019-01-17 18:54:05 -05:00
FMeshDescriptionOperations : : RecomputeNormalsAndTangentsIfNeeded ( RawMesh , ( FMeshDescriptionOperations : : ETangentOptions ) TangentOptions , BuildSettings . bUseMikkTSpace ) ;
2017-06-30 12:21:06 -04:00
}
2019-01-17 18:54:05 -05:00
void FMeshMergeHelpers : : RetrieveMesh ( USkeletalMeshComponent * SkeletalMeshComponent , int32 LODIndex , FMeshDescription & RawMesh , bool bPropagateVertexColours )
2017-06-30 12:21:06 -04:00
{
2018-02-14 14:13:42 -05:00
FSkeletalMeshModel * Resource = SkeletalMeshComponent - > SkeletalMesh - > GetImportedModel ( ) ;
2017-06-30 12:21:06 -04:00
if ( Resource - > LODModels . IsValidIndex ( LODIndex ) )
{
2018-03-06 13:26:20 -05:00
FSkeletalMeshLODInfo & SrcLODInfo = * ( SkeletalMeshComponent - > SkeletalMesh - > GetLODInfo ( LODIndex ) ) ;
2017-06-30 12:21:06 -04:00
// Get the CPU skinned verts for this LOD
TArray < FFinalSkinVertex > FinalVertices ;
SkeletalMeshComponent - > GetCPUSkinnedVertices ( FinalVertices , LODIndex ) ;
2018-02-14 14:13:42 -05:00
FSkeletalMeshLODModel & LODModel = Resource - > LODModels [ LODIndex ] ;
2019-01-17 18:54:05 -05:00
const int32 NumSections = LODModel . Sections . Num ( ) ;
//Empty the raw mesh
RawMesh . Empty ( ) ;
TVertexAttributesRef < FVector > VertexPositions = RawMesh . VertexAttributes ( ) . GetAttributesRef < FVector > ( MeshAttribute : : Vertex : : Position ) ;
TEdgeAttributesRef < bool > EdgeHardnesses = RawMesh . EdgeAttributes ( ) . GetAttributesRef < bool > ( MeshAttribute : : Edge : : IsHard ) ;
TEdgeAttributesRef < float > EdgeCreaseSharpnesses = RawMesh . EdgeAttributes ( ) . GetAttributesRef < float > ( MeshAttribute : : Edge : : CreaseSharpness ) ;
TPolygonGroupAttributesRef < FName > PolygonGroupImportedMaterialSlotNames = RawMesh . PolygonGroupAttributes ( ) . GetAttributesRef < FName > ( MeshAttribute : : PolygonGroup : : ImportedMaterialSlotName ) ;
TVertexInstanceAttributesRef < FVector > VertexInstanceNormals = RawMesh . VertexInstanceAttributes ( ) . GetAttributesRef < FVector > ( MeshAttribute : : VertexInstance : : Normal ) ;
TVertexInstanceAttributesRef < FVector > VertexInstanceTangents = RawMesh . VertexInstanceAttributes ( ) . GetAttributesRef < FVector > ( MeshAttribute : : VertexInstance : : Tangent ) ;
TVertexInstanceAttributesRef < float > VertexInstanceBinormalSigns = RawMesh . VertexInstanceAttributes ( ) . GetAttributesRef < float > ( MeshAttribute : : VertexInstance : : BinormalSign ) ;
TVertexInstanceAttributesRef < FVector4 > VertexInstanceColors = RawMesh . VertexInstanceAttributes ( ) . GetAttributesRef < FVector4 > ( MeshAttribute : : VertexInstance : : Color ) ;
TVertexInstanceAttributesRef < FVector2D > VertexInstanceUVs = RawMesh . VertexInstanceAttributes ( ) . GetAttributesRef < FVector2D > ( MeshAttribute : : VertexInstance : : TextureCoordinate ) ;
int32 TotalTriangles = 0 ;
int32 TotalCorners = 0 ;
for ( int32 SectionIndex = 0 ; SectionIndex < NumSections ; SectionIndex + + )
{
const FSkelMeshSection & SkelMeshSection = LODModel . Sections [ SectionIndex ] ;
TotalTriangles + = SkelMeshSection . NumTriangles ;
}
TotalCorners = TotalTriangles * 3 ;
RawMesh . ReserveNewVertices ( FinalVertices . Num ( ) ) ;
RawMesh . ReserveNewPolygons ( TotalTriangles ) ;
RawMesh . ReserveNewVertexInstances ( TotalCorners ) ;
RawMesh . ReserveNewEdges ( TotalCorners ) ;
2017-06-30 12:21:06 -04:00
// Copy skinned vertex positions
for ( int32 VertIndex = 0 ; VertIndex < FinalVertices . Num ( ) ; + + VertIndex )
{
2019-01-17 18:54:05 -05:00
const FVertexID VertexID = RawMesh . CreateVertex ( ) ;
VertexPositions [ VertexID ] = FinalVertices [ VertIndex ] . Position ;
2017-06-30 12:21:06 -04:00
}
2019-01-17 18:54:05 -05:00
VertexInstanceUVs . SetNumIndices ( MAX_TEXCOORDS ) ;
2017-06-30 12:21:06 -04:00
2019-01-17 18:54:05 -05:00
2017-06-30 12:21:06 -04:00
for ( int32 SectionIndex = 0 ; SectionIndex < NumSections ; SectionIndex + + )
{
2018-02-14 14:13:42 -05:00
const FSkelMeshSection & SkelMeshSection = LODModel . Sections [ SectionIndex ] ;
const int32 NumWedges = SkelMeshSection . NumTriangles * 3 ;
2019-01-17 18:54:05 -05:00
//Create the polygon group ID
int32 SectionMaterialIndex = SkelMeshSection . MaterialIndex ;
int32 MaterialIndex = SectionMaterialIndex ;
2018-02-14 14:13:42 -05:00
// use the remapping of material indices for all LODs besides the base LOD
if ( LODIndex > 0 & & SrcLODInfo . LODMaterialMap . IsValidIndex ( SkelMeshSection . MaterialIndex ) )
{
MaterialIndex = FMath : : Clamp < int32 > ( SrcLODInfo . LODMaterialMap [ SkelMeshSection . MaterialIndex ] , 0 , SkeletalMeshComponent - > SkeletalMesh - > Materials . Num ( ) ) ;
}
2019-01-17 18:54:05 -05:00
FName ImportedMaterialSlotName = SkeletalMeshComponent - > SkeletalMesh - > Materials [ MaterialIndex ] . ImportedMaterialSlotName ;
const FPolygonGroupID SectionPolygonGroupID ( SectionMaterialIndex ) ;
if ( ! RawMesh . IsPolygonGroupValid ( SectionPolygonGroupID ) )
2018-02-14 14:13:42 -05:00
{
2019-01-17 18:54:05 -05:00
RawMesh . CreatePolygonGroupWithID ( SectionPolygonGroupID ) ;
PolygonGroupImportedMaterialSlotNames [ SectionPolygonGroupID ] = ImportedMaterialSlotName ;
}
int32 WedgeIndex = 0 ;
for ( uint32 SectionTriangleIndex = 0 ; SectionTriangleIndex < SkelMeshSection . NumTriangles ; + + SectionTriangleIndex )
{
FVertexID VertexIndexes [ 3 ] ;
2019-01-29 19:23:19 -05:00
TArray < FVertexInstanceID > VertexInstanceIDs ;
VertexInstanceIDs . SetNum ( 3 ) ;
2019-01-17 18:54:05 -05:00
for ( int32 CornerIndex = 0 ; CornerIndex < 3 ; + + CornerIndex , + + WedgeIndex )
{
const int32 VertexIndexForWedge = LODModel . IndexBuffer [ SkelMeshSection . BaseIndex + WedgeIndex ] ;
VertexIndexes [ CornerIndex ] = FVertexID ( VertexIndexForWedge ) ;
FVertexInstanceID VertexInstanceID = RawMesh . CreateVertexInstance ( VertexIndexes [ CornerIndex ] ) ;
VertexInstanceIDs [ CornerIndex ] = VertexInstanceID ;
const FSoftSkinVertex & SoftVertex = SkelMeshSection . SoftVertices [ VertexIndexForWedge - SkelMeshSection . BaseVertexIndex ] ;
const FFinalSkinVertex & SkinnedVertex = FinalVertices [ VertexIndexForWedge ] ;
//Set NTBs
const FVector TangentX = SkinnedVertex . TangentX . ToFVector ( ) ;
const FVector TangentZ = SkinnedVertex . TangentZ . ToFVector ( ) ;
//@todo: do we need to inverse the sign between skeletalmesh and staticmesh, the old code was doing so.
const float TangentYSign = SkinnedVertex . TangentZ . ToFVector4 ( ) . W ;
VertexInstanceTangents [ VertexInstanceID ] = TangentX ;
VertexInstanceBinormalSigns [ VertexInstanceID ] = TangentYSign ;
VertexInstanceNormals [ VertexInstanceID ] = TangentZ ;
for ( uint32 TexCoordIndex = 0 ; TexCoordIndex < MAX_TEXCOORDS ; TexCoordIndex + + )
{
//Add this vertex instance tex coord
VertexInstanceUVs . Set ( VertexInstanceID , TexCoordIndex , SoftVertex . UVs [ TexCoordIndex ] ) ;
}
//Add this vertex instance color
VertexInstanceColors [ VertexInstanceID ] = bPropagateVertexColours ? FVector4 ( FLinearColor ( SoftVertex . Color ) ) : FVector4 ( 1.0f , 1.0f , 1.0f ) ;
}
//Create a polygon from this triangle
2019-01-29 19:23:19 -05:00
const FPolygonID NewPolygonID = RawMesh . CreatePolygon ( SectionPolygonGroupID , VertexInstanceIDs ) ;
2019-01-17 18:54:05 -05:00
//Triangulate the polygon
FMeshPolygon & Polygon = RawMesh . GetPolygon ( NewPolygonID ) ;
RawMesh . ComputePolygonTriangulation ( NewPolygonID , Polygon . Triangles ) ;
2017-06-30 12:21:06 -04:00
}
}
}
}
2019-01-17 18:54:05 -05:00
void FMeshMergeHelpers : : RetrieveMesh ( const UStaticMesh * StaticMesh , int32 LODIndex , FMeshDescription & RawMesh )
2017-06-30 12:21:06 -04:00
{
const FStaticMeshSourceModel & StaticMeshModel = StaticMesh - > SourceModels [ LODIndex ] ;
2019-01-17 18:54:05 -05:00
// Imported meshes will have a valid mesh description
const bool bImportedMesh = StaticMesh - > IsMeshDescriptionValid ( LODIndex ) ;
2017-06-30 12:21:06 -04:00
// Check whether or not this mesh has been reduced in-engine
2019-01-17 18:54:05 -05:00
const bool bReducedMesh = StaticMesh - > IsReductionActive ( LODIndex ) ;
2017-06-30 12:21:06 -04:00
// Trying to retrieve rawmesh from SourceStaticMeshModel was giving issues, which causes a mismatch
const bool bRenderDataMismatch = ( LODIndex > 0 ) | | StaticMeshModel . BuildSettings . bGenerateLightmapUVs ;
if ( bImportedMesh & & ! bReducedMesh & & ! bRenderDataMismatch )
{
2019-01-17 18:54:05 -05:00
RawMesh = * StaticMesh - > GetMeshDescription ( LODIndex ) ;
2017-06-30 12:21:06 -04:00
}
else
{
2019-01-17 18:54:05 -05:00
ExportStaticMeshLOD ( StaticMesh - > RenderData - > LODResources [ LODIndex ] , RawMesh , StaticMesh - > StaticMaterials ) ;
2017-06-30 12:21:06 -04:00
}
// Make sure the raw mesh is not irreparably malformed.
2019-01-17 18:54:05 -05:00
if ( RawMesh . VertexInstances ( ) . Num ( ) < = 0 )
2017-06-30 12:21:06 -04:00
{
// wrong
bool check = true ;
}
// Use build settings from base mesh for LOD entries that was generated inside Editor.
const FMeshBuildSettings & BuildSettings = bImportedMesh ? StaticMeshModel . BuildSettings : StaticMesh - > SourceModels [ 0 ] . BuildSettings ;
2019-01-17 18:54:05 -05:00
// Figure out if we should recompute normals and tangents. By default generated LODs should not recompute normals
uint32 TangentOptions = FMeshDescriptionOperations : : ETangentOptions : : BlendOverlappingNormals ;
if ( BuildSettings . bRemoveDegenerates )
2017-06-30 12:21:06 -04:00
{
2019-01-17 18:54:05 -05:00
// If removing degenerate triangles, ignore them when computing tangents.
TangentOptions | = FMeshDescriptionOperations : : ETangentOptions : : IgnoreDegenerateTriangles ;
2017-06-30 12:21:06 -04:00
}
2019-03-29 17:00:56 -04:00
FMeshDescriptionOperations : : CreatePolygonNTB ( RawMesh , 0.0f ) ;
2019-01-17 18:54:05 -05:00
FMeshDescriptionOperations : : RecomputeNormalsAndTangentsIfNeeded ( RawMesh , ( FMeshDescriptionOperations : : ETangentOptions ) TangentOptions , BuildSettings . bUseMikkTSpace , ( bImportedMesh & & BuildSettings . bRecomputeNormals ) , ( bImportedMesh & & BuildSettings . bRecomputeTangents ) ) ;
2017-06-30 12:21:06 -04:00
}
2019-01-17 18:54:05 -05:00
void FMeshMergeHelpers : : ExportStaticMeshLOD ( const FStaticMeshLODResources & StaticMeshLOD , FMeshDescription & OutRawMesh , const TArray < FStaticMaterial > & Materials )
2017-06-30 12:21:06 -04:00
{
const int32 NumWedges = StaticMeshLOD . IndexBuffer . GetNumIndices ( ) ;
2018-02-14 14:13:42 -05:00
const int32 NumVertexPositions = StaticMeshLOD . VertexBuffers . PositionVertexBuffer . GetNumVertices ( ) ;
2017-06-30 12:21:06 -04:00
const int32 NumFaces = NumWedges / 3 ;
2019-01-17 18:54:05 -05:00
OutRawMesh . Empty ( ) ;
2017-06-30 12:21:06 -04:00
2019-01-17 18:54:05 -05:00
if ( NumVertexPositions < = 0 | | StaticMeshLOD . VertexBuffers . StaticMeshVertexBuffer . GetNumVertices ( ) < = 0 )
2017-06-30 12:21:06 -04:00
{
2019-01-17 18:54:05 -05:00
return ;
}
TVertexAttributesRef < FVector > VertexPositions = OutRawMesh . VertexAttributes ( ) . GetAttributesRef < FVector > ( MeshAttribute : : Vertex : : Position ) ;
TEdgeAttributesRef < bool > EdgeHardnesses = OutRawMesh . EdgeAttributes ( ) . GetAttributesRef < bool > ( MeshAttribute : : Edge : : IsHard ) ;
TEdgeAttributesRef < float > EdgeCreaseSharpnesses = OutRawMesh . EdgeAttributes ( ) . GetAttributesRef < float > ( MeshAttribute : : Edge : : CreaseSharpness ) ;
TPolygonGroupAttributesRef < FName > PolygonGroupImportedMaterialSlotNames = OutRawMesh . PolygonGroupAttributes ( ) . GetAttributesRef < FName > ( MeshAttribute : : PolygonGroup : : ImportedMaterialSlotName ) ;
TVertexInstanceAttributesRef < FVector > VertexInstanceNormals = OutRawMesh . VertexInstanceAttributes ( ) . GetAttributesRef < FVector > ( MeshAttribute : : VertexInstance : : Normal ) ;
TVertexInstanceAttributesRef < FVector > VertexInstanceTangents = OutRawMesh . VertexInstanceAttributes ( ) . GetAttributesRef < FVector > ( MeshAttribute : : VertexInstance : : Tangent ) ;
TVertexInstanceAttributesRef < float > VertexInstanceBinormalSigns = OutRawMesh . VertexInstanceAttributes ( ) . GetAttributesRef < float > ( MeshAttribute : : VertexInstance : : BinormalSign ) ;
TVertexInstanceAttributesRef < FVector4 > VertexInstanceColors = OutRawMesh . VertexInstanceAttributes ( ) . GetAttributesRef < FVector4 > ( MeshAttribute : : VertexInstance : : Color ) ;
TVertexInstanceAttributesRef < FVector2D > VertexInstanceUVs = OutRawMesh . VertexInstanceAttributes ( ) . GetAttributesRef < FVector2D > ( MeshAttribute : : VertexInstance : : TextureCoordinate ) ;
OutRawMesh . ReserveNewVertices ( NumVertexPositions ) ;
OutRawMesh . ReserveNewVertexInstances ( NumWedges ) ;
OutRawMesh . ReserveNewPolygons ( NumFaces ) ;
OutRawMesh . ReserveNewEdges ( NumWedges ) ;
const int32 NumTexCoords = StaticMeshLOD . VertexBuffers . StaticMeshVertexBuffer . GetNumTexCoords ( ) ;
VertexInstanceUVs . SetNumIndices ( NumTexCoords ) ;
for ( int32 SectionIndex = 0 ; SectionIndex < StaticMeshLOD . Sections . Num ( ) ; + + SectionIndex )
{
const FStaticMeshSection & Section = StaticMeshLOD . Sections [ SectionIndex ] ;
FPolygonGroupID CurrentPolygonGroupID = OutRawMesh . CreatePolygonGroup ( ) ;
check ( CurrentPolygonGroupID . GetValue ( ) = = SectionIndex ) ;
if ( Materials . IsValidIndex ( Section . MaterialIndex ) )
2017-06-30 12:21:06 -04:00
{
2019-01-17 18:54:05 -05:00
PolygonGroupImportedMaterialSlotNames [ CurrentPolygonGroupID ] = Materials [ Section . MaterialIndex ] . ImportedMaterialSlotName ;
}
else
{
PolygonGroupImportedMaterialSlotNames [ CurrentPolygonGroupID ] = FName ( * ( TEXT ( " MeshMergeMaterial_ " ) + FString : : FromInt ( SectionIndex ) ) ) ;
2017-06-30 12:21:06 -04:00
}
}
2019-01-17 18:54:05 -05:00
//Create the vertex
for ( int32 VertexIndex = 0 ; VertexIndex < NumVertexPositions ; + + VertexIndex )
2017-06-30 12:21:06 -04:00
{
2019-01-17 18:54:05 -05:00
FVertexID VertexID = OutRawMesh . CreateVertex ( ) ;
VertexPositions [ VertexID ] = StaticMeshLOD . VertexBuffers . PositionVertexBuffer . VertexPosition ( VertexIndex ) ;
}
2017-06-30 12:21:06 -04:00
2019-01-17 18:54:05 -05:00
//Create the vertex instances
for ( int32 TriangleIndex = 0 ; TriangleIndex < NumFaces ; + + TriangleIndex )
{
FPolygonGroupID CurrentPolygonGroupID = FPolygonGroupID : : Invalid ;
for ( int32 SectionIndex = 0 ; SectionIndex < StaticMeshLOD . Sections . Num ( ) ; + + SectionIndex )
2017-06-30 12:21:06 -04:00
{
2019-01-17 18:54:05 -05:00
const FStaticMeshSection & Section = StaticMeshLOD . Sections [ SectionIndex ] ;
uint32 FirstTriangle = Section . FirstIndex / 3 ;
uint32 LastTriangle = FirstTriangle + Section . NumTriangles - 1 ;
if ( ( uint32 ) TriangleIndex > = FirstTriangle & & ( uint32 ) TriangleIndex < = LastTriangle )
{
CurrentPolygonGroupID = FPolygonGroupID ( SectionIndex ) ;
break ;
}
2017-06-30 12:21:06 -04:00
}
2019-01-17 18:54:05 -05:00
check ( CurrentPolygonGroupID ! = FPolygonGroupID : : Invalid ) ;
2017-06-30 12:21:06 -04:00
2019-01-17 18:54:05 -05:00
FVertexID VertexIDs [ 3 ] ;
2019-01-29 19:23:19 -05:00
TArray < FVertexInstanceID > VertexInstanceIDs ;
VertexInstanceIDs . SetNum ( 3 ) ;
2019-01-17 18:54:05 -05:00
for ( int32 Corner = 0 ; Corner < 3 ; + + Corner )
2017-06-30 12:21:06 -04:00
{
2019-01-17 18:54:05 -05:00
int32 WedgeIndex = StaticMeshLOD . IndexBuffer . GetIndex ( TriangleIndex * 3 + Corner ) ;
FVertexID VertexID ( WedgeIndex ) ;
FVertexInstanceID VertexInstanceID = OutRawMesh . CreateVertexInstance ( VertexID ) ;
VertexIDs [ Corner ] = VertexID ;
VertexInstanceIDs [ Corner ] = VertexInstanceID ;
2017-06-30 12:21:06 -04:00
2019-01-17 18:54:05 -05:00
//NTBs
FVector TangentX = StaticMeshLOD . VertexBuffers . StaticMeshVertexBuffer . VertexTangentX ( WedgeIndex ) ;
FVector TangentY = StaticMeshLOD . VertexBuffers . StaticMeshVertexBuffer . VertexTangentY ( WedgeIndex ) ;
FVector TangentZ = StaticMeshLOD . VertexBuffers . StaticMeshVertexBuffer . VertexTangentZ ( WedgeIndex ) ;
VertexInstanceTangents [ VertexInstanceID ] = TangentX ;
VertexInstanceBinormalSigns [ VertexInstanceID ] = GetBasisDeterminantSign ( TangentX , TangentY , TangentZ ) ;
VertexInstanceNormals [ VertexInstanceID ] = TangentZ ;
// Vertex colors
if ( StaticMeshLOD . VertexBuffers . ColorVertexBuffer . GetNumVertices ( ) > 0 )
{
VertexInstanceColors [ VertexInstanceID ] = FLinearColor ( StaticMeshLOD . VertexBuffers . ColorVertexBuffer . VertexColor ( WedgeIndex ) ) ;
}
else
{
VertexInstanceColors [ VertexInstanceID ] = FLinearColor : : White ;
}
//Tex coord
2017-06-30 12:21:06 -04:00
for ( int32 TexCoodIdx = 0 ; TexCoodIdx < NumTexCoords ; + + TexCoodIdx )
{
2019-01-17 18:54:05 -05:00
VertexInstanceUVs . Set ( VertexInstanceID , TexCoodIdx , StaticMeshLOD . VertexBuffers . StaticMeshVertexBuffer . GetVertexUV ( WedgeIndex , TexCoodIdx ) ) ;
2017-06-30 12:21:06 -04:00
}
}
2019-01-17 18:54:05 -05:00
//Create a polygon from this triangle
2019-01-29 19:23:19 -05:00
const FPolygonID NewPolygonID = OutRawMesh . CreatePolygon ( CurrentPolygonGroupID , VertexInstanceIDs ) ;
2019-01-17 18:54:05 -05:00
//Triangulate the polygon
FMeshPolygon & Polygon = OutRawMesh . GetPolygon ( NewPolygonID ) ;
OutRawMesh . ComputePolygonTriangulation ( NewPolygonID , Polygon . Triangles ) ;
2017-06-30 12:21:06 -04:00
}
}
bool FMeshMergeHelpers : : CheckWrappingUVs ( const TArray < FVector2D > & UVs )
{
bool bResult = false ;
FVector2D Min ( FLT_MAX , FLT_MAX ) ;
FVector2D Max ( - FLT_MAX , - FLT_MAX ) ;
for ( const FVector2D & Coordinate : UVs )
{
if ( ( FMath : : IsNegativeFloat ( Coordinate . X ) | | FMath : : IsNegativeFloat ( Coordinate . Y ) ) | | ( Coordinate . X > ( 1.0f + KINDA_SMALL_NUMBER ) | | Coordinate . Y > ( 1.0f + KINDA_SMALL_NUMBER ) ) )
{
bResult = true ;
break ;
}
}
return bResult ;
}
2019-01-17 18:54:05 -05:00
bool FMeshMergeHelpers : : CheckWrappingUVs ( const FMeshDescription & MeshDescription , int32 UVChannelIndex )
{
TVertexInstanceAttributesConstRef < FVector2D > VertexInstanceUVs = MeshDescription . VertexInstanceAttributes ( ) . GetAttributesRef < FVector2D > ( MeshAttribute : : VertexInstance : : TextureCoordinate ) ;
bool bResult = false ;
//Validate the channel, return false if there is an invalid channel index
if ( UVChannelIndex < 0 | | UVChannelIndex > = VertexInstanceUVs . GetNumIndices ( ) )
{
return bResult ;
}
for ( const FVertexInstanceID & VertexInstanceID : MeshDescription . VertexInstances ( ) . GetElementIDs ( ) )
{
const FVector2D & Coordinate = VertexInstanceUVs . Get ( VertexInstanceID , UVChannelIndex ) ;
if ( ( FMath : : IsNegativeFloat ( Coordinate . X ) | | FMath : : IsNegativeFloat ( Coordinate . Y ) ) | | ( Coordinate . X > ( 1.0f + KINDA_SMALL_NUMBER ) | | Coordinate . Y > ( 1.0f + KINDA_SMALL_NUMBER ) ) )
{
bResult = true ;
break ;
}
}
return bResult ;
}
void FMeshMergeHelpers : : CullTrianglesFromVolumesAndUnderLandscapes ( const UWorld * World , const FBoxSphereBounds & Bounds , FMeshDescription & InOutRawMesh )
2017-06-30 12:21:06 -04:00
{
TArray < ALandscapeProxy * > Landscapes ;
TArray < AMeshMergeCullingVolume * > CullVolumes ;
FBox BoxBounds = Bounds . GetBox ( ) ;
for ( ULevel * Level : World - > GetLevels ( ) )
{
for ( AActor * Actor : Level - > Actors )
{
ALandscape * Proxy = Cast < ALandscape > ( Actor ) ;
if ( Proxy & & Proxy - > bUseLandscapeForCullingInvisibleHLODVertices )
{
FVector Origin , Extent ;
Proxy - > GetActorBounds ( false , Origin , Extent ) ;
FBox LandscapeBox ( Origin - Extent , Origin + Extent ) ;
// Ignore Z axis for 2d bounds check
if ( LandscapeBox . IntersectXY ( BoxBounds ) )
{
Landscapes . Add ( Proxy - > GetLandscapeActor ( ) ) ;
}
}
// Check for culling volumes
AMeshMergeCullingVolume * Volume = Cast < AMeshMergeCullingVolume > ( Actor ) ;
if ( Volume )
{
// If the mesh's bounds intersect with the volume there is a possibility of culling
const bool bIntersecting = Volume - > EncompassesPoint ( Bounds . Origin , Bounds . SphereRadius , nullptr ) ;
if ( bIntersecting )
{
CullVolumes . Add ( Volume ) ;
}
}
}
}
2019-01-17 18:54:05 -05:00
TVertexAttributesConstRef < FVector > VertexPositions = InOutRawMesh . VertexAttributes ( ) . GetAttributesRef < FVector > ( MeshAttribute : : Vertex : : Position ) ;
2017-06-30 12:21:06 -04:00
2019-01-17 18:54:05 -05:00
TMap < FVertexID , bool > VertexVisible ;
VertexVisible . Reserve ( InOutRawMesh . Vertices ( ) . Num ( ) ) ;
int32 Index = 0 ;
for ( const FVertexID & VertexID : InOutRawMesh . Vertices ( ) . GetElementIDs ( ) )
2017-06-30 12:21:06 -04:00
{
2019-01-17 18:54:05 -05:00
const FVector & Position = VertexPositions [ VertexID ] ;
2017-06-30 12:21:06 -04:00
// Start with setting visibility to true on all vertices
2019-01-17 18:54:05 -05:00
VertexVisible . Add ( VertexID , true ) ;
2017-06-30 12:21:06 -04:00
// Check if this vertex is culled due to being underneath a landscape
if ( Landscapes . Num ( ) > 0 )
{
bool bVertexWithinLandscapeBounds = false ;
for ( ALandscapeProxy * Proxy : Landscapes )
{
FVector Origin , Extent ;
Proxy - > GetActorBounds ( false , Origin , Extent ) ;
FBox LandscapeBox ( Origin - Extent , Origin + Extent ) ;
bVertexWithinLandscapeBounds | = LandscapeBox . IsInsideXY ( Position ) ;
}
if ( bVertexWithinLandscapeBounds )
{
const FVector Start = Position ;
FVector End = Position - ( WORLD_MAX * FVector : : UpVector ) ;
FVector OutHit ;
const bool IsAboveLandscape = IsLandscapeHit ( Start , End , World , Landscapes , OutHit ) ;
End = Position + ( WORLD_MAX * FVector : : UpVector ) ;
const bool IsUnderneathLandscape = IsLandscapeHit ( Start , End , World , Landscapes , OutHit ) ;
// Vertex is visible when above landscape (with actual landscape underneath) or if there is no landscape beneath or above the vertex (falls outside of landscape bounds)
2019-01-17 18:54:05 -05:00
VertexVisible [ VertexID ] = ( IsAboveLandscape & & ! IsUnderneathLandscape ) ; // || (!IsAboveLandscape && !IsUnderneathLandscape);
2017-06-30 12:21:06 -04:00
}
}
// Volume culling
for ( AMeshMergeCullingVolume * Volume : CullVolumes )
{
const bool bVertexIsInsideVolume = Volume - > EncompassesPoint ( Position , 0.0f , nullptr ) ;
if ( bVertexIsInsideVolume )
{
// Inside a culling volume so invisible
2019-01-17 18:54:05 -05:00
VertexVisible [ VertexID ] = false ;
2017-06-30 12:21:06 -04:00
}
}
Index + + ;
}
// We now know which vertices are below the landscape
2019-01-17 18:54:05 -05:00
TArray < FPolygonID > PolygonToRemove ;
for ( const FPolygonID & PolygonID : InOutRawMesh . Polygons ( ) . GetElementIDs ( ) )
2017-06-30 12:21:06 -04:00
{
bool AboveLandscape = false ;
2019-01-17 18:54:05 -05:00
for ( FMeshTriangle & Triangle : InOutRawMesh . GetPolygonTriangles ( PolygonID ) )
2017-06-30 12:21:06 -04:00
{
2019-01-17 18:54:05 -05:00
for ( int32 Corner = 0 ; Corner < 3 ; + + Corner )
{
AboveLandscape | = VertexVisible [ InOutRawMesh . GetVertexInstanceVertex ( Triangle . GetVertexInstanceID ( Corner ) ) ] ;
}
}
if ( ! AboveLandscape )
{
PolygonToRemove . Add ( PolygonID ) ;
2017-06-30 12:21:06 -04:00
}
}
2019-01-17 18:54:05 -05:00
// Delete the polygons that are not visible
2017-06-30 12:21:06 -04:00
{
2019-01-17 18:54:05 -05:00
TArray < FEdgeID > OrphanedEdges ;
TArray < FVertexInstanceID > OrphanedVertexInstances ;
TArray < FPolygonGroupID > OrphanedPolygonGroups ;
TArray < FVertexID > OrphanedVertices ;
for ( FPolygonID PolygonID : PolygonToRemove )
2017-06-30 12:21:06 -04:00
{
2019-01-17 18:54:05 -05:00
InOutRawMesh . DeletePolygon ( PolygonID , & OrphanedEdges , & OrphanedVertexInstances , & OrphanedPolygonGroups ) ;
2017-06-30 12:21:06 -04:00
}
2019-01-17 18:54:05 -05:00
//Do not remove the polygongroup since its indexed with the mesh material array
/*for (FPolygonGroupID PolygonGroupID : OrphanedPolygonGroups)
{
InOutRawMesh . DeletePolygonGroup ( PolygonGroupID ) ;
} */
for ( FVertexInstanceID VertexInstanceID : OrphanedVertexInstances )
{
InOutRawMesh . DeleteVertexInstance ( VertexInstanceID , & OrphanedVertices ) ;
}
for ( FEdgeID EdgeID : OrphanedEdges )
{
InOutRawMesh . DeleteEdge ( EdgeID , & OrphanedVertices ) ;
}
for ( FVertexID VertexID : OrphanedVertices )
{
InOutRawMesh . DeleteVertex ( VertexID ) ;
}
//Compact and Remap IDs so we have clean ID from 0 to n since we just erase some polygons
//The render build need to have compact ID
FElementIDRemappings OutRemappings ;
InOutRawMesh . Compact ( OutRemappings ) ;
2017-06-30 12:21:06 -04:00
}
}
2019-01-17 18:54:05 -05:00
void FMeshMergeHelpers : : PropagateSplineDeformationToRawMesh ( const USplineMeshComponent * InSplineMeshComponent , FMeshDescription & OutRawMesh )
2017-06-30 12:21:06 -04:00
{
2019-01-17 18:54:05 -05:00
TVertexAttributesRef < FVector > VertexPositions = OutRawMesh . VertexAttributes ( ) . GetAttributesRef < FVector > ( MeshAttribute : : Vertex : : Position ) ;
TVertexInstanceAttributesRef < FVector > VertexInstanceNormals = OutRawMesh . VertexInstanceAttributes ( ) . GetAttributesRef < FVector > ( MeshAttribute : : VertexInstance : : Normal ) ;
TVertexInstanceAttributesRef < FVector > VertexInstanceTangents = OutRawMesh . VertexInstanceAttributes ( ) . GetAttributesRef < FVector > ( MeshAttribute : : VertexInstance : : Tangent ) ;
TVertexInstanceAttributesRef < float > VertexInstanceBinormalSigns = OutRawMesh . VertexInstanceAttributes ( ) . GetAttributesRef < float > ( MeshAttribute : : VertexInstance : : BinormalSign ) ;
2017-06-30 12:21:06 -04:00
// Apply spline deformation for each vertex's tangents
2019-01-17 18:54:05 -05:00
int32 WedgeIndex = 0 ;
for ( const FPolygonID & PolygonID : OutRawMesh . Polygons ( ) . GetElementIDs ( ) )
2017-06-30 12:21:06 -04:00
{
2019-01-17 18:54:05 -05:00
for ( FMeshTriangle & Triangle : OutRawMesh . GetPolygonTriangles ( PolygonID ) )
2017-06-30 12:21:06 -04:00
{
2019-01-17 18:54:05 -05:00
for ( int32 Corner = 0 ; Corner < 3 ; + + Corner , + + WedgeIndex )
{
const FVertexInstanceID VertexInstanceID = Triangle . GetVertexInstanceID ( Corner ) ;
const FVertexID VertexID = OutRawMesh . GetVertexInstanceVertex ( VertexInstanceID ) ;
const float & AxisValue = USplineMeshComponent : : GetAxisValue ( VertexPositions [ VertexID ] , InSplineMeshComponent - > ForwardAxis ) ;
FTransform SliceTransform = InSplineMeshComponent - > CalcSliceTransform ( AxisValue ) ;
FVector TangentY = FVector : : CrossProduct ( VertexInstanceNormals [ VertexInstanceID ] , VertexInstanceTangents [ VertexInstanceID ] ) . GetSafeNormal ( ) * VertexInstanceBinormalSigns [ VertexInstanceID ] ;
VertexInstanceTangents [ VertexInstanceID ] = SliceTransform . TransformVector ( VertexInstanceTangents [ VertexInstanceID ] ) ;
TangentY = SliceTransform . TransformVector ( TangentY ) ;
VertexInstanceNormals [ VertexInstanceID ] = SliceTransform . TransformVector ( VertexInstanceNormals [ VertexInstanceID ] ) ;
VertexInstanceBinormalSigns [ VertexInstanceID ] = GetBasisDeterminantSign ( VertexInstanceTangents [ VertexInstanceID ] , TangentY , VertexInstanceNormals [ VertexInstanceID ] ) ;
}
2017-06-30 12:21:06 -04:00
}
}
// Apply spline deformation for each vertex position
2019-01-17 18:54:05 -05:00
for ( const FVertexID & VertexID : OutRawMesh . Vertices ( ) . GetElementIDs ( ) )
2017-06-30 12:21:06 -04:00
{
2019-01-17 18:54:05 -05:00
float & AxisValue = USplineMeshComponent : : GetAxisValue ( VertexPositions [ VertexID ] , InSplineMeshComponent - > ForwardAxis ) ;
2017-06-30 12:21:06 -04:00
FTransform SliceTransform = InSplineMeshComponent - > CalcSliceTransform ( AxisValue ) ;
AxisValue = 0.0f ;
2019-01-17 18:54:05 -05:00
VertexPositions [ VertexID ] = SliceTransform . TransformPosition ( VertexPositions [ VertexID ] ) ;
2017-06-30 12:21:06 -04:00
}
}
void FMeshMergeHelpers : : PropagateSplineDeformationToPhysicsGeometry ( USplineMeshComponent * SplineMeshComponent , FKAggregateGeom & InOutPhysicsGeometry )
{
const FVector Mask = USplineMeshComponent : : GetAxisMask ( SplineMeshComponent - > GetForwardAxis ( ) ) ;
for ( FKConvexElem & Elem : InOutPhysicsGeometry . ConvexElems )
{
for ( FVector & Position : Elem . VertexData )
{
const float & AxisValue = USplineMeshComponent : : GetAxisValue ( Position , SplineMeshComponent - > ForwardAxis ) ;
FTransform SliceTransform = SplineMeshComponent - > CalcSliceTransform ( AxisValue ) ;
Position = SliceTransform . TransformPosition ( Position * Mask ) ;
}
Elem . UpdateElemBox ( ) ;
}
for ( FKSphereElem & Elem : InOutPhysicsGeometry . SphereElems )
{
const FVector WorldSpaceCenter = Elem . GetTransform ( ) . TransformPosition ( Elem . Center ) ;
Elem . Center = SplineMeshComponent - > CalcSliceTransform ( USplineMeshComponent : : GetAxisValue ( WorldSpaceCenter , SplineMeshComponent - > ForwardAxis ) ) . TransformPosition ( Elem . Center * Mask ) ;
}
for ( FKSphylElem & Elem : InOutPhysicsGeometry . SphylElems )
{
const FVector WorldSpaceCenter = Elem . GetTransform ( ) . TransformPosition ( Elem . Center ) ;
Elem . Center = SplineMeshComponent - > CalcSliceTransform ( USplineMeshComponent : : GetAxisValue ( WorldSpaceCenter , SplineMeshComponent - > ForwardAxis ) ) . TransformPosition ( Elem . Center * Mask ) ;
}
}
2019-01-17 18:54:05 -05:00
void FMeshMergeHelpers : : TransformRawMeshVertexData ( const FTransform & InTransform , FMeshDescription & OutRawMesh )
2017-06-30 12:21:06 -04:00
{
2019-01-17 18:54:05 -05:00
TVertexAttributesRef < FVector > VertexPositions = OutRawMesh . VertexAttributes ( ) . GetAttributesRef < FVector > ( MeshAttribute : : Vertex : : Position ) ;
TEdgeAttributesRef < bool > EdgeHardnesses = OutRawMesh . EdgeAttributes ( ) . GetAttributesRef < bool > ( MeshAttribute : : Edge : : IsHard ) ;
TEdgeAttributesRef < float > EdgeCreaseSharpnesses = OutRawMesh . EdgeAttributes ( ) . GetAttributesRef < float > ( MeshAttribute : : Edge : : CreaseSharpness ) ;
TPolygonGroupAttributesRef < FName > PolygonGroupImportedMaterialSlotNames = OutRawMesh . PolygonGroupAttributes ( ) . GetAttributesRef < FName > ( MeshAttribute : : PolygonGroup : : ImportedMaterialSlotName ) ;
TVertexInstanceAttributesRef < FVector > VertexInstanceNormals = OutRawMesh . VertexInstanceAttributes ( ) . GetAttributesRef < FVector > ( MeshAttribute : : VertexInstance : : Normal ) ;
TVertexInstanceAttributesRef < FVector > VertexInstanceTangents = OutRawMesh . VertexInstanceAttributes ( ) . GetAttributesRef < FVector > ( MeshAttribute : : VertexInstance : : Tangent ) ;
TVertexInstanceAttributesRef < float > VertexInstanceBinormalSigns = OutRawMesh . VertexInstanceAttributes ( ) . GetAttributesRef < float > ( MeshAttribute : : VertexInstance : : BinormalSign ) ;
TVertexInstanceAttributesRef < FVector4 > VertexInstanceColors = OutRawMesh . VertexInstanceAttributes ( ) . GetAttributesRef < FVector4 > ( MeshAttribute : : VertexInstance : : Color ) ;
TVertexInstanceAttributesRef < FVector2D > VertexInstanceUVs = OutRawMesh . VertexInstanceAttributes ( ) . GetAttributesRef < FVector2D > ( MeshAttribute : : VertexInstance : : TextureCoordinate ) ;
for ( const FVertexID & VertexID : OutRawMesh . Vertices ( ) . GetElementIDs ( ) )
2017-06-30 12:21:06 -04:00
{
2019-01-17 18:54:05 -05:00
VertexPositions [ VertexID ] = InTransform . TransformPosition ( VertexPositions [ VertexID ] ) ;
2017-06-30 12:21:06 -04:00
}
2018-03-27 16:13:55 -04:00
auto TransformNormal = [ & ] ( FVector & Normal )
{
FMatrix Matrix = InTransform . ToMatrixWithScale ( ) ;
const float DetM = Matrix . Determinant ( ) ;
FMatrix AdjointT = Matrix . TransposeAdjoint ( ) ;
AdjointT . RemoveScaling ( ) ;
Normal = AdjointT . TransformVector ( Normal ) ;
if ( DetM < 0.f )
{
Normal * = - 1.0f ;
}
} ;
2017-06-30 12:21:06 -04:00
2019-01-17 18:54:05 -05:00
for ( const FVertexInstanceID & VertexInstanceID : OutRawMesh . VertexInstances ( ) . GetElementIDs ( ) )
2017-06-30 12:21:06 -04:00
{
2019-01-17 18:54:05 -05:00
FVector TangentY = FVector : : CrossProduct ( VertexInstanceNormals [ VertexInstanceID ] , VertexInstanceTangents [ VertexInstanceID ] ) . GetSafeNormal ( ) * VertexInstanceBinormalSigns [ VertexInstanceID ] ;
TransformNormal ( VertexInstanceTangents [ VertexInstanceID ] ) ;
2018-03-27 16:13:55 -04:00
TransformNormal ( TangentY ) ;
2019-01-17 18:54:05 -05:00
TransformNormal ( VertexInstanceNormals [ VertexInstanceID ] ) ;
VertexInstanceBinormalSigns [ VertexInstanceID ] = GetBasisDeterminantSign ( VertexInstanceTangents [ VertexInstanceID ] , TangentY , VertexInstanceNormals [ VertexInstanceID ] ) ;
2017-06-30 12:21:06 -04:00
}
const bool bIsMirrored = InTransform . GetDeterminant ( ) < 0.f ;
if ( bIsMirrored )
{
2019-01-17 18:54:05 -05:00
//Reverse the vertexinstance
OutRawMesh . ReverseAllPolygonFacing ( ) ;
2017-06-30 12:21:06 -04:00
}
}
2019-01-17 18:54:05 -05:00
void FMeshMergeHelpers : : RetrieveCullingLandscapeAndVolumes ( UWorld * InWorld , const FBoxSphereBounds & EstimatedMeshProxyBounds , const TEnumAsByte < ELandscapeCullingPrecision : : Type > PrecisionType , TArray < FMeshDescription * > & CullingRawMeshes )
2017-06-30 12:21:06 -04:00
{
// Extract landscape proxies and cull volumes from the world
TArray < ALandscapeProxy * > LandscapeActors ;
TArray < AMeshMergeCullingVolume * > CullVolumes ;
uint32 MaxLandscapeExportLOD = 0 ;
if ( InWorld - > IsValidLowLevel ( ) )
{
for ( FConstLevelIterator Iterator = InWorld - > GetLevelIterator ( ) ; Iterator ; + + Iterator )
{
for ( AActor * Actor : ( * Iterator ) - > Actors )
{
if ( Actor )
{
ALandscapeProxy * LandscapeProxy = Cast < ALandscapeProxy > ( Actor ) ;
if ( LandscapeProxy & & LandscapeProxy - > bUseLandscapeForCullingInvisibleHLODVertices )
{
// Retrieve highest landscape LOD level possible
MaxLandscapeExportLOD = FMath : : Max ( MaxLandscapeExportLOD , FMath : : CeilLogTwo ( LandscapeProxy - > SubsectionSizeQuads + 1 ) - 1 ) ;
LandscapeActors . Add ( LandscapeProxy ) ;
}
// Check for culling volumes
AMeshMergeCullingVolume * Volume = Cast < AMeshMergeCullingVolume > ( Actor ) ;
if ( Volume )
{
// If the mesh's bounds intersect with the volume there is a possibility of culling
const bool bIntersecting = Volume - > EncompassesPoint ( EstimatedMeshProxyBounds . Origin , EstimatedMeshProxyBounds . SphereRadius , nullptr ) ;
if ( bIntersecting )
{
CullVolumes . Add ( Volume ) ;
}
}
}
}
}
}
// Setting determines the precision at which we should export the landscape for culling (highest, half or lowest)
const uint32 LandscapeExportLOD = ( ( float ) MaxLandscapeExportLOD * ( 0.5f * ( float ) PrecisionType ) ) ;
for ( ALandscapeProxy * Landscape : LandscapeActors )
{
// Export the landscape to raw mesh format
2019-01-24 15:35:51 -05:00
FMeshDescription * MeshDescription = new FMeshDescription ( ) ;
UStaticMesh : : RegisterMeshAttributes ( * MeshDescription ) ;
2017-06-30 12:21:06 -04:00
FBoxSphereBounds LandscapeBounds = EstimatedMeshProxyBounds ;
2019-01-24 15:35:51 -05:00
Landscape - > ExportToRawMesh ( LandscapeExportLOD , * MeshDescription , LandscapeBounds ) ;
if ( MeshDescription - > Vertices ( ) . Num ( ) )
2017-06-30 12:21:06 -04:00
{
2019-01-24 15:35:51 -05:00
CullingRawMeshes . Add ( MeshDescription ) ;
2017-06-30 12:21:06 -04:00
}
}
// Also add volume mesh data as culling meshes
for ( AMeshMergeCullingVolume * Volume : CullVolumes )
{
// Export the landscape to raw mesh format
2019-01-17 18:54:05 -05:00
FMeshDescription * VolumeMesh = new FMeshDescription ( ) ;
UStaticMesh : : RegisterMeshAttributes ( * VolumeMesh ) ;
2017-06-30 12:21:06 -04:00
TArray < FStaticMaterial > VolumeMaterials ;
GetBrushMesh ( Volume , Volume - > Brush , * VolumeMesh , VolumeMaterials ) ;
// Offset vertices to correct world position;
FVector VolumeLocation = Volume - > GetActorLocation ( ) ;
2019-01-17 18:54:05 -05:00
TVertexAttributesRef < FVector > VertexPositions = VolumeMesh - > VertexAttributes ( ) . GetAttributesRef < FVector > ( MeshAttribute : : Vertex : : Position ) ;
for ( const FVertexID & VertexID : VolumeMesh - > Vertices ( ) . GetElementIDs ( ) )
2017-06-30 12:21:06 -04:00
{
2019-01-17 18:54:05 -05:00
VertexPositions [ VertexID ] + = VolumeLocation ;
2017-06-30 12:21:06 -04:00
}
CullingRawMeshes . Add ( VolumeMesh ) ;
}
}
2018-07-31 17:06:48 -04:00
void FMeshMergeHelpers : : TransformPhysicsGeometry ( const FTransform & InTransform , const bool bBakeConvexTransform , struct FKAggregateGeom & AggGeom )
2017-06-30 12:21:06 -04:00
{
FTransform NoScaleInTransform = InTransform ;
NoScaleInTransform . SetScale3D ( FVector ( 1 , 1 , 1 ) ) ;
// Pre-scale all non-convex geometry
const FVector Scale3D = InTransform . GetScale3D ( ) ;
if ( ! Scale3D . Equals ( FVector ( 1.f ) ) )
{
const float MinPrimSize = KINDA_SMALL_NUMBER ;
for ( FKSphereElem & Elem : AggGeom . SphereElems )
{
Elem = Elem . GetFinalScaled ( Scale3D , FTransform : : Identity ) ;
}
for ( FKBoxElem & Elem : AggGeom . BoxElems )
{
Elem = Elem . GetFinalScaled ( Scale3D , FTransform : : Identity ) ;
}
for ( FKSphylElem & Elem : AggGeom . SphylElems )
{
Elem = Elem . GetFinalScaled ( Scale3D , FTransform : : Identity ) ;
}
}
// Multiply out merge transform (excluding scale) with original transforms for non-convex geometry
for ( FKSphereElem & Elem : AggGeom . SphereElems )
{
FTransform ElemTM = Elem . GetTransform ( ) ;
Elem . SetTransform ( ElemTM * NoScaleInTransform ) ;
}
for ( FKBoxElem & Elem : AggGeom . BoxElems )
{
FTransform ElemTM = Elem . GetTransform ( ) ;
Elem . SetTransform ( ElemTM * NoScaleInTransform ) ;
}
for ( FKSphylElem & Elem : AggGeom . SphylElems )
{
FTransform ElemTM = Elem . GetTransform ( ) ;
Elem . SetTransform ( ElemTM * NoScaleInTransform ) ;
}
for ( FKConvexElem & Elem : AggGeom . ConvexElems )
{
FTransform ElemTM = Elem . GetTransform ( ) ;
2018-07-31 17:06:48 -04:00
if ( bBakeConvexTransform )
{
for ( FVector & Position : Elem . VertexData )
{
Position = ElemTM . TransformPosition ( Position ) ;
}
Elem . SetTransform ( InTransform ) ;
}
else
{
Elem . SetTransform ( ElemTM * InTransform ) ;
}
2017-06-30 12:21:06 -04:00
}
}
2018-07-31 17:06:48 -04:00
void FMeshMergeHelpers : : ExtractPhysicsGeometry ( UBodySetup * InBodySetup , const FTransform & ComponentToWorld , const bool bBakeConvexTransform , struct FKAggregateGeom & OutAggGeom )
2017-06-30 12:21:06 -04:00
{
if ( InBodySetup = = nullptr )
{
return ;
}
OutAggGeom = InBodySetup - > AggGeom ;
// Convert boxes to convex, so they can be sheared
for ( int32 BoxIdx = 0 ; BoxIdx < OutAggGeom . BoxElems . Num ( ) ; BoxIdx + + )
{
FKConvexElem * NewConvexColl = new ( OutAggGeom . ConvexElems ) FKConvexElem ( ) ;
NewConvexColl - > ConvexFromBoxElem ( OutAggGeom . BoxElems [ BoxIdx ] ) ;
}
OutAggGeom . BoxElems . Empty ( ) ;
// we are not owner of this stuff
OutAggGeom . RenderInfo = nullptr ;
for ( FKConvexElem & Elem : OutAggGeom . ConvexElems )
{
Elem . SetConvexMesh ( nullptr ) ;
Elem . SetMirroredConvexMesh ( nullptr ) ;
}
// Transform geometry to world space
2018-07-31 17:06:48 -04:00
TransformPhysicsGeometry ( ComponentToWorld , bBakeConvexTransform , OutAggGeom ) ;
2017-06-30 12:21:06 -04:00
}
FVector2D FMeshMergeHelpers : : GetValidUV ( const FVector2D & UV )
{
FVector2D NewUV = UV ;
// first make sure they're positive
if ( UV . X < 0.0f )
{
NewUV . X = UV . X + FMath : : CeilToInt ( FMath : : Abs ( UV . X ) ) ;
}
if ( UV . Y < 0.0f )
{
NewUV . Y = UV . Y + FMath : : CeilToInt ( FMath : : Abs ( UV . Y ) ) ;
}
// now make sure they're within [0, 1]
if ( UV . X > 1.0f )
{
NewUV . X = FMath : : Fmod ( NewUV . X , 1.0f ) ;
}
if ( UV . Y > 1.0f )
{
NewUV . Y = FMath : : Fmod ( NewUV . Y , 1.0f ) ;
}
return NewUV ;
}
2019-01-17 18:54:05 -05:00
void FMeshMergeHelpers : : CalculateTextureCoordinateBoundsForRawMesh ( const FMeshDescription & InRawMesh , TArray < FBox2D > & OutBounds )
2017-06-30 12:21:06 -04:00
{
2019-01-17 18:54:05 -05:00
TVertexInstanceAttributesConstRef < FVector2D > VertexInstanceUVs = InRawMesh . VertexInstanceAttributes ( ) . GetAttributesRef < FVector2D > ( MeshAttribute : : VertexInstance : : TextureCoordinate ) ;
2017-06-30 12:21:06 -04:00
OutBounds . Empty ( ) ;
2019-01-17 18:54:05 -05:00
for ( const FPolygonID & PolygonID : InRawMesh . Polygons ( ) . GetElementIDs ( ) )
2017-06-30 12:21:06 -04:00
{
2019-01-17 18:54:05 -05:00
int32 MaterialIndex = InRawMesh . GetPolygonPolygonGroup ( PolygonID ) . GetValue ( ) ;
2017-06-30 12:21:06 -04:00
if ( OutBounds . Num ( ) < = MaterialIndex )
OutBounds . SetNumZeroed ( MaterialIndex + 1 ) ;
{
2019-01-17 18:54:05 -05:00
TArray < FVertexInstanceID > PolygonVertexInstances = InRawMesh . GetPolygonPerimeterVertexInstances ( PolygonID ) ;
for ( const FVertexInstanceID & VertexInstanceID : PolygonVertexInstances )
2017-06-30 12:21:06 -04:00
{
2019-01-17 18:54:05 -05:00
for ( int32 UVIndex = 0 ; UVIndex < VertexInstanceUVs . GetNumIndices ( ) ; + + UVIndex )
2017-06-30 12:21:06 -04:00
{
2019-01-17 18:54:05 -05:00
OutBounds [ MaterialIndex ] + = VertexInstanceUVs . Get ( VertexInstanceID , UVIndex ) ;
2017-06-30 12:21:06 -04:00
}
}
}
}
}
2019-01-17 18:54:05 -05:00
bool FMeshMergeHelpers : : PropagatePaintedColorsToRawMesh ( const UStaticMeshComponent * StaticMeshComponent , int32 LODIndex , FMeshDescription & RawMesh )
2017-06-30 12:21:06 -04:00
{
UStaticMesh * StaticMesh = StaticMeshComponent - > GetStaticMesh ( ) ;
if ( StaticMesh - > SourceModels . IsValidIndex ( LODIndex ) & &
StaticMeshComponent - > LODData . IsValidIndex ( LODIndex ) & &
StaticMeshComponent - > LODData [ LODIndex ] . OverrideVertexColors ! = nullptr )
{
FColorVertexBuffer & ColorVertexBuffer = * StaticMeshComponent - > LODData [ LODIndex ] . OverrideVertexColors ;
2018-02-14 14:13:42 -05:00
FStaticMeshLODResources & RenderModel = StaticMesh - > RenderData - > LODResources [ LODIndex ] ;
2017-06-30 12:21:06 -04:00
if ( ColorVertexBuffer . GetNumVertices ( ) = = RenderModel . GetNumVertices ( ) )
2018-02-14 14:13:42 -05:00
{
2019-01-17 18:54:05 -05:00
const int32 NumWedges = RawMesh . VertexInstances ( ) . Num ( ) ;
2018-02-14 14:13:42 -05:00
const int32 NumRenderWedges = RenderModel . IndexBuffer . GetNumIndices ( ) ;
const bool bUseRenderWedges = NumWedges = = NumRenderWedges ;
2019-01-17 18:54:05 -05:00
TVertexInstanceAttributesRef < FVector4 > VertexInstanceColors = RawMesh . VertexInstanceAttributes ( ) . GetAttributesRef < FVector4 > ( MeshAttribute : : VertexInstance : : Color ) ;
2018-02-14 14:13:42 -05:00
if ( bUseRenderWedges )
2017-06-30 12:21:06 -04:00
{
2019-01-17 18:54:05 -05:00
//Create a map index
TMap < int32 , FVertexInstanceID > IndexToVertexInstanceID ;
IndexToVertexInstanceID . Reserve ( NumWedges ) ;
int32 CurrentWedgeIndex = 0 ;
for ( const FPolygonID & PolygonID : RawMesh . Polygons ( ) . GetElementIDs ( ) )
2017-06-30 12:21:06 -04:00
{
2019-01-17 18:54:05 -05:00
const TArray < FMeshTriangle > & Triangles = RawMesh . GetPolygonTriangles ( PolygonID ) ;
for ( const FMeshTriangle & Triangle : Triangles )
{
for ( int32 Corner = 0 ; Corner < 3 ; + + Corner , + + CurrentWedgeIndex )
{
IndexToVertexInstanceID . Add ( CurrentWedgeIndex , Triangle . GetVertexInstanceID ( Corner ) ) ;
}
}
2017-06-30 12:21:06 -04:00
}
2018-02-14 14:13:42 -05:00
const FIndexArrayView ArrayView = RenderModel . IndexBuffer . GetArrayView ( ) ;
for ( int32 WedgeIndex = 0 ; WedgeIndex < NumRenderWedges ; WedgeIndex + + )
{
const int32 Index = ArrayView [ WedgeIndex ] ;
FColor WedgeColor = FColor : : White ;
if ( Index ! = INDEX_NONE )
{
WedgeColor = ColorVertexBuffer . VertexColor ( Index ) ;
}
2019-01-17 18:54:05 -05:00
VertexInstanceColors [ IndexToVertexInstanceID [ WedgeIndex ] ] = FLinearColor ( WedgeColor ) ;
2018-02-14 14:13:42 -05:00
}
return true ;
2017-06-30 12:21:06 -04:00
}
// No wedge map (this can happen when we poly reduce the LOD for example)
2019-01-17 18:54:05 -05:00
// Use index buffer directly. Not sure this will happen with FMeshDescription
2017-06-30 12:21:06 -04:00
else
{
2019-01-17 18:54:05 -05:00
if ( RawMesh . Vertices ( ) . Num ( ) = = ColorVertexBuffer . GetNumVertices ( ) )
2017-06-30 12:21:06 -04:00
{
2019-01-17 18:54:05 -05:00
//Create a map index
TMap < FVertexID , int32 > VertexIDToVertexIndex ;
VertexIDToVertexIndex . Reserve ( RawMesh . Vertices ( ) . Num ( ) ) ;
int32 CurrentVertexIndex = 0 ;
for ( const FVertexID & VertexID : RawMesh . Vertices ( ) . GetElementIDs ( ) )
{
VertexIDToVertexIndex . Add ( VertexID , CurrentVertexIndex + + ) ;
}
for ( const FVertexID & VertexID : RawMesh . Vertices ( ) . GetElementIDs ( ) )
2017-06-30 12:21:06 -04:00
{
FColor WedgeColor = FColor : : White ;
2019-01-17 18:54:05 -05:00
uint32 VertIndex = VertexIDToVertexIndex [ VertexID ] ;
2017-06-30 12:21:06 -04:00
if ( VertIndex < ColorVertexBuffer . GetNumVertices ( ) )
{
WedgeColor = ColorVertexBuffer . VertexColor ( VertIndex ) ;
}
2019-01-17 18:54:05 -05:00
const TArray < FVertexInstanceID > & VertexInstances = RawMesh . GetVertexVertexInstances ( VertexID ) ;
for ( const FVertexInstanceID & VertexInstanceID : VertexInstances )
{
VertexInstanceColors [ VertexInstanceID ] = FLinearColor ( WedgeColor ) ;
}
2017-06-30 12:21:06 -04:00
}
return true ;
}
}
}
}
return false ;
}
bool FMeshMergeHelpers : : IsLandscapeHit ( const FVector & RayOrigin , const FVector & RayEndPoint , const UWorld * World , const TArray < ALandscapeProxy * > & LandscapeProxies , FVector & OutHitLocation )
{
TArray < FHitResult > Results ;
// Each landscape component has 2 collision shapes, 1 of them is specific to landscape editor
// Trace only ECC_Visibility channel, so we do hit only Editor specific shape
World - > LineTraceMultiByObjectType ( Results , RayOrigin , RayEndPoint , FCollisionObjectQueryParams ( ECollisionChannel : : ECC_WorldStatic ) , FCollisionQueryParams ( SCENE_QUERY_STAT ( LandscapeTrace ) , true ) ) ;
bool bHitLandscape = false ;
for ( const FHitResult & HitResult : Results )
{
ULandscapeHeightfieldCollisionComponent * CollisionComponent = Cast < ULandscapeHeightfieldCollisionComponent > ( HitResult . Component . Get ( ) ) ;
if ( CollisionComponent )
{
ALandscapeProxy * HitLandscape = CollisionComponent - > GetLandscapeProxy ( ) ;
if ( HitLandscape & & LandscapeProxies . Contains ( HitLandscape ) )
{
// Could write a correct clipping algorithm, that clips the triangle to hit location
OutHitLocation = HitLandscape - > LandscapeActorToWorld ( ) . InverseTransformPosition ( HitResult . Location ) ;
// Above landscape so visible
bHitLandscape = true ;
}
}
}
return bHitLandscape ;
}
2018-03-06 13:26:20 -05:00
2019-01-17 18:54:05 -05:00
void FMeshMergeHelpers : : AppendRawMesh ( FMeshDescription & InTarget , const FMeshDescription & InSource )
2018-03-06 13:26:20 -05:00
{
2019-01-17 18:54:05 -05:00
TVertexAttributesConstRef < FVector > SourceVertexPositions = InSource . VertexAttributes ( ) . GetAttributesRef < FVector > ( MeshAttribute : : Vertex : : Position ) ;
TEdgeAttributesConstRef < bool > SourceEdgeHardnesses = InSource . EdgeAttributes ( ) . GetAttributesRef < bool > ( MeshAttribute : : Edge : : IsHard ) ;
TEdgeAttributesConstRef < float > SourceEdgeCreaseSharpnesses = InSource . EdgeAttributes ( ) . GetAttributesRef < float > ( MeshAttribute : : Edge : : CreaseSharpness ) ;
TPolygonGroupAttributesConstRef < FName > SourcePolygonGroupImportedMaterialSlotNames = InSource . PolygonGroupAttributes ( ) . GetAttributesRef < FName > ( MeshAttribute : : PolygonGroup : : ImportedMaterialSlotName ) ;
TVertexInstanceAttributesConstRef < FVector > SourceVertexInstanceNormals = InSource . VertexInstanceAttributes ( ) . GetAttributesRef < FVector > ( MeshAttribute : : VertexInstance : : Normal ) ;
TVertexInstanceAttributesConstRef < FVector > SourceVertexInstanceTangents = InSource . VertexInstanceAttributes ( ) . GetAttributesRef < FVector > ( MeshAttribute : : VertexInstance : : Tangent ) ;
TVertexInstanceAttributesConstRef < float > SourceVertexInstanceBinormalSigns = InSource . VertexInstanceAttributes ( ) . GetAttributesRef < float > ( MeshAttribute : : VertexInstance : : BinormalSign ) ;
TVertexInstanceAttributesConstRef < FVector4 > SourceVertexInstanceColors = InSource . VertexInstanceAttributes ( ) . GetAttributesRef < FVector4 > ( MeshAttribute : : VertexInstance : : Color ) ;
TVertexInstanceAttributesConstRef < FVector2D > SourceVertexInstanceUVs = InSource . VertexInstanceAttributes ( ) . GetAttributesRef < FVector2D > ( MeshAttribute : : VertexInstance : : TextureCoordinate ) ;
TVertexAttributesRef < FVector > TargetVertexPositions = InTarget . VertexAttributes ( ) . GetAttributesRef < FVector > ( MeshAttribute : : Vertex : : Position ) ;
TEdgeAttributesRef < bool > TargetEdgeHardnesses = InTarget . EdgeAttributes ( ) . GetAttributesRef < bool > ( MeshAttribute : : Edge : : IsHard ) ;
TEdgeAttributesRef < float > TargetEdgeCreaseSharpnesses = InTarget . EdgeAttributes ( ) . GetAttributesRef < float > ( MeshAttribute : : Edge : : CreaseSharpness ) ;
TPolygonGroupAttributesRef < FName > TargetPolygonGroupImportedMaterialSlotNames = InTarget . PolygonGroupAttributes ( ) . GetAttributesRef < FName > ( MeshAttribute : : PolygonGroup : : ImportedMaterialSlotName ) ;
TVertexInstanceAttributesRef < FVector > TargetVertexInstanceNormals = InTarget . VertexInstanceAttributes ( ) . GetAttributesRef < FVector > ( MeshAttribute : : VertexInstance : : Normal ) ;
TVertexInstanceAttributesRef < FVector > TargetVertexInstanceTangents = InTarget . VertexInstanceAttributes ( ) . GetAttributesRef < FVector > ( MeshAttribute : : VertexInstance : : Tangent ) ;
TVertexInstanceAttributesRef < float > TargetVertexInstanceBinormalSigns = InTarget . VertexInstanceAttributes ( ) . GetAttributesRef < float > ( MeshAttribute : : VertexInstance : : BinormalSign ) ;
TVertexInstanceAttributesRef < FVector4 > TargetVertexInstanceColors = InTarget . VertexInstanceAttributes ( ) . GetAttributesRef < FVector4 > ( MeshAttribute : : VertexInstance : : Color ) ;
TVertexInstanceAttributesRef < FVector2D > TargetVertexInstanceUVs = InTarget . VertexInstanceAttributes ( ) . GetAttributesRef < FVector2D > ( MeshAttribute : : VertexInstance : : TextureCoordinate ) ;
InTarget . ReserveNewVertices ( InSource . Vertices ( ) . Num ( ) ) ;
InTarget . ReserveNewVertexInstances ( InSource . VertexInstances ( ) . Num ( ) ) ;
InTarget . ReserveNewEdges ( InSource . Edges ( ) . Num ( ) ) ;
InTarget . ReserveNewPolygons ( InSource . Vertices ( ) . Num ( ) ) ;
//Append PolygonGroup
for ( const FPolygonGroupID & SourcePolygonGroupID : InSource . PolygonGroups ( ) . GetElementIDs ( ) )
2018-03-06 13:26:20 -05:00
{
2019-01-17 18:54:05 -05:00
if ( ! InTarget . IsPolygonGroupValid ( SourcePolygonGroupID ) )
2018-03-06 13:26:20 -05:00
{
2019-04-01 17:02:13 -04:00
const FName BaseName = SourcePolygonGroupImportedMaterialSlotNames [ SourcePolygonGroupID ] ;
FName CurrentTestName = BaseName ;
int32 UniqueID = 1 ;
bool bUnique = true ;
do
{
for ( const FPolygonGroupID PolygonGroupID : InTarget . PolygonGroups ( ) . GetElementIDs ( ) )
{
if ( TargetPolygonGroupImportedMaterialSlotNames [ PolygonGroupID ] = = CurrentTestName )
{
CurrentTestName = FName ( * ( BaseName . ToString ( ) + FString : : FromInt ( UniqueID + + ) ) ) ;
bUnique = false ;
}
}
} while ( ! bUnique ) ;
2019-05-07 17:33:25 -04:00
InTarget . CreatePolygonGroupWithID ( SourcePolygonGroupID ) ;
2019-04-01 17:02:13 -04:00
TargetPolygonGroupImportedMaterialSlotNames [ SourcePolygonGroupID ] = CurrentTestName ;
2018-03-06 13:26:20 -05:00
}
}
2019-01-17 18:54:05 -05:00
//Append the Vertexs
TMap < FVertexID , FVertexID > SourceToTargetVertexID ;
SourceToTargetVertexID . Reserve ( InSource . Vertices ( ) . Num ( ) ) ;
for ( const FVertexID & SourceVertexID : InSource . Vertices ( ) . GetElementIDs ( ) )
2018-03-06 13:26:20 -05:00
{
2019-01-17 18:54:05 -05:00
const FVertexID TargetVertexID = InTarget . CreateVertex ( ) ;
SourceToTargetVertexID . Add ( SourceVertexID , TargetVertexID ) ;
2019-04-01 09:20:34 -04:00
TargetVertexPositions [ TargetVertexID ] = SourceVertexPositions [ SourceVertexID ] ;
2018-03-06 13:26:20 -05:00
}
2019-01-17 18:54:05 -05:00
//Append VertexInstances
if ( SourceVertexInstanceUVs . GetNumIndices ( ) > TargetVertexInstanceUVs . GetNumIndices ( ) )
2018-03-06 13:26:20 -05:00
{
2019-01-17 18:54:05 -05:00
TargetVertexInstanceUVs . SetNumIndices ( SourceVertexInstanceUVs . GetNumIndices ( ) ) ;
2018-03-06 13:26:20 -05:00
}
2019-01-17 18:54:05 -05:00
TMap < FVertexInstanceID , FVertexInstanceID > SourceToTargetVertexInstanceID ;
SourceToTargetVertexInstanceID . Reserve ( InSource . VertexInstances ( ) . Num ( ) ) ;
for ( const FVertexInstanceID & SourceVertexInstanceID : InSource . VertexInstances ( ) . GetElementIDs ( ) )
2018-03-06 13:26:20 -05:00
{
2019-01-17 18:54:05 -05:00
const FVertexID SourceVertexID = InSource . GetVertexInstanceVertex ( SourceVertexInstanceID ) ;
const FVertexInstanceID TargetVertexInstanceID = InTarget . CreateVertexInstance ( SourceToTargetVertexID [ SourceVertexID ] ) ;
TargetVertexInstanceTangents [ TargetVertexInstanceID ] = SourceVertexInstanceTangents [ SourceVertexInstanceID ] ;
TargetVertexInstanceBinormalSigns [ TargetVertexInstanceID ] = SourceVertexInstanceBinormalSigns [ SourceVertexInstanceID ] ;
TargetVertexInstanceNormals [ TargetVertexInstanceID ] = SourceVertexInstanceNormals [ SourceVertexInstanceID ] ;
TargetVertexInstanceColors [ TargetVertexInstanceID ] = SourceVertexInstanceColors [ SourceVertexInstanceID ] ;
for ( int32 UVIndex = 0 ; UVIndex < TargetVertexInstanceUVs . GetNumIndices ( ) ; + + UVIndex )
2018-03-06 13:26:20 -05:00
{
2019-01-17 18:54:05 -05:00
FVector2D SourceUV = SourceVertexInstanceUVs . GetNumIndices ( ) > UVIndex ? SourceVertexInstanceUVs . Get ( SourceVertexInstanceID , UVIndex ) : FVector2D ( 0.0f , 0.0f ) ;
TargetVertexInstanceUVs . Set ( TargetVertexInstanceID , UVIndex , SourceUV ) ;
2018-03-06 13:26:20 -05:00
}
2019-01-17 18:54:05 -05:00
SourceToTargetVertexInstanceID . Add ( SourceVertexInstanceID , TargetVertexInstanceID ) ;
2018-03-06 13:26:20 -05:00
}
2019-01-17 18:54:05 -05:00
//Append Edges
TMap < FEdgeID , FEdgeID > SourceToTargetEdgeID ;
SourceToTargetEdgeID . Reserve ( InSource . Edges ( ) . Num ( ) ) ;
for ( const FEdgeID & SourceEdgeID : InSource . Edges ( ) . GetElementIDs ( ) )
{
const FMeshEdge & SourceEdge = InSource . GetEdge ( SourceEdgeID ) ;
const FEdgeID TargetEdgeID = InTarget . CreateEdge ( SourceToTargetVertexID [ SourceEdge . VertexIDs [ 0 ] ] , SourceToTargetVertexID [ SourceEdge . VertexIDs [ 1 ] ] ) ;
TargetEdgeHardnesses [ TargetEdgeID ] = SourceEdgeHardnesses [ SourceEdgeID ] ;
TargetEdgeCreaseSharpnesses [ TargetEdgeID ] = SourceEdgeCreaseSharpnesses [ SourceEdgeID ] ;
SourceToTargetEdgeID . Add ( SourceEdgeID , TargetEdgeID ) ;
}
2019-01-29 19:23:19 -05:00
auto CreateContour = [ & InSource , & SourceToTargetVertexInstanceID , & SourceToTargetEdgeID ] ( const TArray < FVertexInstanceID > & SourceVertexInstanceIDs , TArray < FVertexInstanceID > & DestVertexInstanceIDs )
2019-01-17 18:54:05 -05:00
{
const int32 ContourCount = SourceVertexInstanceIDs . Num ( ) ;
for ( int32 ContourIndex = 0 ; ContourIndex < ContourCount ; + + ContourIndex )
{
FVertexInstanceID SourceVertexInstanceID = SourceVertexInstanceIDs [ ContourIndex ] ;
2019-01-29 19:23:19 -05:00
DestVertexInstanceIDs . Add ( SourceToTargetVertexInstanceID [ SourceVertexInstanceID ] ) ;
2019-01-17 18:54:05 -05:00
}
} ;
//Append Polygons
for ( const FPolygonID & SourcePolygonID : InSource . Polygons ( ) . GetElementIDs ( ) )
{
const FMeshPolygon & SourcePolygon = InSource . GetPolygon ( SourcePolygonID ) ;
const TArray < FVertexInstanceID > & SourceVertexInstanceIDs = InSource . GetPolygonPerimeterVertexInstances ( SourcePolygonID ) ;
2019-01-29 19:23:19 -05:00
TArray < FVertexInstanceID > ContourVertexInstances ;
CreateContour ( SourceVertexInstanceIDs , ContourVertexInstances ) ;
2019-01-17 18:54:05 -05:00
// Insert a polygon into the mesh
2019-01-29 19:23:19 -05:00
const FPolygonID TargetPolygonID = InTarget . CreatePolygon ( SourcePolygon . PolygonGroupID , ContourVertexInstances ) ;
2019-01-17 18:54:05 -05:00
//Triangulate the polygon
FMeshPolygon & Polygon = InTarget . GetPolygon ( TargetPolygonID ) ;
InTarget . ComputePolygonTriangulation ( TargetPolygonID , Polygon . Triangles ) ;
}
2018-03-06 13:26:20 -05:00
}
2019-01-17 18:54:05 -05:00
void FMeshMergeHelpers : : MergeImpostersToRawMesh ( TArray < const UStaticMeshComponent * > ImposterComponents , FMeshDescription & InRawMesh , const FVector & InPivot , int32 InBaseMaterialIndex , TArray < UMaterialInterface * > & OutImposterMaterials )
2018-03-06 13:26:20 -05:00
{
// TODO decide whether we want this to be user specified or derived from the RawMesh
/*const int32 UVOneIndex = [RawMesh, Data]() -> int32
{
int32 ChannelIndex = 0 ;
for ( ; ChannelIndex < MAX_MESH_TEXTURE_COORDS ; + + ChannelIndex )
{
if ( RawMesh . WedgeTexCoords [ ChannelIndex ] . Num ( ) = = 0 )
{
break ;
}
}
int32 MaxUVChannel = ChannelIndex ;
for ( const UStaticMeshComponent * Component : ImposterComponents )
{
MaxUVChannel = FMath : : Max ( MaxUVChannel , Component - > GetStaticMesh ( ) - > RenderData - > LODResources [ Component - > GetStaticMesh ( ) - > GetNumLODs ( ) - 1 ] . GetNumTexCoords ( ) ) ;
}
return MaxUVChannel ;
} ( ) ; */
const int32 UVOneIndex = 2 ; // if this is changed back to being dynamic, renable the if statement below
// Ensure there are enough UV channels available to store the imposter data
//if (UVOneIndex != INDEX_NONE && UVOneIndex < (MAX_MESH_TEXTURE_COORDS - 2))
{
2019-04-01 09:20:44 -04:00
TMap < UMaterialInterface * , FPolygonGroupID > ImposterMaterialToPolygonGroupID ;
2018-03-06 13:26:20 -05:00
for ( const UStaticMeshComponent * Component : ImposterComponents )
{
// Retrieve imposter LOD mesh and material
const int32 LODIndex = Component - > GetStaticMesh ( ) - > GetNumLODs ( ) - 1 ;
2019-01-17 18:54:05 -05:00
// Retrieve mesh data in FMeshDescription form
FMeshDescription ImposterMesh ;
2019-03-25 17:14:59 -04:00
UStaticMesh : : RegisterMeshAttributes ( ImposterMesh ) ;
2018-03-06 13:26:20 -05:00
FMeshMergeHelpers : : RetrieveMesh ( Component , LODIndex , ImposterMesh , false ) ;
// Retrieve the sections, we're expect 1 for imposter meshes
TArray < FSectionInfo > Sections ;
FMeshMergeHelpers : : ExtractSections ( Component , LODIndex , Sections ) ;
2019-04-01 09:20:44 -04:00
TArray < int32 > SectionImposterUniqueMaterialIndex ;
2018-03-06 13:26:20 -05:00
for ( FSectionInfo & Info : Sections )
{
2019-04-01 09:20:44 -04:00
SectionImposterUniqueMaterialIndex . Add ( OutImposterMaterials . AddUnique ( Info . Material ) ) ;
2018-03-06 13:26:20 -05:00
}
// Imposter magic, we're storing the actor world position and X scale spread across two UV channels
const int32 UVTwoIndex = UVOneIndex + 1 ;
2019-01-17 18:54:05 -05:00
TVertexInstanceAttributesRef < FVector2D > VertexInstanceUVs = ImposterMesh . VertexInstanceAttributes ( ) . GetAttributesRef < FVector2D > ( MeshAttribute : : VertexInstance : : TextureCoordinate ) ;
VertexInstanceUVs . SetNumIndices ( UVTwoIndex + 1 ) ;
const int32 NumIndices = ImposterMesh . VertexInstances ( ) . Num ( ) ;
2018-03-06 13:26:20 -05:00
const FTransform & ActorToWorld = Component - > GetOwner ( ) - > GetActorTransform ( ) ;
const FVector ActorPosition = ActorToWorld . TransformPosition ( FVector : : ZeroVector ) - InPivot ;
2019-01-17 18:54:05 -05:00
for ( const FVertexInstanceID & VertexInstanceID : ImposterMesh . VertexInstances ( ) . GetElementIDs ( ) )
2018-03-06 13:26:20 -05:00
{
2019-01-17 18:54:05 -05:00
FVector2D UVOne ;
FVector2D UVTwo ;
2018-03-06 13:26:20 -05:00
UVOne . X = ActorPosition . X ;
UVOne . Y = ActorPosition . Y ;
2019-01-17 18:54:05 -05:00
VertexInstanceUVs . Set ( VertexInstanceID , UVOneIndex , UVOne ) ;
2018-03-06 13:26:20 -05:00
UVTwo . X = ActorPosition . Z ;
2019-04-01 17:02:29 -04:00
UVTwo . Y = FMath : : Abs ( ActorToWorld . GetScale3D ( ) . X ) ;
2019-01-17 18:54:05 -05:00
VertexInstanceUVs . Set ( VertexInstanceID , UVTwoIndex , UVTwo ) ;
2018-03-06 13:26:20 -05:00
}
2019-04-01 09:20:34 -04:00
TPolygonGroupAttributesRef < FName > SourcePolygonGroupImportedMaterialSlotNames = ImposterMesh . PolygonGroupAttributes ( ) . GetAttributesRef < FName > ( MeshAttribute : : PolygonGroup : : ImportedMaterialSlotName ) ;
TPolygonGroupAttributesRef < FName > TargetPolygonGroupImportedMaterialSlotNames = InRawMesh . PolygonGroupAttributes ( ) . GetAttributesRef < FName > ( MeshAttribute : : PolygonGroup : : ImportedMaterialSlotName ) ;
//Add the missing polygon group ID to the target(InRawMesh)
//Remap the source mesh(ImposterMesh) polygongroup to fit with the target polygon groups
TMap < FPolygonGroupID , FPolygonGroupID > RemapSourcePolygonGroup ;
RemapSourcePolygonGroup . Reserve ( ImposterMesh . PolygonGroups ( ) . Num ( ) ) ;
2019-04-01 09:20:44 -04:00
int32 SectionIndex = 0 ;
2019-04-01 09:20:34 -04:00
for ( const FPolygonGroupID & SourcePolygonGroupID : ImposterMesh . PolygonGroups ( ) . GetElementIDs ( ) )
{
2019-04-01 09:20:44 -04:00
UMaterialInterface * MaterialUseBySection = OutImposterMaterials [ SectionImposterUniqueMaterialIndex [ SectionIndex + + ] ] ;
FPolygonGroupID * ExistTargetPolygonGroupID = ImposterMaterialToPolygonGroupID . Find ( MaterialUseBySection ) ;
FPolygonGroupID MatchTargetPolygonGroupID = ExistTargetPolygonGroupID = = nullptr ? FPolygonGroupID : : Invalid : * ExistTargetPolygonGroupID ;
2019-04-01 09:20:34 -04:00
if ( MatchTargetPolygonGroupID = = FPolygonGroupID : : Invalid )
{
MatchTargetPolygonGroupID = InRawMesh . CreatePolygonGroup ( ) ;
2019-04-01 17:02:13 -04:00
//use the material name to fill the imported material name. Material name will be unique
TargetPolygonGroupImportedMaterialSlotNames [ MatchTargetPolygonGroupID ] = MaterialUseBySection - > GetFName ( ) ;
2019-04-01 09:20:44 -04:00
ImposterMaterialToPolygonGroupID . Add ( MaterialUseBySection , MatchTargetPolygonGroupID ) ;
2019-04-01 09:20:34 -04:00
}
RemapSourcePolygonGroup . Add ( SourcePolygonGroupID , MatchTargetPolygonGroupID ) ;
}
FMeshDescriptionOperations : : RemapPolygonGroups ( ImposterMesh , RemapSourcePolygonGroup ) ;
2018-03-06 13:26:20 -05:00
FMeshMergeHelpers : : AppendRawMesh ( InRawMesh , ImposterMesh ) ;
}
}
2019-01-17 18:54:05 -05:00
}