wip(assembler): M3 round 3 -- separated islands + Unreal island route (owner build 18:46)
Islands read as separate (91.89% open sky at mid-height), underside cavity closed, rim teeth were capture shading. Island manifest import + BuildHost proof passed on the pre-cache tree; M1 SurfaceWorld and M2 V1/V2 gates passed. Known open: final XY-column cache compiled in the owner build but is unverified; island LOD0 p95 ~155 ms misses the 133 ms sprint deadline (legacy ~43 ms); the island manifest only fits the BuildHost fixture layout (owner's world: Core init fails, empty world) -> round 4 builds plans inside Unreal. 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
4afea7c802
commit
48fa028086
37 files changed
+3788
-107
No files matched your search
@@ -936,6 +936,12 @@ public:
|
||||
// edge interpolation and normals to the existing mesher.
|
||||
float DensityAt(float X,float Y,float Z) const
|
||||
{
|
||||
float IslandDensity=0.0f;
|
||||
if(NativeFloatingIslandDensityAt(X,Y,Z,IslandDensity))
|
||||
{
|
||||
++ThreadClassificationStats().NativeFloatFieldCalls;
|
||||
return ApplyEditBrushes(IslandDensity,X,Y,Z);
|
||||
}
|
||||
float NativeDensity=0.0f;
|
||||
if(NativeSurfaceDensityAt(X,Y,Z,NativeDensity))
|
||||
{
|
||||
@@ -954,6 +960,13 @@ public:
|
||||
|
||||
float DensityAtLattice(int32 X,int32 Y,int32 Z) const
|
||||
{
|
||||
float IslandDensity=0.0f;
|
||||
if(NativeFloatingIslandDensityAt(static_cast<float>(X),static_cast<float>(Y),
|
||||
static_cast<float>(Z),IslandDensity))
|
||||
{
|
||||
++ThreadClassificationStats().NativeLatticeFieldCalls;
|
||||
return ApplyEditBrushes(IslandDensity,X,Y,Z);
|
||||
}
|
||||
float NativeDensity=0.0f;
|
||||
if(NativeSurfaceDensityAt(static_cast<float>(X),static_cast<float>(Y),
|
||||
static_cast<float>(Z),NativeDensity))
|
||||
@@ -975,6 +988,12 @@ public:
|
||||
|
||||
float DensityAtUnclamped(float X,float Y,float Z) const
|
||||
{
|
||||
float IslandDensity=0.0f;
|
||||
if(NativeFloatingIslandDensityAt(X,Y,Z,IslandDensity))
|
||||
{
|
||||
++ThreadClassificationStats().NativeUnclampedFieldCalls;
|
||||
return ApplyEditBrushes(IslandDensity,X,Y,Z);
|
||||
}
|
||||
float NativeDensity=0.0f;
|
||||
if(NativeSurfaceDensityAt(X,Y,Z,NativeDensity))
|
||||
{
|
||||
@@ -1007,11 +1026,18 @@ public:
|
||||
Count=std::clamp(Count,0,8);
|
||||
if(Count==0)return;
|
||||
bool bHasLegacySurfaceSample=false;
|
||||
bool bHasNativeIslandSample=false;
|
||||
for(int32 Lane=0;Lane<Count;++Lane)
|
||||
bHasLegacySurfaceSample|=UsesLegacySurfaceField(
|
||||
static_cast<float>(XStart+Lane*XStep),static_cast<float>(Y),
|
||||
static_cast<float>(Z));
|
||||
if(bHasLegacySurfaceSample)
|
||||
{
|
||||
const float SampleX=static_cast<float>(XStart+Lane*XStep);
|
||||
const float SampleY=static_cast<float>(Y);
|
||||
const float SampleZ=static_cast<float>(Z);
|
||||
bHasLegacySurfaceSample|=UsesLegacySurfaceField(SampleX,SampleY,SampleZ);
|
||||
float IslandDensity=0.0f;
|
||||
bHasNativeIslandSample|=NativeFloatingIslandDensityAt(
|
||||
SampleX,SampleY,SampleZ,IslandDensity);
|
||||
}
|
||||
if(bHasLegacySurfaceSample||bHasNativeIslandSample)
|
||||
{
|
||||
for(int32 Lane=0;Lane<Count;++Lane)
|
||||
OutDensity[Lane]=DensityAtLattice(XStart+Lane*XStep,Y,Z);
|
||||
@@ -1100,6 +1126,9 @@ private:
|
||||
if(OutDetailDisplacement)*OutDetailDisplacement=0.0f;
|
||||
if(OutCaveInfluence)*OutCaveInfluence=0.0f;
|
||||
if(OutFloorInfluence)*OutFloorInfluence=0.0f;
|
||||
float IslandDensity=0.0f;
|
||||
if(NativeFloatingIslandDensityAt(X,Y,Z,IslandDensity))
|
||||
return bApplyEdits?ApplyEditBrushes(IslandDensity,X,Y,Z):IslandDensity;
|
||||
if(UsesLegacySurfaceField(X,Y,Z))
|
||||
{
|
||||
float NativeDensity=0.0f;
|
||||
@@ -1191,17 +1220,22 @@ public:
|
||||
int32 BMin[3]={Origin.X-Pad,Origin.Y-Pad,Origin.Z-Pad};
|
||||
int32 BMax[3]={Origin.X+(Cells+1)*Step,Origin.Y+(Cells+1)*Step,Origin.Z+(Cells+1)*Step};
|
||||
const VoxelForgeCore::WorldAssemblyStratumPlanV1* SurfacePlan=nullptr;
|
||||
bool bSurfaceOverlap=false,bOtherStrateOverlap=false,bBadPlan=false;
|
||||
const VoxelForgeCore::WorldAssemblyFloatingIslandPlanV1* IslandPlan=nullptr;
|
||||
bool bSurfaceOverlap=false,bIslandOverlap=false,bOtherStrateOverlap=false;
|
||||
bool bIslandOtherStrateOverlap=false,bBadPlan=false;
|
||||
if(Owner&&Owner->Manager)
|
||||
{
|
||||
// Keep the delivered SurfaceWorld chunk mapping unchanged.
|
||||
// Conserver le mapping de chunks SurfaceWorld deja livre.
|
||||
const int32 FirstChunk=FMath::FloorToInt(static_cast<float>(BMin[2])
|
||||
/static_cast<float>(CHUNK_SIZE));
|
||||
const int32 LastChunk=FMath::FloorToInt(static_cast<float>(BMax[2])
|
||||
/static_cast<float>(CHUNK_SIZE));
|
||||
for(int32 ChunkZ=FirstChunk;ChunkZ<=LastChunk;++ChunkZ)
|
||||
{
|
||||
if(Owner->Manager->GetGeneratorTypeForChunk(FIntVector(0,0,ChunkZ))
|
||||
==ECaveGeneratorType::SurfaceWorld)
|
||||
const ECaveGeneratorType Type=Owner->Manager->GetGeneratorTypeForChunk(
|
||||
FIntVector(0,0,ChunkZ));
|
||||
if(Type==ECaveGeneratorType::SurfaceWorld)
|
||||
{
|
||||
bSurfaceOverlap=true;
|
||||
const int32 StrateIndex=Owner->Manager->GetStrateIndex(
|
||||
@@ -1211,12 +1245,39 @@ public:
|
||||
bBadPlan=true;
|
||||
SurfacePlan=Candidate;
|
||||
}
|
||||
else bOtherStrateOverlap=true;
|
||||
else if(Type!=ECaveGeneratorType::FloatingIslands)
|
||||
bOtherStrateOverlap=true;
|
||||
}
|
||||
|
||||
// Floating islands use the explicit 12.5 cm owner to 25 cm Core mapping:
|
||||
// one legacy 4 m chunk occupies 16 Core voxels.
|
||||
// Les iles flottantes suivent l'echelle explicite proprietaire/Core: 16 voxels Core.
|
||||
constexpr int32 CoreVoxelsPerIslandChunk=CHUNK_SIZE/2;
|
||||
const int32 FirstIslandChunk=FMath::FloorToInt(static_cast<float>(BMin[2])
|
||||
/static_cast<float>(CoreVoxelsPerIslandChunk));
|
||||
const int32 LastIslandChunk=FMath::FloorToInt(static_cast<float>(BMax[2])
|
||||
/static_cast<float>(CoreVoxelsPerIslandChunk));
|
||||
for(int32 ChunkZ=FirstIslandChunk;ChunkZ<=LastIslandChunk;++ChunkZ)
|
||||
{
|
||||
const ECaveGeneratorType Type=Owner->Manager->GetGeneratorTypeForChunk(
|
||||
FIntVector(0,0,ChunkZ));
|
||||
if(Type==ECaveGeneratorType::FloatingIslands)
|
||||
{
|
||||
bIslandOverlap=true;
|
||||
const int32 StrateIndex=Owner->Manager->GetStrateIndex(
|
||||
static_cast<float>((static_cast<double>(ChunkZ*CHUNK_SIZE+CHUNK_SIZE/2))*VOXEL_SIZE));
|
||||
const auto* Candidate=FindWorldAssemblyFloatingIslandStratum(StrateIndex,ChunkZ);
|
||||
if(!Candidate||(IslandPlan&&IslandPlan!=Candidate))bBadPlan=true;
|
||||
IslandPlan=Candidate;
|
||||
}
|
||||
else bIslandOtherStrateOverlap=true;
|
||||
}
|
||||
}
|
||||
const auto Finish=[&](EVoxelTileClass Verdict,bool bUnknown=false)
|
||||
{
|
||||
FBoxClassification Result{Verdict,bSurfaceOverlap&&!bOtherStrateOverlap,bUnknown};
|
||||
const bool bNative=(bSurfaceOverlap&&!bOtherStrateOverlap)
|
||||
||(bIslandOverlap&&!bIslandOtherStrateOverlap);
|
||||
FBoxClassification Result{Verdict,bNative,bUnknown};
|
||||
auto& Counts=ThreadClassificationStats();
|
||||
Counts.Milliseconds+=std::chrono::duration<double,std::milli>(Clock::now()-Start).count();
|
||||
if(!Result.bNativeSurface||bUnknown)++Counts.UnknownBoxes;
|
||||
@@ -1227,7 +1288,9 @@ public:
|
||||
};
|
||||
// A box crossing recipes cannot use one field interval; unknown composition stays Mixed.
|
||||
// Une boite qui traverse plusieurs recettes reste Mixed, car l'intervalle d'un seul champ ne suffit pas.
|
||||
if(bBadPlan|| (bSurfaceOverlap&&bOtherStrateOverlap))
|
||||
if(bBadPlan||(bSurfaceOverlap&&(bIslandOverlap||bOtherStrateOverlap))
|
||||
||(bIslandOverlap&&(bIslandOtherStrateOverlap
|
||||
||(!bSurfaceOverlap&&bOtherStrateOverlap))))
|
||||
return Finish(EVoxelTileClass::Mixed,true);
|
||||
if(!EditBrushes.empty()&&EditBoundsMin.X<=BMax[0]&&EditBoundsMax.X>=BMin[0]
|
||||
&&EditBoundsMin.Y<=BMax[1]&&EditBoundsMax.Y>=BMin[1]
|
||||
@@ -1273,6 +1336,38 @@ public:
|
||||
default:return Finish(EVoxelTileClass::Mixed,true);
|
||||
}
|
||||
}
|
||||
if(bIslandOverlap)
|
||||
{
|
||||
if(!IslandPlan)return Finish(EVoxelTileClass::Mixed,true);
|
||||
constexpr std::int64_t Scale=VoxelForgeCore::WorldAssemblySubvoxelsPerVoxel;
|
||||
constexpr std::int64_t CoreVoxelsPerLegacyChunk=CHUNK_SIZE/2;
|
||||
const std::int64_t Bottom=static_cast<std::int64_t>(IslandPlan->bottomChunkZ)
|
||||
*CoreVoxelsPerLegacyChunk*Scale;
|
||||
const std::int64_t Top=(static_cast<std::int64_t>(IslandPlan->topChunkZ)+1)
|
||||
*CoreVoxelsPerLegacyChunk*Scale;
|
||||
const std::int64_t Seal=IslandPlan->manifest.recipe.boundarySealSubvoxels;
|
||||
const std::int64_t BoxBottom=static_cast<std::int64_t>(BMin[2])*Scale;
|
||||
const std::int64_t BoxTop=static_cast<std::int64_t>(BMax[2])*Scale;
|
||||
const bool bBottomSealOverlap=BoxBottom<Bottom+Seal&&BoxTop>=Bottom;
|
||||
const bool bTopSealOverlap=BoxBottom<=Top&&BoxTop>Top-Seal;
|
||||
if(bBottomSealOverlap)
|
||||
return Finish(BoxBottom>=Bottom&&BoxTop<=Bottom+Seal
|
||||
?EVoxelTileClass::AllSolid:EVoxelTileClass::Mixed);
|
||||
if(bTopSealOverlap)
|
||||
return Finish(BoxBottom>=Top-Seal&&BoxTop<=Top
|
||||
?EVoxelTileClass::AllSolid:EVoxelTileClass::Mixed);
|
||||
const VoxelForgeCore::FloatingIslandFieldV1 Block(
|
||||
IslandPlan->manifest.recipe,IslandPlan->manifest.plan);
|
||||
if(!Block.isValid())return Finish(EVoxelTileClass::Mixed,true);
|
||||
const auto Interval=Block.interval(static_cast<int64>(BMin[0])*Scale,
|
||||
static_cast<int64>(BMin[1])*Scale,static_cast<int64>(BMin[2])*Scale,
|
||||
static_cast<int64>(BMax[0])*Scale,static_cast<int64>(BMax[1])*Scale,
|
||||
static_cast<int64>(BMax[2])*Scale);
|
||||
if(!Interval.known)return Finish(EVoxelTileClass::Mixed,true);
|
||||
if(Interval.minimumDensitySubvoxels>=0)return Finish(EVoxelTileClass::AllAir);
|
||||
if(Interval.maximumDensitySubvoxels<0)return Finish(EVoxelTileClass::AllSolid);
|
||||
return Finish(EVoxelTileClass::Mixed);
|
||||
}
|
||||
const bool bRock=EvaluateFast((BMin[0]+BMax[0])*0.5,
|
||||
(BMin[1]+BMax[1])*0.5,(BMin[2]+BMax[2])*0.5);
|
||||
return Finish(bRock?EVoxelTileClass::AllSolid:EVoxelTileClass::AllAir);
|
||||
@@ -1753,6 +1848,16 @@ private:
|
||||
return It==WorldAssembly->plan.strates.end()?nullptr:&*It;
|
||||
}
|
||||
|
||||
const VoxelForgeCore::WorldAssemblyFloatingIslandPlanV1* FindWorldAssemblyFloatingIslandStratum(
|
||||
int32 StrateIndex,int32 ChunkZ) const
|
||||
{
|
||||
if(!WorldAssembly||StrateIndex<0)return nullptr;
|
||||
const auto It=std::find_if(WorldAssembly->floatingIslands.begin(),
|
||||
WorldAssembly->floatingIslands.end(),[StrateIndex,ChunkZ](const auto& Entry)
|
||||
{return Entry.strateIndex==StrateIndex&&ChunkZ<=Entry.topChunkZ&&ChunkZ>=Entry.bottomChunkZ;});
|
||||
return It==WorldAssembly->floatingIslands.end()?nullptr:&*It;
|
||||
}
|
||||
|
||||
bool NativeSurfaceDensityAt(float X,float Y,float Z,float& OutDensity) const
|
||||
{
|
||||
if(!WorldAssembly||!Owner||!Owner->Manager||!Owner->Generator
|
||||
@@ -1778,6 +1883,45 @@ private:
|
||||
return true;
|
||||
}
|
||||
|
||||
bool NativeFloatingIslandDensityAt(float X,float Y,float Z,float& OutDensity) const
|
||||
{
|
||||
if(!WorldAssembly||!Owner||!Owner->Manager||!Owner->Generator
|
||||
||!std::isfinite(X)||!std::isfinite(Y)||!std::isfinite(Z))return false;
|
||||
// Convert Core query Z back to the owner's legacy chunk coordinate.
|
||||
// Convertir Z du Core vers la coordonnee de chunk legacy du proprietaire.
|
||||
constexpr int32 CoreVoxelsPerLegacyChunk=CHUNK_SIZE/2;
|
||||
const int32 ChunkZ=FMath::FloorToInt(Z/static_cast<float>(CoreVoxelsPerLegacyChunk));
|
||||
if(Owner->Manager->GetGeneratorTypeForChunk(FIntVector(0,0,ChunkZ))
|
||||
!=ECaveGeneratorType::FloatingIslands)return false;
|
||||
const int32 StrateIndex=Owner->Manager->GetStrateIndex(
|
||||
static_cast<float>((static_cast<double>(ChunkZ*CHUNK_SIZE+CHUNK_SIZE/2))*VOXEL_SIZE));
|
||||
const auto* Plan=FindWorldAssemblyFloatingIslandStratum(StrateIndex,ChunkZ);
|
||||
if(!Plan)return false;
|
||||
constexpr double Scale=static_cast<double>(VoxelForgeCore::WorldAssemblySubvoxelsPerVoxel);
|
||||
constexpr double Maximum=1000000000000.0/Scale;
|
||||
if(std::abs(static_cast<double>(X))>Maximum||std::abs(static_cast<double>(Y))>Maximum
|
||||
||std::abs(static_cast<double>(Z))>Maximum)return false;
|
||||
const auto ToFixed=[](float Value)
|
||||
{return static_cast<int64>(std::llround(static_cast<double>(Value)
|
||||
*VoxelForgeCore::WorldAssemblySubvoxelsPerVoxel));};
|
||||
const VoxelForgeCore::FloatingIslandFieldV1 Field(
|
||||
Plan->manifest.recipe,Plan->manifest.plan);
|
||||
if(!Field.isValid())return false;
|
||||
std::int64_t Density=Field.densitySubvoxels(ToFixed(X),ToFixed(Y),ToFixed(Z));
|
||||
// A legacy 4 m chunk is 16 Core voxels at the published 12.5 cm to 25 cm scale.
|
||||
// Un chunk legacy de 4 m represente 16 voxels Core avec l'echelle publiee.
|
||||
const std::int64_t Bottom=static_cast<std::int64_t>(Plan->bottomChunkZ)
|
||||
*CoreVoxelsPerLegacyChunk*VoxelForgeCore::WorldAssemblySubvoxelsPerVoxel;
|
||||
const std::int64_t Top=(static_cast<std::int64_t>(Plan->topChunkZ)+1)
|
||||
*CoreVoxelsPerLegacyChunk*VoxelForgeCore::WorldAssemblySubvoxelsPerVoxel;
|
||||
const std::int64_t Seal=Plan->manifest.recipe.boundarySealSubvoxels;
|
||||
const std::int64_t Zq=ToFixed(Z);
|
||||
if(Zq>=Bottom&&Zq<Bottom+Seal)Density=std::min(Density,-std::max<std::int64_t>(1,Zq-Bottom));
|
||||
if(Zq<=Top&&Zq>Top-Seal)Density=std::min(Density,-std::max<std::int64_t>(1,Top-Zq));
|
||||
OutDensity=static_cast<float>(static_cast<double>(Density)/Scale);
|
||||
return std::isfinite(OutDensity);
|
||||
}
|
||||
|
||||
bool UsesLegacySurfaceField(float X,float Y,float Z) const
|
||||
{
|
||||
if(!Owner||!Owner->Manager||!Owner->Generator)return false;
|
||||
|
||||
Reference in new issue
Block a user