wip(assembler): M2 round 3 -- opt-in hybrid sharp mesher (WorldAssemblerHybridV1) in the Unreal Core route
Default MarchingCubesV1 unchanged (W1/W8/W16 = round-6 hashes). Hybrid DC only in LOD0 interior cells with tagged features; tile-border cells and LOD1+ stay MC. BuildHost: fixtures repeat exactly, cooked collision bounds = render bounds, same-LOD borders pass, sampled SurfaceWorld cliff bit-identical to MC. Open: tagged tiles cost 5.7-6.7x MC; corner-top field contact error 20 cm; 5 MC doorway LOD cases. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01MmSoF64BbRFmk9C3p1VsBJ
This commit is contained in:
1 parent
a3b7d2015e
commit
22a6b30494
21 files changed
+3009
-23
No files matched your search
@@ -2,6 +2,7 @@
|
||||
// Implémentation du marching cubes density-only.
|
||||
|
||||
#include "VoxelMarchingCubesMesher.h"
|
||||
#include "VoxelHybridSharpMesher.h"
|
||||
#include "MarchingCubesTables.h"
|
||||
#include "StandaloneShapeWorld.h"
|
||||
#include "VoxelDensityProfile.h"
|
||||
@@ -164,6 +165,8 @@ FVoxelMeshData UVoxelMarchingCubesMesher::GenerateMesh(FIntVector OriginVoxels,
|
||||
// plus de (ré)allocation de hash-map par tuile (chaque worker a son propre exemplaire).
|
||||
static thread_local TMap<FIntVector, int32> VertexMap;
|
||||
VertexMap.Reset();
|
||||
static thread_local TMap<FIntVector, TMap<uint64, int32>> SplitNormalVertexMap;
|
||||
SplitNormalVertexMap.Reset();
|
||||
const int32 VertexCapacityHint=FMath::Clamp(InCellsPerAxis,2,CHUNK_SIZE);
|
||||
VertexMap.Reserve(VertexCapacityHint*VertexCapacityHint*2);
|
||||
|
||||
@@ -230,7 +233,8 @@ FVoxelMeshData UVoxelMarchingCubesMesher::GenerateMesh(FIntVector OriginVoxels,
|
||||
};
|
||||
|
||||
// Normale fournie par l'appelant (gradient lu dans la grille de densité, T1.b).
|
||||
auto GetOrCreateVertex = [&](const FVector& WorldPos, const FVector& RawNormal) -> int32
|
||||
auto GetOrCreateVertex = [&](const FVector& WorldPos, const FVector& RawNormal,
|
||||
uint64 NormalSplitKey = 0) -> int32
|
||||
{
|
||||
const FIntVector Key(
|
||||
FMath::RoundToInt(WorldPos.X * 100.0f),
|
||||
@@ -238,13 +242,27 @@ FVoxelMeshData UVoxelMarchingCubesMesher::GenerateMesh(FIntVector OriginVoxels,
|
||||
FMath::RoundToInt(WorldPos.Z * 100.0f)
|
||||
);
|
||||
|
||||
if (int32* Existing = VertexMap.Find(Key))
|
||||
if (NormalSplitKey != 0)
|
||||
{
|
||||
if (TMap<uint64, int32>* SplitMap = SplitNormalVertexMap.Find(Key))
|
||||
{
|
||||
if (int32* Existing = SplitMap->Find(NormalSplitKey)) return *Existing;
|
||||
}
|
||||
}
|
||||
else if (int32* Existing = VertexMap.Find(Key))
|
||||
{
|
||||
return *Existing;
|
||||
}
|
||||
|
||||
const int32 NewIndex = MeshData.Vertices.Num();
|
||||
VertexMap.Add(Key, NewIndex);
|
||||
if (NormalSplitKey != 0)
|
||||
{
|
||||
SplitNormalVertexMap.FindOrAdd(Key).Add(NormalSplitKey, NewIndex);
|
||||
}
|
||||
else
|
||||
{
|
||||
VertexMap.Add(Key, NewIndex);
|
||||
}
|
||||
|
||||
MeshData.Vertices.Add(WorldPos);
|
||||
|
||||
@@ -1349,6 +1367,20 @@ FVoxelMeshData UVoxelMarchingCubesMesher::GenerateMesh(FIntVector OriginVoxels,
|
||||
SampleGradientG(gx, gy, gz + 1) - SampleGradientG(gx, gy, gz - 1));
|
||||
};
|
||||
|
||||
// DC is limited to tagged LOD0 patches. Coarse tiles and a connected patch that reaches a
|
||||
// tile edge use MC there, preserving the existing MC-to-MC clipmap transition and skirts.
|
||||
// Le DC reste limite aux surfaces LOD0 balisees; les patches connectes au bord restent MC.
|
||||
VoxelHybridSharpMesher::FResult HybridResult;
|
||||
if (bUseHybridSharpMesher && Step == 1 && CellsPerAxis == CHUNK_SIZE
|
||||
&& CzLo == 0 && CzHi == CellsPerAxis - 1 && !HybridSharpFeatures.IsEmpty())
|
||||
{
|
||||
HybridResult = VoxelHybridSharpMesher::Generate(
|
||||
CellsPerAxis, Step, IsoLevel, GeometryVoxelSize, OriginVoxels, ChunkWorldPos,
|
||||
HybridSharpFeatures,
|
||||
[&](int32 X, int32 Y, int32 Z) { return SampleG(X, Y, Z); },
|
||||
[&](int32 X, int32 Y, int32 Z) { return GradAt(X, Y, Z); });
|
||||
}
|
||||
|
||||
//=========================================================================
|
||||
// ITÉRATION SUR LES CELLULES
|
||||
//=========================================================================
|
||||
@@ -1564,6 +1596,10 @@ FVoxelMeshData UVoxelMarchingCubesMesher::GenerateMesh(FIntVector OriginVoxels,
|
||||
const int32 E0 = MCTriTable[CaseIndex][i];
|
||||
const int32 E1 = MCTriTable[CaseIndex][i + 1];
|
||||
const int32 E2 = MCTriTable[CaseIndex][i + 2];
|
||||
if (HybridResult.UsesDCEdge(cx, cy, cz, E0, CellsPerAxis))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
const int32 Idx0 = GetOrCreateVertex(EdgeVertices[E0], EdgeNormals[E0]);
|
||||
const int32 Idx1 = GetOrCreateVertex(EdgeVertices[E1], EdgeNormals[E1]);
|
||||
const int32 Idx2 = GetOrCreateVertex(EdgeVertices[E2], EdgeNormals[E2]);
|
||||
@@ -1591,6 +1627,26 @@ FVoxelMeshData UVoxelMarchingCubesMesher::GenerateMesh(FIntVector OriginVoxels,
|
||||
}
|
||||
}
|
||||
|
||||
// Add DC geometry to the same material runs as MC. Analytic feature IDs split corner normals.
|
||||
// Ajouter la geometrie DC dans les memes groupes que MC; les IDs separent les normales nettes.
|
||||
for (const VoxelHybridSharpMesher::FTriangle& Triangle : HybridResult.Triangles)
|
||||
{
|
||||
const int32 Idx0 = GetOrCreateVertex(
|
||||
Triangle.Positions[0], Triangle.Normals[0], Triangle.SplitKeys[0]);
|
||||
const int32 Idx1 = GetOrCreateVertex(
|
||||
Triangle.Positions[1], Triangle.Normals[1], Triangle.SplitKeys[1]);
|
||||
const int32 Idx2 = GetOrCreateVertex(
|
||||
Triangle.Positions[2], Triangle.Normals[2], Triangle.SplitKeys[2]);
|
||||
const int32 CapVotes = bStandaloneSkipMaterialGroups ? 0
|
||||
: static_cast<int32>(VertexClasses[Idx0])
|
||||
+ static_cast<int32>(VertexClasses[Idx1])
|
||||
+ static_cast<int32>(VertexClasses[Idx2]);
|
||||
TArray<int32>& Dst = (CapVotes >= 2) ? CapTris : GroundTris;
|
||||
Dst.Add(Idx0);
|
||||
Dst.Add(Idx2);
|
||||
Dst.Add(Idx1);
|
||||
}
|
||||
|
||||
if (bProfileMesher)
|
||||
{
|
||||
VoxelDensityProfile::AddMeasurement(
|
||||
|
||||
Reference in new issue
Block a user