fix: signed-overflow UB in VoxelHash made cave placement compiler-dependent; all generators LOD0-8; speed matrix (L60)
VoxelHash::Cell/Pair, legacy Cellular3D and the shared Core cellular hash added 0x7FFFFFFF to a signed int32 before casting to uint32; overflow is undefined, so Clang and GCC placed cave passage 1 differently (first differing sample at LOD1 tile (0,64,-512)). The bias is now done in unsigned arithmetic, in both the standalone copy and the Unreal plugin header (Source/VoxelForge/Public/VoxelCaveMorphology.h). Native caves, motifs and lattice now stream LOD0-8 with skirts and cross-level transitions. New verify.py --speed-matrix runs every generator on one asserted-identical view (5 interleaved runs): motifs 1.33, profiles 1.30-1.32, caves 1.41, natural SW 1.67, lattice 1.70, FI 4.93 s whole view. fast/medium/full PASS, Clang/GCC peer hashes equal. Research R29 (open-edge ledge) and R30 (compiler-divergence suspects). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_016dhxM43dnWvUu2B5Ph1iG1
This commit is contained in:
1 parent
fbae82e024
commit
c0c204ba50
15 files changed
+938
-65
No files matched your search
@@ -3187,9 +3187,11 @@ public:
|
||||
const float SampleY=static_cast<float>(Y);
|
||||
const float SampleZ=static_cast<float>(Z);
|
||||
bHasLegacySurfaceSample|=UsesLegacySurfaceField(SampleX,SampleY,SampleZ);
|
||||
const auto* bound=FindBoundStratumForZ(SampleZ);
|
||||
bHasNativeGraphSample|=bound
|
||||
&&bound->Kind==FBoundStratumField::EKind::Caves;
|
||||
const auto* managerBound=FindBoundStratumForManagerZ(SampleZ);
|
||||
const auto* resolvedBound=FindBoundStratumForZ(SampleZ);
|
||||
bHasNativeGraphSample|=(managerBound
|
||||
&&managerBound->Kind==FBoundStratumField::EKind::Caves)
|
||||
||(resolvedBound&&resolvedBound->Kind==FBoundStratumField::EKind::Caves);
|
||||
HasNativeIslandSample[static_cast<std::size_t>(Lane)]=NativeFloatingIslandDensityAt(
|
||||
SampleX,SampleY,SampleZ,NativeIslandDensity[static_cast<std::size_t>(Lane)]);
|
||||
bHasNativeIslandSample|=HasNativeIslandSample[static_cast<std::size_t>(Lane)];
|
||||
@@ -3897,8 +3899,7 @@ private:
|
||||
>node.maximum[splitAxis]-node.minimum[splitAxis])
|
||||
splitAxis=axis;
|
||||
const std::size_t middle=first+(end-first)/2;
|
||||
std::nth_element(runtime.segmentOrder.begin()+first,
|
||||
runtime.segmentOrder.begin()+middle,
|
||||
std::sort(runtime.segmentOrder.begin()+first,
|
||||
runtime.segmentOrder.begin()+end,
|
||||
[&](std::uint32_t a,std::uint32_t b)
|
||||
{
|
||||
@@ -7120,6 +7121,7 @@ private:
|
||||
double nearestFloor=0.0,nearestGrade=0.0,nearestRadial=0.0;
|
||||
const double radius=feature.edge->boreRadiusMicrometres/1000000.0;
|
||||
const double height=feature.edge->boreHeightMicrometres/1000000.0;
|
||||
constexpr double SegmentDistanceTieToleranceMetres=1.0e-12;
|
||||
if(!(radius>0.0&&height>0.0))continue;
|
||||
const double minScale=std::min(radius,height);
|
||||
std::uint32_t nearestSegment=std::numeric_limits<std::uint32_t>::max();
|
||||
@@ -7147,7 +7149,10 @@ private:
|
||||
const double normalized=std::sqrt(radialSquared/(radius*radius)
|
||||
+vertical*vertical/(height*height));
|
||||
const double distance=(normalized-1.0)*std::min(radius,height);
|
||||
if(distance<tube||(distance==tube&&segmentIndex<nearestSegment))
|
||||
const bool clearlyCloser=distance<tube-SegmentDistanceTieToleranceMetres;
|
||||
const bool stableTie=std::abs(distance-tube)
|
||||
<=SegmentDistanceTieToleranceMetres&&segmentIndex<nearestSegment;
|
||||
if(clearlyCloser||stableTie)
|
||||
{
|
||||
tube=distance;nearestSegment=segmentIndex;
|
||||
nearestFloor=segment.start[2]+t*(segment.end[2]-segment.start[2]);
|
||||
@@ -7178,7 +7183,7 @@ private:
|
||||
{
|
||||
if(nodeIndex<0||static_cast<std::size_t>(nodeIndex)>=feature.segmentNodes.size())return;
|
||||
const auto& node=feature.segmentNodes[static_cast<std::size_t>(nodeIndex)];
|
||||
if(nodeLowerBound(node)>tube)return;
|
||||
if(nodeLowerBound(node)>tube+SegmentDistanceTieToleranceMetres)return;
|
||||
if(node.left<0)
|
||||
{
|
||||
for(std::size_t offset=node.first;offset<node.end;++offset)
|
||||
@@ -10195,10 +10200,19 @@ public:
|
||||
return;
|
||||
}
|
||||
bool bHasLegacySurfaceSample=false;
|
||||
bool bHasNativeGraphSample=false;
|
||||
for(int32 Lane=0;Lane<Count;++Lane)
|
||||
{
|
||||
const float SampleZ=static_cast<float>(ZStart+Lane*ZStep);
|
||||
bHasLegacySurfaceSample|=UsesLegacySurfaceField(static_cast<float>(X),
|
||||
static_cast<float>(Y),static_cast<float>(ZStart+Lane*ZStep));
|
||||
if(bHasLegacySurfaceSample)
|
||||
static_cast<float>(Y),SampleZ);
|
||||
const auto* managerBound=FindBoundStratumForManagerZ(SampleZ);
|
||||
const auto* resolvedBound=FindBoundStratumForZ(SampleZ);
|
||||
bHasNativeGraphSample|=(managerBound
|
||||
&&managerBound->Kind==FBoundStratumField::EKind::Caves)
|
||||
||(resolvedBound&&resolvedBound->Kind==FBoundStratumField::EKind::Caves);
|
||||
}
|
||||
if(bHasLegacySurfaceSample||bHasNativeGraphSample)
|
||||
{
|
||||
for(int32 Lane=0;Lane<Count;++Lane)
|
||||
OutDensity[Lane]=DensityAtLattice(X,Y,ZStart+Lane*ZStep);
|
||||
|
||||
Reference in new issue
Block a user