2019-01-02 14:54:39 -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"
2018-09-18 13:00:20 -04: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 ) ;
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
}
2018-05-09 18:45:58 -04:00
const bool bMirrored = Component - > GetComponentToWorld ( ) . GetDeterminant ( ) < 0.f ;
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 ;
2018-05-09 18:45:58 -04:00
// In case the object is mirrored the material indices/vertex data will be reversed in place, so we need to adjust the sections accordingly
if ( bMirrored )
{
const uint32 NumTriangles = StaticMesh - > RenderData - > LODResources [ LODIndex ] . GetNumTriangles ( ) ;
SectionInfo . StartIndex = NumTriangles - SectionInfo . EndIndex ;
SectionInfo . EndIndex = SectionInfo . StartIndex + MeshSection . NumTriangles ;
}
2017-06-30 12:21:06 -04:00
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 ) ;
}
}
2018-10-03 16:09:08 -04:00
void FMeshMergeHelpers : : ExpandInstances ( const UInstancedStaticMeshComponent * InInstancedStaticMeshComponent , FMeshDescription & InOutRawMesh , TArray < FSectionInfo > & InOutSections )
2018-03-06 13:26:20 -05:00
{
2018-10-03 16:09:08 -04:00
FMeshDescription CombinedRawMesh ;
2018-03-06 13:26:20 -05:00
for ( const FInstancedStaticMeshInstanceData & InstanceData : InInstancedStaticMeshComponent - > PerInstanceSMData )
{
2018-10-03 16:09:08 -04:00
FMeshDescription InstanceRawMesh = InOutRawMesh ;
2018-03-06 13:26:20 -05:00
FMeshMergeHelpers : : TransformRawMeshVertexData ( FTransform ( InstanceData . Transform ) , InstanceRawMesh ) ;
FMeshMergeHelpers : : AppendRawMesh ( CombinedRawMesh , InstanceRawMesh ) ;
}
InOutRawMesh = CombinedRawMesh ;
}
2018-10-03 16:09:08 -04: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 > ( ) ;
2018-12-10 09:29:08 -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
2018-10-03 16:09:08 -04: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.
2018-10-03 16:09:08 -04: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 ) ;
2018-10-03 16:09:08 -04: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
2018-10-03 16:09:08 -04:00
uint32 TangentOptions = FMeshDescriptionOperations : : ETangentOptions : : BlendOverlappingNormals ;
if ( BuildSettings . bRemoveDegenerates )
2017-06-30 12:21:06 -04:00
{
2018-10-03 16:09:08 -04:00
// If removing degenerate triangles, ignore them when computing tangents.
TangentOptions | = FMeshDescriptionOperations : : ETangentOptions : : IgnoreDegenerateTriangles ;
2017-06-30 12:21:06 -04:00
}
2018-10-03 16:09:08 -04:00
FMeshDescriptionOperations : : RecomputeNormalsAndTangentsIfNeeded ( RawMesh , ( FMeshDescriptionOperations : : ETangentOptions ) TangentOptions , BuildSettings . bUseMikkTSpace ) ;
2017-06-30 12:21:06 -04:00
}
2018-10-03 16:09:08 -04: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 ] ;
2018-10-03 16:09:08 -04: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 )
{
2018-10-03 16:09:08 -04:00
const FVertexID VertexID = RawMesh . CreateVertex ( ) ;
VertexPositions [ VertexID ] = FinalVertices [ VertIndex ] . Position ;
2017-06-30 12:21:06 -04:00
}
2018-10-03 16:09:08 -04:00
VertexInstanceUVs . SetNumIndices ( MAX_TEXCOORDS ) ;
2017-06-30 12:21:06 -04:00
2018-10-03 16:09:08 -04: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 ;
2018-10-03 16:09:08 -04: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 ( ) ) ;
}
2018-10-03 16:09:08 -04:00
FName ImportedMaterialSlotName = SkeletalMeshComponent - > SkeletalMesh - > Materials [ MaterialIndex ] . ImportedMaterialSlotName ;
const FPolygonGroupID SectionPolygonGroupID ( SectionMaterialIndex ) ;
if ( ! RawMesh . IsPolygonGroupValid ( SectionPolygonGroupID ) )
2018-02-14 14:13:42 -05:00
{
2018-10-03 16:09:08 -04:00
RawMesh . CreatePolygonGroupWithID ( SectionPolygonGroupID ) ;
PolygonGroupImportedMaterialSlotNames [ SectionPolygonGroupID ] = ImportedMaterialSlotName ;
}
int32 WedgeIndex = 0 ;
for ( uint32 SectionTriangleIndex = 0 ; SectionTriangleIndex < SkelMeshSection . NumTriangles ; + + SectionTriangleIndex )
{
FVertexID VertexIndexes [ 3 ] ;
2019-01-18 06:37:35 -05:00
TArray < FVertexInstanceID > VertexInstanceIDs ;
VertexInstanceIDs . SetNum ( 3 ) ;
2018-10-03 16:09:08 -04: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-18 06:37:35 -05:00
const FPolygonID NewPolygonID = RawMesh . CreatePolygon ( SectionPolygonGroupID , VertexInstanceIDs ) ;
2018-10-03 16:09:08 -04:00
//Triangulate the polygon
FMeshPolygon & Polygon = RawMesh . GetPolygon ( NewPolygonID ) ;
RawMesh . ComputePolygonTriangulation ( NewPolygonID , Polygon . Triangles ) ;
2017-06-30 12:21:06 -04:00
}
}
}
}
2018-10-03 16:09:08 -04: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 ] ;
2018-12-10 09:29:08 -05:00
// Imported meshes will have a valid mesh description
const bool bImportedMesh = StaticMesh - > IsMeshDescriptionValid ( LODIndex ) ;
2018-10-03 16:09:08 -04:00
2017-06-30 12:21:06 -04:00
// Check whether or not this mesh has been reduced in-engine
2018-12-05 14:55:06 -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 )
{
2018-12-10 09:29:08 -05:00
RawMesh = * StaticMesh - > GetMeshDescription ( LODIndex ) ;
2017-06-30 12:21:06 -04:00
}
else
{
2018-10-03 16:09:08 -04: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.
2018-10-03 16:09:08 -04: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 ;
2018-10-03 16:09:08 -04: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
{
2018-10-03 16:09:08 -04:00
// If removing degenerate triangles, ignore them when computing tangents.
TangentOptions | = FMeshDescriptionOperations : : ETangentOptions : : IgnoreDegenerateTriangles ;
2017-06-30 12:21:06 -04:00
}
2018-10-03 16:09:08 -04:00
FMeshDescriptionOperations : : RecomputeNormalsAndTangentsIfNeeded ( RawMesh , ( FMeshDescriptionOperations : : ETangentOptions ) TangentOptions , BuildSettings . bUseMikkTSpace , ( bImportedMesh & & BuildSettings . bRecomputeNormals ) , ( bImportedMesh & & BuildSettings . bRecomputeTangents ) ) ;
2017-06-30 12:21:06 -04:00
}
2018-10-03 16:09:08 -04: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 ;
2018-10-03 16:09:08 -04:00
OutRawMesh . Empty ( ) ;
2017-06-30 12:21:06 -04:00
2018-10-03 16:09:08 -04:00
if ( NumVertexPositions < = 0 | | StaticMeshLOD . VertexBuffers . StaticMeshVertexBuffer . GetNumVertices ( ) < = 0 )
2017-06-30 12:21:06 -04:00
{
2018-10-03 16:09:08 -04: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
{
2018-10-03 16:09:08 -04:00
PolygonGroupImportedMaterialSlotNames [ CurrentPolygonGroupID ] = Materials [ Section . MaterialIndex ] . ImportedMaterialSlotName ;
}
else
{
PolygonGroupImportedMaterialSlotNames [ CurrentPolygonGroupID ] = FName ( * ( TEXT ( " MeshMergeMaterial_ " ) + FString : : FromInt ( SectionIndex ) ) ) ;
2017-06-30 12:21:06 -04:00
}
}
2018-10-03 16:09:08 -04:00
//Create the vertex
for ( int32 VertexIndex = 0 ; VertexIndex < NumVertexPositions ; + + VertexIndex )
2017-06-30 12:21:06 -04:00
{
2018-10-03 16:09:08 -04:00
FVertexID VertexID = OutRawMesh . CreateVertex ( ) ;
VertexPositions [ VertexID ] = StaticMeshLOD . VertexBuffers . PositionVertexBuffer . VertexPosition ( VertexIndex ) ;
}
2017-06-30 12:21:06 -04:00
2018-10-03 16:09:08 -04: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
{
2018-10-03 16:09:08 -04: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
}
2018-10-03 16:09:08 -04:00
check ( CurrentPolygonGroupID ! = FPolygonGroupID : : Invalid ) ;
2017-06-30 12:21:06 -04:00
2018-10-03 16:09:08 -04:00
FVertexID VertexIDs [ 3 ] ;
2019-01-18 06:37:35 -05:00
TArray < FVertexInstanceID > VertexInstanceIDs ;
VertexInstanceIDs . SetNum ( 3 ) ;
2018-10-03 16:09:08 -04:00
for ( int32 Corner = 0 ; Corner < 3 ; + + Corner )
2017-06-30 12:21:06 -04:00
{
2018-10-03 16:09:08 -04: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
2018-10-03 16:09:08 -04: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 )
{
2018-10-03 16:09:08 -04:00
VertexInstanceUVs . Set ( VertexInstanceID , TexCoodIdx , StaticMeshLOD . VertexBuffers . StaticMeshVertexBuffer . GetVertexUV ( WedgeIndex , TexCoodIdx ) ) ;
2017-06-30 12:21:06 -04:00
}
}
2018-10-03 16:09:08 -04:00
//Create a polygon from this triangle
2019-01-18 06:37:35 -05:00
const FPolygonID NewPolygonID = OutRawMesh . CreatePolygon ( CurrentPolygonGroupID , VertexInstanceIDs ) ;
2018-10-03 16:09:08 -04: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 ;
}
2018-10-03 16:09:08 -04: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 ) ;
}
}
}
}
2018-10-03 16:09:08 -04:00
TVertexAttributesConstRef < FVector > VertexPositions = InOutRawMesh . VertexAttributes ( ) . GetAttributesRef < FVector > ( MeshAttribute : : Vertex : : Position ) ;
2017-06-30 12:21:06 -04:00
2018-10-03 16:09:08 -04: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
{
2018-10-03 16:09:08 -04:00
const FVector & Position = VertexPositions [ VertexID ] ;
2017-06-30 12:21:06 -04:00
// Start with setting visibility to true on all vertices
2018-10-03 16:09:08 -04: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)
2018-10-03 16:09:08 -04: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
2018-10-03 16:09:08 -04:00
VertexVisible [ VertexID ] = false ;
2017-06-30 12:21:06 -04:00
}
}
Index + + ;
}
// We now know which vertices are below the landscape
2018-10-03 16:09:08 -04:00
TArray < FPolygonID > PolygonToRemove ;
for ( const FPolygonID & PolygonID : InOutRawMesh . Polygons ( ) . GetElementIDs ( ) )
2017-06-30 12:21:06 -04:00
{
bool AboveLandscape = false ;
2018-10-03 16:09:08 -04:00
for ( FMeshTriangle & Triangle : InOutRawMesh . GetPolygonTriangles ( PolygonID ) )
2017-06-30 12:21:06 -04:00
{
2018-10-03 16:09:08 -04: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
}
}
2018-10-03 16:09:08 -04:00
// Delete the polygons that are not visible
2017-06-30 12:21:06 -04:00
{
2018-10-03 16:09:08 -04: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
{
2018-10-03 16:09:08 -04:00
InOutRawMesh . DeletePolygon ( PolygonID , & OrphanedEdges , & OrphanedVertexInstances , & OrphanedPolygonGroups ) ;
2017-06-30 12:21:06 -04:00
}
2018-10-03 16:09:08 -04: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
}
}
2018-10-03 16:09:08 -04:00
void FMeshMergeHelpers : : PropagateSplineDeformationToRawMesh ( const USplineMeshComponent * InSplineMeshComponent , FMeshDescription & OutRawMesh )
2017-06-30 12:21:06 -04:00
{
2018-10-03 16:09:08 -04: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
2018-10-03 16:09:08 -04:00
int32 WedgeIndex = 0 ;
for ( const FPolygonID & PolygonID : OutRawMesh . Polygons ( ) . GetElementIDs ( ) )
2017-06-30 12:21:06 -04:00
{
2018-10-03 16:09:08 -04:00
for ( FMeshTriangle & Triangle : OutRawMesh . GetPolygonTriangles ( PolygonID ) )
2017-06-30 12:21:06 -04:00
{
2018-10-03 16:09:08 -04: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
2018-10-03 16:09:08 -04:00
for ( const FVertexID & VertexID : OutRawMesh . Vertices ( ) . GetElementIDs ( ) )
2017-06-30 12:21:06 -04:00
{
2018-10-03 16:09:08 -04: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 ;
2018-10-03 16:09:08 -04: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 ) ;
}
}
2018-10-03 16:09:08 -04:00
void FMeshMergeHelpers : : TransformRawMeshVertexData ( const FTransform & InTransform , FMeshDescription & OutRawMesh )
2017-06-30 12:21:06 -04:00
{
2018-10-03 16:09:08 -04: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
{
2018-10-03 16:09:08 -04: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
2018-10-03 16:09:08 -04:00
for ( const FVertexInstanceID & VertexInstanceID : OutRawMesh . VertexInstances ( ) . GetElementIDs ( ) )
2017-06-30 12:21:06 -04:00
{
2018-10-03 16:09:08 -04: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 ) ;
2018-10-03 16:09:08 -04: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 )
{
2018-10-03 16:09:08 -04:00
//Reverse the vertexinstance
OutRawMesh . ReverseAllPolygonFacing ( ) ;
2017-06-30 12:21:06 -04:00
}
}
2018-10-03 16:09:08 -04: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-29 16:15:19 -05:00
FMeshDescription * MeshDescription = new FMeshDescription ( ) ;
UStaticMesh : : RegisterMeshAttributes ( * MeshDescription ) ;
2017-06-30 12:21:06 -04:00
FBoxSphereBounds LandscapeBounds = EstimatedMeshProxyBounds ;
2019-01-29 16:15:19 -05:00
Landscape - > ExportToRawMesh ( LandscapeExportLOD , * MeshDescription , LandscapeBounds ) ;
if ( MeshDescription - > Vertices ( ) . Num ( ) )
2017-06-30 12:21:06 -04:00
{
2019-01-29 16:15:19 -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
2018-10-03 16:09:08 -04: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 ( ) ;
2018-10-03 16:09:08 -04: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
{
2018-10-03 16:09:08 -04:00
VertexPositions [ VertexID ] + = VolumeLocation ;
2017-06-30 12:21:06 -04:00
}
CullingRawMeshes . Add ( VolumeMesh ) ;
}
}
2018-07-31 02:23:26 -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 02:23:26 -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 02:23:26 -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 02:23:26 -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 ;
}
2018-10-03 16:09:08 -04:00
void FMeshMergeHelpers : : CalculateTextureCoordinateBoundsForRawMesh ( const FMeshDescription & InRawMesh , TArray < FBox2D > & OutBounds )
2017-06-30 12:21:06 -04:00
{
2018-10-03 16:09:08 -04:00
TVertexInstanceAttributesConstRef < FVector2D > VertexInstanceUVs = InRawMesh . VertexInstanceAttributes ( ) . GetAttributesRef < FVector2D > ( MeshAttribute : : VertexInstance : : TextureCoordinate ) ;
2017-06-30 12:21:06 -04:00
OutBounds . Empty ( ) ;
2018-10-03 16:09:08 -04:00
for ( const FPolygonID & PolygonID : InRawMesh . Polygons ( ) . GetElementIDs ( ) )
2017-06-30 12:21:06 -04:00
{
2018-10-03 16:09:08 -04:00
int32 MaterialIndex = InRawMesh . GetPolygonPolygonGroup ( PolygonID ) . GetValue ( ) ;
2017-06-30 12:21:06 -04:00
if ( OutBounds . Num ( ) < = MaterialIndex )
OutBounds . SetNumZeroed ( MaterialIndex + 1 ) ;
{
2018-10-03 16:09:08 -04:00
TArray < FVertexInstanceID > PolygonVertexInstances = InRawMesh . GetPolygonPerimeterVertexInstances ( PolygonID ) ;
for ( const FVertexInstanceID & VertexInstanceID : PolygonVertexInstances )
2017-06-30 12:21:06 -04:00
{
2018-10-03 16:09:08 -04:00
for ( int32 UVIndex = 0 ; UVIndex < VertexInstanceUVs . GetNumIndices ( ) ; + + UVIndex )
2017-06-30 12:21:06 -04:00
{
2018-10-03 16:09:08 -04:00
OutBounds [ MaterialIndex ] + = VertexInstanceUVs . Get ( VertexInstanceID , UVIndex ) ;
2017-06-30 12:21:06 -04:00
}
}
}
}
}
2018-10-03 16:09:08 -04: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
{
2018-10-03 16:09:08 -04: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 ;
2018-10-03 16:09:08 -04: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
{
2018-10-03 16:09:08 -04: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
{
2018-10-03 16:09:08 -04: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 ) ;
}
2018-10-03 16:09:08 -04: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)
2018-10-03 16:09:08 -04:00
// Use index buffer directly. Not sure this will happen with FMeshDescription
2017-06-30 12:21:06 -04:00
else
{
2018-10-03 16:09:08 -04:00
if ( RawMesh . Vertices ( ) . Num ( ) = = ColorVertexBuffer . GetNumVertices ( ) )
2017-06-30 12:21:06 -04:00
{
2018-10-03 16:09:08 -04: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 ;
2018-10-03 16:09:08 -04:00
uint32 VertIndex = VertexIDToVertexIndex [ VertexID ] ;
2017-06-30 12:21:06 -04:00
if ( VertIndex < ColorVertexBuffer . GetNumVertices ( ) )
{
WedgeColor = ColorVertexBuffer . VertexColor ( VertIndex ) ;
}
2018-10-03 16:09:08 -04: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
2018-10-03 16:09:08 -04:00
void FMeshMergeHelpers : : AppendRawMesh ( FMeshDescription & InTarget , const FMeshDescription & InSource )
2018-03-06 13:26:20 -05:00
{
2018-10-03 16:09:08 -04: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
{
2018-10-03 16:09:08 -04:00
if ( ! InTarget . IsPolygonGroupValid ( SourcePolygonGroupID ) )
2018-03-06 13:26:20 -05:00
{
2018-10-03 16:09:08 -04:00
InTarget . CreatePolygonGroupWithID ( SourcePolygonGroupID ) ;
TargetPolygonGroupImportedMaterialSlotNames [ SourcePolygonGroupID ] = SourcePolygonGroupImportedMaterialSlotNames [ SourcePolygonGroupID ] ;
2018-03-06 13:26:20 -05:00
}
}
2018-10-03 16:09:08 -04: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
{
2018-10-03 16:09:08 -04:00
const FVertexID TargetVertexID = InTarget . CreateVertex ( ) ;
SourceToTargetVertexID . Add ( SourceVertexID , TargetVertexID ) ;
2018-03-06 13:26:20 -05:00
}
2018-10-03 16:09:08 -04:00
//Append VertexInstances
if ( SourceVertexInstanceUVs . GetNumIndices ( ) > TargetVertexInstanceUVs . GetNumIndices ( ) )
2018-03-06 13:26:20 -05:00
{
2018-10-03 16:09:08 -04:00
TargetVertexInstanceUVs . SetNumIndices ( SourceVertexInstanceUVs . GetNumIndices ( ) ) ;
2018-03-06 13:26:20 -05:00
}
2018-10-03 16:09:08 -04: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
{
2018-10-03 16:09:08 -04: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
{
2018-10-03 16:09:08 -04: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
}
2018-10-03 16:09:08 -04:00
SourceToTargetVertexInstanceID . Add ( SourceVertexInstanceID , TargetVertexInstanceID ) ;
2018-03-06 13:26:20 -05:00
}
2018-10-03 16:09:08 -04: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-18 06:37:35 -05:00
auto CreateContour = [ & InSource , & SourceToTargetVertexInstanceID , & SourceToTargetEdgeID ] ( const TArray < FVertexInstanceID > & SourceVertexInstanceIDs , TArray < FVertexInstanceID > & DestVertexInstanceIDs )
2018-10-03 16:09:08 -04:00
{
const int32 ContourCount = SourceVertexInstanceIDs . Num ( ) ;
for ( int32 ContourIndex = 0 ; ContourIndex < ContourCount ; + + ContourIndex )
{
FVertexInstanceID SourceVertexInstanceID = SourceVertexInstanceIDs [ ContourIndex ] ;
2019-01-18 06:37:35 -05:00
DestVertexInstanceIDs . Add ( SourceToTargetVertexInstanceID [ SourceVertexInstanceID ] ) ;
2018-10-03 16:09:08 -04: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-18 06:37:35 -05:00
TArray < FVertexInstanceID > ContourVertexInstances ;
CreateContour ( SourceVertexInstanceIDs , ContourVertexInstances ) ;
2018-10-03 16:09:08 -04:00
// Insert a polygon into the mesh
2019-01-18 06:37:35 -05:00
const FPolygonID TargetPolygonID = InTarget . CreatePolygon ( SourcePolygon . PolygonGroupID , ContourVertexInstances ) ;
2018-10-03 16:09:08 -04:00
//Triangulate the polygon
FMeshPolygon & Polygon = InTarget . GetPolygon ( TargetPolygonID ) ;
InTarget . ComputePolygonTriangulation ( TargetPolygonID , Polygon . Triangles ) ;
}
2018-03-06 13:26:20 -05:00
}
2018-10-03 16:09:08 -04: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))
{
for ( const UStaticMeshComponent * Component : ImposterComponents )
{
// Retrieve imposter LOD mesh and material
const int32 LODIndex = Component - > GetStaticMesh ( ) - > GetNumLODs ( ) - 1 ;
2018-10-03 16:09:08 -04:00
// Retrieve mesh data in FMeshDescription form
FMeshDescription ImposterMesh ;
2019-03-27 15:03:08 -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 ) ;
for ( FSectionInfo & Info : Sections )
{
2018-10-03 16:09:08 -04:00
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 ;
2018-10-03 16:09:08 -04: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 ;
2018-10-03 16:09:08 -04:00
for ( const FVertexInstanceID & VertexInstanceID : ImposterMesh . VertexInstances ( ) . GetElementIDs ( ) )
2018-03-06 13:26:20 -05:00
{
2018-10-03 16:09:08 -04:00
FVector2D UVOne ;
FVector2D UVTwo ;
2018-03-06 13:26:20 -05:00
UVOne . X = ActorPosition . X ;
UVOne . Y = ActorPosition . Y ;
2018-10-03 16:09:08 -04:00
VertexInstanceUVs . Set ( VertexInstanceID , UVOneIndex , UVOne ) ;
2018-03-06 13:26:20 -05:00
UVTwo . X = ActorPosition . Z ;
UVTwo . Y = ActorToWorld . GetScale3D ( ) . X ;
2018-10-03 16:09:08 -04:00
VertexInstanceUVs . Set ( VertexInstanceID , UVTwoIndex , UVTwo ) ;
2018-03-06 13:26:20 -05:00
}
FMeshMergeHelpers : : AppendRawMesh ( InRawMesh , ImposterMesh ) ;
}
}
2018-09-19 11:42:22 -04:00
}