Files
UnrealEngineUWP/Engine/Source/Developer/MeshBuilder/Private/MeshDescriptionHelper.cpp

162 lines
7.1 KiB
C++
Raw Normal View History

// Copyright 1998-2019 Epic Games, Inc. All Rights Reserved.
#include "MeshDescriptionHelper.h"
#include "CoreMinimal.h"
#include "CoreTypes.h"
#include "UObject/UObjectGlobals.h"
#include "UObject/Package.h"
#include "Engine/EngineTypes.h"
#include "Engine/StaticMesh.h"
#include "MeshDescription.h"
Total revamp of mesh element attribute model. Attributes now have a number of possible types (FVector, FVector4, FVector2D, float, int, bool, FName, UObject*) and are exposed as individual flat arrays, indexed by element ID. For example, vertex positions are essentially exposed as an array of FVector which can be directly accessed and modified. This has a number of advantages: - It is completely extensible: new attributes can be created (even by a third party) and added to a mesh description without requiring a serialization version bump, or any change to the parent structures. - This is more efficient in batch operations which deal with a number of mesh elements in one go. - These attribute buffers can potentially be passed directly to third-party libraries without requiring any kind of transformation. - The distinct types allow for a better representation of the attribute being specified, without invalid values being possible (cf representing a bool value in an FVector4). Attributes also have default values, and a flags field which confers use-specific properties to them. Editable Mesh currently uses this to determine whether an attribute's value can be automatically initialized by lerping the values of its neighbours, as well as for identifying auto-generated attributes such as tangents/normals. This is desirable as it means that even unknown / third-party attributes can potentially be handled transparently by Editable Mesh, without requiring the code to be extended. Certain higher-level operations in EditableMesh have been optimized to make full use of vertex instances where possible. The welding/splitting of identical vertex instances has been removed from here, as the aim is to unify this with mesh utility code elsewhere. Various bug fixes. #rb Alexis.Matte [CL 3794563 by Richard TalbotWatkin in Dev-Geometry branch]
2017-12-07 13:02:12 -05:00
#include "MeshAttributes.h"
#include "Serialization/MemoryWriter.h"
#include "Serialization/MemoryReader.h"
#include "RenderUtils.h"
#include "IMeshReductionInterfaces.h"
#include "IMeshReductionManagerModule.h"
#include "Materials/Material.h"
#include "RawMesh.h"
#include "BuildStatisticManager.h"
#include "MeshDescriptionOperations.h"
#include "Modules/ModuleManager.h"
//Enable all check
//#define ENABLE_NTB_CHECK
DEFINE_LOG_CATEGORY(LogMeshDescriptionBuildStatistic);
FMeshDescriptionHelper::FMeshDescriptionHelper(FMeshBuildSettings* InBuildSettings)
: BuildSettings(InBuildSettings)
{
}
void FMeshDescriptionHelper::GetRenderMeshDescription(UObject* Owner, const FMeshDescription& InOriginalMeshDescription, FMeshDescription& OutRenderMeshDescription)
{
UStaticMesh* StaticMesh = Cast<UStaticMesh>(Owner);
check(StaticMesh);
//Copy the Original Mesh Description in the render mesh description
OutRenderMeshDescription = InOriginalMeshDescription;
float ComparisonThreshold = BuildSettings->bRemoveDegenerates ? THRESH_POINTS_ARE_SAME : 0.0f;
//This function make sure the Polygon NTB are compute and also remove degenerated triangle from the render mesh description.
FMeshDescriptionOperations::CreatePolygonNTB(OutRenderMeshDescription, ComparisonThreshold);
//OutRenderMeshDescription->ComputePolygonTangentsAndNormals(BuildSettings->bRemoveDegenerates ? SMALL_NUMBER : 0.0f);
FVertexInstanceArray& VertexInstanceArray = OutRenderMeshDescription.VertexInstances();
New attribute array API. Fixed some flaws in the original API, deprecated various methods, and introduced some new features. - Now attribute arrays are accessed via TAttributesRef or TAttributesView (and corresponding const versions). These value types hold references to attribute arrays, and individual elements can be accessed by their element ID and attribute index. Using a value type is safer than the previous method which required assignment to a const-ref (and not doing so would take a temporary copy of the attribute array). - The attribute set has been totally flattened, so all attributes of different types are added to the same container. This greatly improves compile times, prevents attributes from being created with the same name but different types, and permits the view feature. - The class hierarchy has changed to have generic base classes where possible with no particular ElementID type. This reduces the code footprint by no longer generating nearly identical copies of templated methods. - A TAttributesView allows the user to access an attribute array by the type of their choosing, regardless of its actual type. For example, the Normal attribute may be registered with type FPackedVector, but accessed as if it was an FVector. This allows us to move away from very strong typing, and instead transparently store attributes of a more efficient size, while the user is not affected. - A transient attribute flag has been added, to denote that a particular attribute should not be saved. #rb none [CL 4226081 by Richard TalbotWatkin in Dev-Editor branch]
2018-07-20 18:58:37 -04:00
TVertexInstanceAttributesRef<FVector> Normals = OutRenderMeshDescription.VertexInstanceAttributes().GetAttributesRef<FVector>( MeshAttribute::VertexInstance::Normal );
TVertexInstanceAttributesRef<FVector> Tangents = OutRenderMeshDescription.VertexInstanceAttributes().GetAttributesRef<FVector>( MeshAttribute::VertexInstance::Tangent );
TVertexInstanceAttributesRef<float> BinormalSigns = OutRenderMeshDescription.VertexInstanceAttributes().GetAttributesRef<float>( MeshAttribute::VertexInstance::BinormalSign );
// Find overlapping corners to accelerate adjacency.
FMeshDescriptionOperations::FindOverlappingCorners(OverlappingCorners, OutRenderMeshDescription, ComparisonThreshold);
// Compute any missing normals or tangents.
{
// Static meshes always blend normals of overlapping corners.
uint32 TangentOptions = FMeshDescriptionOperations::ETangentOptions::BlendOverlappingNormals;
if (BuildSettings->bRemoveDegenerates)
{
// If removing degenerate triangles, ignore them when computing tangents.
TangentOptions |= FMeshDescriptionOperations::ETangentOptions::IgnoreDegenerateTriangles;
}
//Keep the original mesh description NTBs if we do not rebuild the normals or tangents.
bool bComputeTangentLegacy = !BuildSettings->bUseMikkTSpace && (BuildSettings->bRecomputeNormals || BuildSettings->bRecomputeTangents);
bool bHasAllNormals = true;
bool bHasAllTangents = true;
Total revamp of mesh element attribute model. Attributes now have a number of possible types (FVector, FVector4, FVector2D, float, int, bool, FName, UObject*) and are exposed as individual flat arrays, indexed by element ID. For example, vertex positions are essentially exposed as an array of FVector which can be directly accessed and modified. This has a number of advantages: - It is completely extensible: new attributes can be created (even by a third party) and added to a mesh description without requiring a serialization version bump, or any change to the parent structures. - This is more efficient in batch operations which deal with a number of mesh elements in one go. - These attribute buffers can potentially be passed directly to third-party libraries without requiring any kind of transformation. - The distinct types allow for a better representation of the attribute being specified, without invalid values being possible (cf representing a bool value in an FVector4). Attributes also have default values, and a flags field which confers use-specific properties to them. Editable Mesh currently uses this to determine whether an attribute's value can be automatically initialized by lerping the values of its neighbours, as well as for identifying auto-generated attributes such as tangents/normals. This is desirable as it means that even unknown / third-party attributes can potentially be handled transparently by Editable Mesh, without requiring the code to be extended. Certain higher-level operations in EditableMesh have been optimized to make full use of vertex instances where possible. The welding/splitting of identical vertex instances has been removed from here, as the aim is to unify this with mesh utility code elsewhere. Various bug fixes. #rb Alexis.Matte [CL 3794563 by Richard TalbotWatkin in Dev-Geometry branch]
2017-12-07 13:02:12 -05:00
for (const FVertexInstanceID VertexInstanceID : VertexInstanceArray.GetElementIDs())
{
// Dump normals and tangents if we are recomputing them.
if (BuildSettings->bRecomputeTangents)
{
//Dump the tangents
Total revamp of mesh element attribute model. Attributes now have a number of possible types (FVector, FVector4, FVector2D, float, int, bool, FName, UObject*) and are exposed as individual flat arrays, indexed by element ID. For example, vertex positions are essentially exposed as an array of FVector which can be directly accessed and modified. This has a number of advantages: - It is completely extensible: new attributes can be created (even by a third party) and added to a mesh description without requiring a serialization version bump, or any change to the parent structures. - This is more efficient in batch operations which deal with a number of mesh elements in one go. - These attribute buffers can potentially be passed directly to third-party libraries without requiring any kind of transformation. - The distinct types allow for a better representation of the attribute being specified, without invalid values being possible (cf representing a bool value in an FVector4). Attributes also have default values, and a flags field which confers use-specific properties to them. Editable Mesh currently uses this to determine whether an attribute's value can be automatically initialized by lerping the values of its neighbours, as well as for identifying auto-generated attributes such as tangents/normals. This is desirable as it means that even unknown / third-party attributes can potentially be handled transparently by Editable Mesh, without requiring the code to be extended. Certain higher-level operations in EditableMesh have been optimized to make full use of vertex instances where possible. The welding/splitting of identical vertex instances has been removed from here, as the aim is to unify this with mesh utility code elsewhere. Various bug fixes. #rb Alexis.Matte [CL 3794563 by Richard TalbotWatkin in Dev-Geometry branch]
2017-12-07 13:02:12 -05:00
BinormalSigns[VertexInstanceID] = 0.0f;
Tangents[VertexInstanceID] = FVector(0.0f);
}
if (BuildSettings->bRecomputeNormals)
{
//Dump the normals
Total revamp of mesh element attribute model. Attributes now have a number of possible types (FVector, FVector4, FVector2D, float, int, bool, FName, UObject*) and are exposed as individual flat arrays, indexed by element ID. For example, vertex positions are essentially exposed as an array of FVector which can be directly accessed and modified. This has a number of advantages: - It is completely extensible: new attributes can be created (even by a third party) and added to a mesh description without requiring a serialization version bump, or any change to the parent structures. - This is more efficient in batch operations which deal with a number of mesh elements in one go. - These attribute buffers can potentially be passed directly to third-party libraries without requiring any kind of transformation. - The distinct types allow for a better representation of the attribute being specified, without invalid values being possible (cf representing a bool value in an FVector4). Attributes also have default values, and a flags field which confers use-specific properties to them. Editable Mesh currently uses this to determine whether an attribute's value can be automatically initialized by lerping the values of its neighbours, as well as for identifying auto-generated attributes such as tangents/normals. This is desirable as it means that even unknown / third-party attributes can potentially be handled transparently by Editable Mesh, without requiring the code to be extended. Certain higher-level operations in EditableMesh have been optimized to make full use of vertex instances where possible. The welding/splitting of identical vertex instances has been removed from here, as the aim is to unify this with mesh utility code elsewhere. Various bug fixes. #rb Alexis.Matte [CL 3794563 by Richard TalbotWatkin in Dev-Geometry branch]
2017-12-07 13:02:12 -05:00
Normals[VertexInstanceID] = FVector(0.0f);
}
Total revamp of mesh element attribute model. Attributes now have a number of possible types (FVector, FVector4, FVector2D, float, int, bool, FName, UObject*) and are exposed as individual flat arrays, indexed by element ID. For example, vertex positions are essentially exposed as an array of FVector which can be directly accessed and modified. This has a number of advantages: - It is completely extensible: new attributes can be created (even by a third party) and added to a mesh description without requiring a serialization version bump, or any change to the parent structures. - This is more efficient in batch operations which deal with a number of mesh elements in one go. - These attribute buffers can potentially be passed directly to third-party libraries without requiring any kind of transformation. - The distinct types allow for a better representation of the attribute being specified, without invalid values being possible (cf representing a bool value in an FVector4). Attributes also have default values, and a flags field which confers use-specific properties to them. Editable Mesh currently uses this to determine whether an attribute's value can be automatically initialized by lerping the values of its neighbours, as well as for identifying auto-generated attributes such as tangents/normals. This is desirable as it means that even unknown / third-party attributes can potentially be handled transparently by Editable Mesh, without requiring the code to be extended. Certain higher-level operations in EditableMesh have been optimized to make full use of vertex instances where possible. The welding/splitting of identical vertex instances has been removed from here, as the aim is to unify this with mesh utility code elsewhere. Various bug fixes. #rb Alexis.Matte [CL 3794563 by Richard TalbotWatkin in Dev-Geometry branch]
2017-12-07 13:02:12 -05:00
bHasAllNormals &= !Normals[VertexInstanceID].IsNearlyZero();
bHasAllTangents &= !Tangents[VertexInstanceID].IsNearlyZero();
}
//MikkTSpace should be use only when the user want to recompute the normals or tangents otherwise should always fallback on builtin
//We cannot use mikkt space with degenerated normals fallback on buitin.
if (BuildSettings->bUseMikkTSpace && (BuildSettings->bRecomputeNormals || BuildSettings->bRecomputeTangents))
{
if (!bHasAllNormals)
{
FMeshDescriptionOperations::CreateNormals(OutRenderMeshDescription, (FMeshDescriptionOperations::ETangentOptions)TangentOptions, false);
//EComputeNTBsOptions ComputeNTBsOptions = EComputeNTBsOptions::Normals;
//OutRenderMeshDescription.ComputeTangentsAndNormals(ComputeNTBsOptions);
}
FMeshDescriptionOperations::CreateMikktTangents(OutRenderMeshDescription, (FMeshDescriptionOperations::ETangentOptions)TangentOptions);
}
else
{
FMeshDescriptionOperations::CreateNormals(OutRenderMeshDescription, (FMeshDescriptionOperations::ETangentOptions)TangentOptions, true);
//EComputeNTBsOptions ComputeNTBsOptions = (bHasAllNormals ? EComputeNTBsOptions::None : EComputeNTBsOptions::Normals) | (bHasAllTangents ? EComputeNTBsOptions::None : EComputeNTBsOptions::Tangents);
//OutRenderMeshDescription.ComputeTangentsAndNormals(ComputeNTBsOptions);
}
}
if (BuildSettings->bGenerateLightmapUVs && VertexInstanceArray.Num() > 0)
{
New attribute array API. Fixed some flaws in the original API, deprecated various methods, and introduced some new features. - Now attribute arrays are accessed via TAttributesRef or TAttributesView (and corresponding const versions). These value types hold references to attribute arrays, and individual elements can be accessed by their element ID and attribute index. Using a value type is safer than the previous method which required assignment to a const-ref (and not doing so would take a temporary copy of the attribute array). - The attribute set has been totally flattened, so all attributes of different types are added to the same container. This greatly improves compile times, prevents attributes from being created with the same name but different types, and permits the view feature. - The class hierarchy has changed to have generic base classes where possible with no particular ElementID type. This reduces the code footprint by no longer generating nearly identical copies of templated methods. - A TAttributesView allows the user to access an attribute array by the type of their choosing, regardless of its actual type. For example, the Normal attribute may be registered with type FPackedVector, but accessed as if it was an FVector. This allows us to move away from very strong typing, and instead transparently store attributes of a more efficient size, while the user is not affected. - A transient attribute flag has been added, to denote that a particular attribute should not be saved. #rb none [CL 4226081 by Richard TalbotWatkin in Dev-Editor branch]
2018-07-20 18:58:37 -04:00
TVertexInstanceAttributesRef<FVector2D> VertexInstanceUVs = OutRenderMeshDescription.VertexInstanceAttributes().GetAttributesRef<FVector2D>(MeshAttribute::VertexInstance::TextureCoordinate);
int32 NumIndices = VertexInstanceUVs.GetNumIndices();
//Verify the src light map channel
if (BuildSettings->SrcLightmapIndex >= NumIndices)
{
BuildSettings->SrcLightmapIndex = 0;
}
//Verify the destination light map channel
if (BuildSettings->DstLightmapIndex >= NumIndices)
{
//Make sure we do not add illegal UV Channel index
if (BuildSettings->DstLightmapIndex >= MAX_MESH_TEXTURE_COORDS_MD)
{
BuildSettings->DstLightmapIndex = MAX_MESH_TEXTURE_COORDS_MD - 1;
}
//Add some unused UVChannel to the mesh description for the lightmapUVs
VertexInstanceUVs.SetNumIndices(BuildSettings->DstLightmapIndex + 1);
BuildSettings->DstLightmapIndex = NumIndices;
}
FMeshDescriptionOperations::CreateLightMapUVLayout(OutRenderMeshDescription,
BuildSettings->SrcLightmapIndex,
BuildSettings->DstLightmapIndex,
BuildSettings->MinLightmapResolution,
(ELightmapUVVersion)(StaticMesh->LightmapUVVersion),
OverlappingCorners);
}
}
void FMeshDescriptionHelper::ReduceLOD(const FMeshDescription& BaseMesh, FMeshDescription& DestMesh, const FMeshReductionSettings& ReductionSettings, const FOverlappingCorners& InOverlappingCorners, float &OutMaxDeviation)
{
IMeshReductionManagerModule& MeshReductionModule = FModuleManager::Get().LoadModuleChecked<IMeshReductionManagerModule>("MeshReductionInterface");
IMeshReduction* MeshReduction = MeshReductionModule.GetStaticMeshReductionInterface();
if (!MeshReduction)
{
// no reduction possible
OutMaxDeviation = 0.f;
return;
}
OutMaxDeviation = ReductionSettings.MaxDeviation;
MeshReduction->ReduceMeshDescription(DestMesh, OutMaxDeviation, BaseMesh, InOverlappingCorners, ReductionSettings);
}
void FMeshDescriptionHelper::FindOverlappingCorners(const FMeshDescription& MeshDescription, float ComparisonThreshold)
{
FMeshDescriptionOperations::FindOverlappingCorners(OverlappingCorners, MeshDescription, ComparisonThreshold);
}