You've already forked UnrealEngineUWP
mirror of
https://github.com/izzy2lost/UnrealEngineUWP.git
synced 2026-03-26 18:15:20 -07:00
ModelingTools: Fix texture filtering into neighboring charts for tightly packed UV shells.
#rb jimmy.andrews michael.balzer #rnx #jira none #preflight 61bbb2868a62de8385c38473 #ROBOMERGE-AUTHOR: lonnie.li #ROBOMERGE-SOURCE: CL 18480102 in //UE5/Release-5.0/... via CL 18481553 #ROBOMERGE-BOT: STARSHIP (Release-Engine-Staging -> Release-Engine-Test) (v899-18417669) [CL 18481825 by lonnie li in ue5-release-engine-test branch]
This commit is contained in:
+56
-13
@@ -5,7 +5,7 @@
|
||||
#include "Sampling/MeshMapBakerQueue.h"
|
||||
#include "Image/ImageOccupancyMap.h"
|
||||
#include "Image/ImageTile.h"
|
||||
#include "Algo/Count.h"
|
||||
#include "Selections/MeshConnectedComponents.h"
|
||||
#include "ProfilingDebugging/ScopedTimers.h"
|
||||
|
||||
using namespace UE::Geometry;
|
||||
@@ -81,6 +81,13 @@ void FMeshMapBaker::InitBake()
|
||||
}
|
||||
|
||||
InitFilter();
|
||||
|
||||
// Compute UV charts if null or invalid.
|
||||
if (!TargetMeshUVCharts || !ensure(TargetMeshUVCharts->Num() == TargetMesh->TriangleCount()))
|
||||
{
|
||||
ComputeUVCharts(*TargetMesh, TargetMeshUVChartsLocal);
|
||||
TargetMeshUVCharts = &TargetMeshUVChartsLocal;
|
||||
}
|
||||
}
|
||||
|
||||
void FMeshMapBaker::InitBakeDefaults()
|
||||
@@ -121,7 +128,7 @@ void FMeshMapBaker::Bake()
|
||||
BakeAnalytics.Reset();
|
||||
FScopedDurationTimer TotalBakeTimer(BakeAnalytics.TotalBakeDuration);
|
||||
|
||||
if (Bakers.IsEmpty())
|
||||
if (Bakers.IsEmpty() || !TargetMesh)
|
||||
{
|
||||
return;
|
||||
}
|
||||
@@ -305,11 +312,17 @@ void FMeshMapBaker::Bake()
|
||||
|
||||
FImageOccupancyMap OccupancyMap;
|
||||
OccupancyMap.GutterSize = GutterSize;
|
||||
OccupancyMap.Initialize(Dimensions, Tile, SamplesPerPixel);
|
||||
OccupancyMap.ComputeFromUVSpaceMesh(FlatMesh, [this](int32 TriangleID) { return FlatMesh.GetTriangleGroup(TriangleID); });
|
||||
OccupancyMap.Initialize(Dimensions, PaddedTile, SamplesPerPixel);
|
||||
OccupancyMap.ComputeFromUVSpaceMesh(FlatMesh, [this](int32 TriangleID) { return FlatMesh.GetTriangleGroup(TriangleID); }, TargetMeshUVCharts);
|
||||
GutterTexelsPerTile[TileIdx] = OccupancyMap.GutterTexels;
|
||||
|
||||
BakeAnalytics.NumSamplePixels += Algo::CountIf(OccupancyMap.TexelInteriorSamples, [](const int32 Value){ return Value > 0; });
|
||||
const int64 NumTilePixels = Tile.Num();
|
||||
for (int64 TilePixelIdx = 0; TilePixelIdx < NumTilePixels; ++TilePixelIdx)
|
||||
{
|
||||
const FVector2i SourceCoords = Tile.GetSourceCoords(TilePixelIdx);
|
||||
const int64 OccupancyMapIdx = OccupancyMap.Tile.GetIndexFromSourceCoords(SourceCoords);
|
||||
BakeAnalytics.NumSamplePixels += OccupancyMap.TexelInteriorSamples[OccupancyMapIdx];;
|
||||
}
|
||||
|
||||
FMeshMapTileBuffer* TileBuffer = new FMeshMapTileBuffer(PaddedTile, BakeSampleBufferSize);
|
||||
|
||||
@@ -330,16 +343,16 @@ void FMeshMapBaker::Bake()
|
||||
return;
|
||||
}
|
||||
|
||||
const int64 TilePixelLinearIdx = Tile.GetIndex(TileCoords);
|
||||
if (OccupancyMap.TexelNumSamples(TilePixelLinearIdx) == 0)
|
||||
const FVector2i ImageCoords = Tile.GetSourceCoords(TileCoords);
|
||||
const int64 OccupancyMapLinearIdx = OccupancyMap.Tile.GetIndexFromSourceCoords(ImageCoords);
|
||||
if (OccupancyMap.TexelNumSamples(OccupancyMapLinearIdx) == 0)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
const FVector2i ImageCoords = Tile.GetSourceCoords(TileCoords);
|
||||
for (int32 SampleIdx = 0; SampleIdx < NumSamples; ++SampleIdx)
|
||||
{
|
||||
const int64 LinearIdx = TilePixelLinearIdx * NumSamples + SampleIdx;
|
||||
const int64 LinearIdx = OccupancyMapLinearIdx * NumSamples + SampleIdx;
|
||||
if (OccupancyMap.IsInterior(LinearIdx))
|
||||
{
|
||||
const FVector2d UVPosition = (FVector2d)OccupancyMap.TexelQueryUV[LinearIdx];
|
||||
@@ -349,7 +362,7 @@ void FMeshMapBaker::Bake()
|
||||
DetailCorrespondenceSampler.SampleUV(UVTriangleID, UVPosition, Sample);
|
||||
if (Sample.DetailMesh && DetailSampler->IsTriangle(Sample.DetailMesh, Sample.DetailTriID))
|
||||
{
|
||||
BakeSample(*TileBuffer, Sample, UVPosition, ImageCoords);
|
||||
BakeSample(*TileBuffer, Sample, UVPosition, ImageCoords, OccupancyMap);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -479,7 +492,8 @@ void FMeshMapBaker::BakeSample(
|
||||
FMeshMapTileBuffer& TileBuffer,
|
||||
const FMeshMapEvaluator::FCorrespondenceSample& Sample,
|
||||
const FVector2d& UVPosition,
|
||||
const FVector2i& ImageCoords)
|
||||
const FVector2i& ImageCoords,
|
||||
const FImageOccupancyMap& OccupancyMap)
|
||||
{
|
||||
// Evaluate each baker into stack allocated float buffer
|
||||
float* Buffer = static_cast<float*>(FMemory_Alloca(sizeof(float) * BakeSampleBufferSize));
|
||||
@@ -493,7 +507,10 @@ void FMeshMapBaker::BakeSample(
|
||||
|
||||
const FImageTile& Tile = TileBuffer.GetTile();
|
||||
|
||||
auto AddFn = [this, &ImageCoords, &UVPosition, &Tile, &TileBuffer, Buffer](const TArray<int32>& BakeIds) -> void
|
||||
const int64 OccupancyMapSampleIdx = OccupancyMap.Tile.GetIndexFromSourceCoords(ImageCoords);
|
||||
const int32 SampleUVChart = OccupancyMap.TexelQueryUVChart[OccupancyMapSampleIdx];
|
||||
|
||||
auto AddFn = [this, &ImageCoords, &UVPosition, &Tile, &TileBuffer, Buffer, &OccupancyMap, SampleUVChart](const TArray<int32>& BakeIds) -> void
|
||||
{
|
||||
const FVector2i BoxFilterStart(
|
||||
FMath::Clamp(ImageCoords.X - FilterKernelSize, 0, Dimensions.GetWidth()),
|
||||
@@ -509,6 +526,8 @@ void FMeshMapBaker::BakeSample(
|
||||
{
|
||||
const FVector2i SourceCoords = BoxFilterTile.GetSourceCoords(FilterIdx);
|
||||
const int64 BufferTilePixelLinearIdx = Tile.GetIndexFromSourceCoords(SourceCoords);
|
||||
const int64 OccupancyMapFilterIdx = OccupancyMap.Tile.GetIndexFromSourceCoords(SourceCoords);
|
||||
const int32 BufferTilePixelUVChart = OccupancyMap.TexelQueryUVChart[OccupancyMapFilterIdx];
|
||||
float* PixelBuffer = TileBuffer.GetPixel(BufferTilePixelLinearIdx);
|
||||
float& PixelWeight = TileBuffer.GetPixelWeight(BufferTilePixelLinearIdx);
|
||||
|
||||
@@ -517,7 +536,8 @@ void FMeshMapBaker::BakeSample(
|
||||
TexelDistance.X *= Dimensions.GetWidth();
|
||||
TexelDistance.Y *= Dimensions.GetHeight();
|
||||
|
||||
const float FilterWeight = TextureFilterEval(TexelDistance);
|
||||
float FilterWeight = TextureFilterEval(TexelDistance);
|
||||
FilterWeight *= (SampleUVChart == BufferTilePixelUVChart);
|
||||
PixelWeight += FilterWeight;
|
||||
for (const int32 BakeIdx : BakeIds)
|
||||
{
|
||||
@@ -670,4 +690,27 @@ float FMeshMapBaker::EvaluateFilter(const FVector2d& Dist)
|
||||
}
|
||||
|
||||
|
||||
void FMeshMapBaker::ComputeUVCharts(const FDynamicMesh3& Mesh, TArray<int32>& MeshUVCharts)
|
||||
{
|
||||
MeshUVCharts.SetNumZeroed(Mesh.TriangleCount());
|
||||
if (const FDynamicMeshUVOverlay* UVOverlay = Mesh.Attributes() ? Mesh.Attributes()->PrimaryUV() : nullptr)
|
||||
{
|
||||
FMeshConnectedComponents UVComponents(&Mesh);
|
||||
UVComponents.FindConnectedTriangles();
|
||||
UVComponents.FindConnectedTriangles([UVOverlay](int32 Triangle0, int32 Triangle1) {
|
||||
return UVOverlay ? UVOverlay->AreTrianglesConnected(Triangle0, Triangle1) : false;
|
||||
});
|
||||
const int32 NumComponents = UVComponents.Num();
|
||||
for (int32 ComponentId = 0; ComponentId < NumComponents; ++ComponentId)
|
||||
{
|
||||
const FMeshConnectedComponents::FComponent& UVComp = UVComponents.GetComponent(ComponentId);
|
||||
for (const int32 TriId : UVComp.Indices)
|
||||
{
|
||||
MeshUVCharts[TriId] = ComponentId;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
+46
-1
@@ -77,6 +77,36 @@ public:
|
||||
EBakeFilterType GetFilter() const { return FilterType; }
|
||||
int32 GetTileSize() const { return TileSize; }
|
||||
|
||||
/**
|
||||
* Computes the connected UV triangles and returns an array containing
|
||||
* the mapping from triangle ID to unique UV chart ID. If the mesh
|
||||
* has no UVs, the UVCharts will be initialized to 0.
|
||||
*
|
||||
* @param Mesh the mesh to compute UV charts.
|
||||
* @param MeshUVCharts the triangle ID to UV Chart ID array.
|
||||
*/
|
||||
static void ComputeUVCharts(const FDynamicMesh3& Mesh, TArray<int32>& MeshUVCharts);
|
||||
|
||||
/**
|
||||
* Set an a Triangle ID to UV Chart ID array for TargetMesh.
|
||||
* If this is not set, then the baker will compute it as part of Bake().
|
||||
* Since ComputeUVCharts() is non-trivial, this method is intended
|
||||
* to allow a client to externally cache the result of ComputeUVCharts
|
||||
* to minimize the overhead per bake.
|
||||
*
|
||||
* @param UVChartsIn the TriID to UVChartID map
|
||||
*/
|
||||
void SetTargetMeshUVCharts(TArray<int32>* UVChartsIn)
|
||||
{
|
||||
TargetMeshUVCharts = UVChartsIn;
|
||||
}
|
||||
|
||||
/** @return the Triangle ID to UV Chart ID mapping */
|
||||
const TArray<int32>* GetTargetMeshUVCharts() const
|
||||
{
|
||||
return TargetMeshUVCharts;
|
||||
}
|
||||
|
||||
//
|
||||
// Analytics
|
||||
//
|
||||
@@ -105,7 +135,8 @@ protected:
|
||||
FMeshMapTileBuffer& TileBuffer,
|
||||
const FMeshMapEvaluator::FCorrespondenceSample& Sample,
|
||||
const FVector2d& UVPosition,
|
||||
const FVector2i& ImageCoords);
|
||||
const FVector2i& ImageCoords,
|
||||
const FImageOccupancyMap& OccupancyMap);
|
||||
|
||||
/** Initialize evaluation contexts and precompute data for bake evaluation. */
|
||||
void InitBake();
|
||||
@@ -184,6 +215,20 @@ protected:
|
||||
|
||||
/** Array of bake result images. */
|
||||
TArray<TUniquePtr<TImageBuilder<FVector4f>>> BakeResults;
|
||||
|
||||
/**
|
||||
* Array of TargetMesh triangle ID to UV chart ID mapping.
|
||||
* Can be optionally provided by the client. If not provided,
|
||||
* will be computed as part of the bake.
|
||||
*/
|
||||
TArray<int32>* TargetMeshUVCharts = nullptr;
|
||||
|
||||
/**
|
||||
* Local Array of TargetMesh triangle ID to UV chart ID mapping.
|
||||
* This will be populated only if not provided by the client via
|
||||
* TargetMeshUVCharts.
|
||||
*/
|
||||
TArray<int32> TargetMeshUVChartsLocal;
|
||||
};
|
||||
|
||||
} // end namespace UE::Geometry
|
||||
|
||||
Reference in New Issue
Block a user