Files
UnrealEngine/Engine/Plugins/Editor/ProxyLODPlugin/Source/ProxyLOD/Private/ProxyLODMeshSDFConversions.h
2025-05-18 13:04:45 +08:00

166 lines
6.5 KiB
C++

// Copyright Epic Games, Inc. All Rights Reserved.
#pragma once
#include "ProxyLODMeshTypes.h"
#include "ProxyLODMeshConvertUtils.h"
#include "ProxyLODMeshUtilities.h"
#include "ProxyLODOpenVDB.h"
namespace ProxyLOD
{
/**
* Generate a single sparse Signed Distance Field (SDF) Grid from the polys managed by InMesh,
* Optionally store the index of the closest poly is recorded in a sparse PolyIndexGrid.
*
* @param InMesh Source polygons to be voxelized.
* @param OutSDFGrid Resulting sparse signed distance field.
* @param OutPolyIndexGrid Optional resulting sparse grid. For each voxel with valid distance in the OutSDFGrid
* the index of the closest poly will be recorded in the corresponding voxel
* of the OutPolyIndedGrid.
*
* @retun 'true' is success, 'false' will generally be an out of memory error.
*/
template <typename SrcMeshType>
bool MeshToSDFVolume( const SrcMeshType& InMesh,
const openvdb::math::Transform& InTransform,
openvdb::FloatGrid::Ptr& OutSDFGrid,
openvdb::Int32Grid* OutPolyIndexGrid = nullptr);
/**
* Extract the isosurface (=IsoValue) of the given SDF volume, in the form of triangle mesh.
*
* NB: This produces geometry only, and ignores Tangents, Texture Coordinates and Colors etc.
*
* @param InSDFVolume Sparse signed distance field: voxel based representation of geometry.
* @param IsoValue Indicates the surface defined by this distance value.
* @param AdaptivityValue Internal adaptivity attempts to simplify regions of low curvature.
* Local face normals are compared using this value as a threshold.
* @param OutMesh Resulting triangular mesh that is consistent with the surface defined by the iso-value.
*/
template <typename DstMeshType>
void SDFVolumeToMesh( const openvdb::FloatGrid::ConstPtr InSDFVolume,
const double IsoValue,
const double AdaptivityValue,
DstMeshType& OutMesh);
/**
* Extract the isosurface (=IsoValue) of the given SDF volume, in the form of triangle mesh and adds
* very simple vertex normals.
*
* NB: This produces geometry only, and ignores Tangents, Texture Coordinates and Colors etc.
*
* @param InSDFVolume Sparse signed distance field: voxel based representation of geometry.
* @param IsoValue Indicates the surface defined by this distance value.
* @param AdaptivityValue Internal adaptivity attempts to simplify regions of low curvature.
* Local face normals are compared using this value as a threshold.
* @param OutMesh Resulting triangular mesh that is consistent with the surface defined by the iso-value.
*/
template <typename AOSVertexType>
void ExtractIsosurfaceWithNormals( const openvdb::FloatGrid::ConstPtr InSDFVolume,
const double IsoValue,
const double Adaptivity,
TAOSMesh<AOSVertexType>& OutMesh);
/**
* Updates the InOutSDFVollume to potentially close small holes and gaps in the iso-surface.
*
* This is particularly useful when processing distant buildings (where the doors
* and windows may only be a few voxels in size). In this case, closing the openings
* may result in a water-tight mesh and thus remove interior geometry.
*
* NB: In addition to closing holes, this may merge nearby separate objects.
*
* @param InOutSDFVolume Signed distance field that will be altered
* @param GapRadius 1/2 the length scale of the gap or hole size.
* @param MaxDilations The max allowed number of dilation/erosion pairs,
*
* NB: If the GapRadius is large compared with the voxelsize of the input volume,
* the dilations and erosions will be done with a larger voxelsize (as determined
* by MaxDilations).
*
*/
void CloseGaps(openvdb::FloatGrid::Ptr InOutSDFVolume, const double GapRadius, const int32 MaxDilations);
/**
* Update the InOutSDFVolume by doing a CSG difference with the Clipping volume.
*
* NB: In addition to altering the InOutSDFVolume, this may destroy the clipping volume
*
* @param InOutSDFVolume Signed distance field representing the interesting geometry.
* @param ClippingVolume Signed distance field representing the region to be subtracted from the interesting geometry.
*
*/
void RemoveClipped(openvdb::FloatGrid::Ptr InOutSDFVolume, openvdb::FloatGrid::Ptr ClippingVolume);
}
template <typename SrcMeshType>
bool ProxyLOD::MeshToSDFVolume(const SrcMeshType& InMesh, const openvdb::math::Transform& InTransform, openvdb::FloatGrid::Ptr& SDFGrid, openvdb::Int32Grid* PolyIndexGrid)
{
TRACE_CPUPROFILER_EVENT_SCOPE(ProxyLOD::MeshToSDFVolume)
bool bSuccess = true;
try
{
const float HalfBandWidth = 2.f;
int Flags = 0;
{
TRACE_CPUPROFILER_EVENT_SCOPE(OpenVDB::MeshToVolume)
SDFGrid = openvdb::tools::meshToVolume<openvdb::FloatGrid>(InMesh, InTransform, HalfBandWidth /*exterior*/, HalfBandWidth/*interior*/, Flags, PolyIndexGrid);
}
// reduce memory footprint, increase the sparseness.
{
TRACE_CPUPROFILER_EVENT_SCOPE(OpenVDB::PruneLevelSet)
openvdb::tools::pruneLevelSet(SDFGrid->tree(), HalfBandWidth, -HalfBandWidth);
}
}
catch (std::bad_alloc&)
{
bSuccess = false;
if (SDFGrid)
{
SDFGrid->tree().clear(); // free any memory held in the smart pointers in the grid
}
if (PolyIndexGrid)
{
PolyIndexGrid->clear();
}
}
return bSuccess;
}
template <typename DstMeshType>
void ProxyLOD::SDFVolumeToMesh(const openvdb::FloatGrid::ConstPtr SDFVolume, const double IsoValue, const double Adaptivity, DstMeshType& OutMesh)
{
TRACE_CPUPROFILER_EVENT_SCOPE(ProxyLOD::SDFVolumeToMesh)
// we should be generating a new FMeshDescription.
OutMesh.Empty();
// Temporary Mesh that supports Quads and Triangles
FMixedPolyMesh TempMixedPolyMesh;
// Convert to Quad Mesh - extracting iso-surface defined by IsoValue
openvdb::tools::volumeToMesh(*SDFVolume, TempMixedPolyMesh.Points, TempMixedPolyMesh.Triangles, TempMixedPolyMesh.Quads, IsoValue, Adaptivity);
MixedPolyMeshToAOSMesh(TempMixedPolyMesh, OutMesh);
}
template <typename AOSVertexType>
void ProxyLOD::ExtractIsosurfaceWithNormals(const openvdb::FloatGrid::ConstPtr SDFVolume, const double IsoValue, const double Adaptivity, TAOSMesh<AOSVertexType>& OutMesh)
{
SDFVolumeToMesh(SDFVolume, IsoValue, Adaptivity, OutMesh);
AddNormals(OutMesh);
}