core: coarser smooth-route tolerance + shell support bound (L119, evaluator v224)
Chord error 2.5 -> 10 cm, shell work skipped outside the 0-0.75 m band. Sweep pairs -39%, prepare -60%, near-ready 3-8% faster than L115 but still +13..+22% vs L109. Floor offset 7.88 mm; captures match L115 by eye; fast tier, walk audits, Clang/GCC W1/W8/W12 determinism green. Not for merge yet. 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
6e52fb48b2
commit
707bc61553
40 files changed
+2352
-54
No files matched your search
@@ -147,7 +147,9 @@ namespace VoxelForgeCore
|
||||
// by the opt-in passage composer profile, except the mesh composition itself.
|
||||
std::uint64_t passageSweepRouteSegmentCandidates = 0;
|
||||
std::uint64_t passageSweepSegmentSamplePairs = 0;
|
||||
std::uint64_t passageSweepPrepareNanoseconds = 0;
|
||||
std::uint64_t passageSweepOutsideInfluencePairs = 0;
|
||||
std::uint64_t passageSweepShellSupportSkips = 0;
|
||||
std::uint64_t passageSweepMinimumUpdates = 0;
|
||||
std::uint64_t passageSweepBaseInfluenceSamples = 0;
|
||||
std::uint64_t passageSweepDetailShellSamples = 0;
|
||||
@@ -474,8 +476,9 @@ namespace VoxelForgeCore
|
||||
// Version 220 adaptively samples passage curves and rounds open-air wall crests.
|
||||
// Version 221 ranks passage segments before floor shaping and preserves their signed exterior distance.
|
||||
// Version 223 projects the floor onto one continuous arc-length profile and groups
|
||||
// dense passage samples into coarse tile candidates.
|
||||
inline constexpr std::uint32_t WorldAssemblyEvaluatorVersion = 223;
|
||||
// dense passage samples into coarse tile candidates. Version 224 keeps the same
|
||||
// continuous floor while relaxing the spline chord tolerance and bounding shell work.
|
||||
inline constexpr std::uint32_t WorldAssemblyEvaluatorVersion = 224;
|
||||
|
||||
enum class FieldChannel : std::uint32_t
|
||||
{
|
||||
|
||||
@@ -4605,7 +4605,7 @@ private:
|
||||
const double qPerMetre=Q*1000000.0/
|
||||
std::max<std::uint32_t>(1,ResolvedLayout->coreVoxelSizeMicrometres);
|
||||
constexpr double PassageSegmentSpacingMetres=8.0;
|
||||
constexpr double PassageSegmentChordErrorMetres=0.025;
|
||||
constexpr double PassageSegmentChordErrorMetres=0.100;
|
||||
std::size_t preparedSegments=0,controlSpans=0;
|
||||
for(std::size_t passageIndex=0;passageIndex<ResolvedLayout->passages.size();
|
||||
++passageIndex)
|
||||
@@ -11441,6 +11441,9 @@ inline void FStandaloneShapeWorld::FScopedPassageTileQueries::prepareSweptTubeBa
|
||||
constexpr double OpenAirSideWallHeightMetres=1.0;
|
||||
if(!shape_||step<=0||cells<=0||!std::isfinite(passageCarveReachMetres_)
|
||||
||std::abs(passageCarveReachMetres_-InfluenceMetres)>1.0e-9)return;
|
||||
const bool profile=profileStats_!=nullptr;
|
||||
const auto prepareStart=profile?std::chrono::steady_clock::now()
|
||||
:std::chrono::steady_clock::time_point{};
|
||||
|
||||
auto sweep=std::make_shared<FPassageTileSweepData>();
|
||||
sweep->gridMinimumSubvoxels={
|
||||
@@ -11463,7 +11466,6 @@ inline void FStandaloneShapeWorld::FScopedPassageTileQueries::prepareSweptTubeBa
|
||||
constexpr double MouthShellBlendMetres=5.0;
|
||||
const double wallReliefShell=0.41*qPerMetre;
|
||||
const double floorDetailShell=1.0*qPerMetre;
|
||||
const bool profile=profileStats_!=nullptr;
|
||||
if(profile)
|
||||
{
|
||||
profileStats_->passageSweepRouteSegmentCandidates=routeSegmentCandidateCount_;
|
||||
@@ -11550,8 +11552,6 @@ inline void FStandaloneShapeWorld::FScopedPassageTileQueries::prepareSweptTubeBa
|
||||
FStandaloneShapeWorld::PassageFlatFloorCenterZSubvoxels(
|
||||
constants,segments,segmentIndex,floorT,segment,
|
||||
qx,qy,floorDepth,qPerMetre);
|
||||
const double flatDistance=FStandaloneShapeWorld::PassageFlatBottomDistance(
|
||||
static_cast<float>(signedDistance),floorCenterZ,qz,floorDepth,qPerMetre);
|
||||
if(profile)++profileStats_->passageSweepSegmentSamplePairs;
|
||||
if(signedDistance>sweep->influenceSubvoxels)
|
||||
{
|
||||
@@ -11572,51 +11572,75 @@ inline void FStandaloneShapeWorld::FScopedPassageTileQueries::prepareSweptTubeBa
|
||||
sample.floorSegmentIndex=static_cast<std::uint32_t>(
|
||||
segmentIndex);
|
||||
}
|
||||
const double alongMetres=segment.authoredAlongMetres
|
||||
+t*segment.authoredLengthMetres;
|
||||
const double mouthDistanceMetres=std::max(0.0,std::min(alongMetres,
|
||||
constants.totalPathLengthMetres-alongMetres));
|
||||
const double shellFade=std::clamp(mouthDistanceMetres/
|
||||
MouthShellBlendMetres,0.0,1.0);
|
||||
const double smoothShellFade=shellFade*shellFade
|
||||
*(3.0-2.0*shellFade);
|
||||
const double floorDistanceMetres=(floorCenterZ-floorDepth-qz)/qPerMetre;
|
||||
const double floorBlend=std::clamp(floorDistanceMetres/0.25,0.0,1.0);
|
||||
const double smoothFloorBlend=floorBlend*floorBlend
|
||||
*(3.0-2.0*floorBlend);
|
||||
const double wallElevationMetres=(qz-(floorCenterZ-floorDepth))
|
||||
/qPerMetre;
|
||||
const double mouthWallThickness=segment.routeSegment
|
||||
?smoothShellFade*shellThickness:0.0;
|
||||
double floorExtensionFade=1.0;
|
||||
if(!segment.routeSegment)
|
||||
// A negative shell distance is possible only when the flattened tube
|
||||
// distance lies in [0, shellThickness]. SmoothMaxDistance is at least
|
||||
// max(roundDistance, floorDistance) and can raise that maximum by no
|
||||
// more than cornerWidth/6. Skip its work for pairs outside this exact
|
||||
// support, with a small subvoxel guard for float rounding. The final
|
||||
// shell union only consumes negative distances.
|
||||
constexpr double CornerBlendMetres=0.50;
|
||||
const float roundDistanceFloat=static_cast<float>(signedDistance);
|
||||
const float floorDistanceFloat=static_cast<float>(floorCenterZ-floorDepth-qz);
|
||||
const double flatDistanceLowerBound=std::max(
|
||||
static_cast<double>(roundDistanceFloat),
|
||||
static_cast<double>(floorDistanceFloat));
|
||||
const double cornerWidth=static_cast<double>(static_cast<float>(
|
||||
CornerBlendMetres*qPerMetre));
|
||||
const bool shellSupportPossible=flatDistanceLowerBound
|
||||
>=-cornerWidth/6.0-1.0
|
||||
&&flatDistanceLowerBound<=shellThickness+1.0;
|
||||
if(shellSupportPossible)
|
||||
{
|
||||
const double pastMouthMetres=std::max(0.0,alongMetres
|
||||
-constants.totalPathLengthMetres);
|
||||
const double extensionFade=std::clamp(1.0
|
||||
-pastMouthMetres/MouthShellBlendMetres,0.0,1.0);
|
||||
floorExtensionFade=extensionFade*extensionFade
|
||||
*(3.0-2.0*extensionFade);
|
||||
const double flatDistance=FStandaloneShapeWorld::PassageFlatBottomDistance(
|
||||
roundDistanceFloat,floorCenterZ,qz,floorDepth,qPerMetre);
|
||||
const double alongMetres=segment.authoredAlongMetres
|
||||
+t*segment.authoredLengthMetres;
|
||||
const double mouthDistanceMetres=std::max(0.0,std::min(alongMetres,
|
||||
constants.totalPathLengthMetres-alongMetres));
|
||||
const double shellFade=std::clamp(mouthDistanceMetres/
|
||||
MouthShellBlendMetres,0.0,1.0);
|
||||
const double smoothShellFade=shellFade*shellFade
|
||||
*(3.0-2.0*shellFade);
|
||||
const double floorDistanceMetres=(floorCenterZ-floorDepth-qz)/qPerMetre;
|
||||
const double floorBlend=std::clamp(floorDistanceMetres/0.25,0.0,1.0);
|
||||
const double smoothFloorBlend=floorBlend*floorBlend
|
||||
*(3.0-2.0*floorBlend);
|
||||
const double wallElevationMetres=(qz-(floorCenterZ-floorDepth))
|
||||
/qPerMetre;
|
||||
const double mouthWallThickness=segment.routeSegment
|
||||
?smoothShellFade*shellThickness:0.0;
|
||||
double floorExtensionFade=1.0;
|
||||
if(!segment.routeSegment)
|
||||
{
|
||||
const double pastMouthMetres=std::max(0.0,alongMetres
|
||||
-constants.totalPathLengthMetres);
|
||||
const double extensionFade=std::clamp(1.0
|
||||
-pastMouthMetres/MouthShellBlendMetres,0.0,1.0);
|
||||
floorExtensionFade=extensionFade*extensionFade
|
||||
*(3.0-2.0*extensionFade);
|
||||
}
|
||||
const double floorShellThickness=smoothFloorBlend*shellThickness
|
||||
*floorExtensionFade*smoothShellFade;
|
||||
const double wallShellDistance=
|
||||
FStandaloneShapeWorld::PassageRoundedWallShellDistance(
|
||||
flatDistance,wallElevationMetres*qPerMetre,
|
||||
OpenAirSideWallHeightMetres*qPerMetre,mouthWallThickness);
|
||||
const double floorShellDistance=std::max(
|
||||
-static_cast<double>(flatDistance),
|
||||
static_cast<double>(flatDistance)-floorShellThickness);
|
||||
const double localShellDistance=std::min(wallShellDistance,
|
||||
floorShellDistance);
|
||||
sample.shellSignedDistance=std::min(sample.shellSignedDistance,
|
||||
localShellDistance);
|
||||
}
|
||||
const double floorShellThickness=smoothFloorBlend*shellThickness
|
||||
*floorExtensionFade*smoothShellFade;
|
||||
const double wallShellDistance=
|
||||
FStandaloneShapeWorld::PassageRoundedWallShellDistance(
|
||||
flatDistance,wallElevationMetres*qPerMetre,
|
||||
OpenAirSideWallHeightMetres*qPerMetre,mouthWallThickness);
|
||||
const double floorShellDistance=std::max(-static_cast<double>(flatDistance),
|
||||
static_cast<double>(flatDistance)-floorShellThickness);
|
||||
const double localShellDistance=std::min(wallShellDistance,
|
||||
floorShellDistance);
|
||||
sample.shellSignedDistance=std::min(sample.shellSignedDistance,
|
||||
localShellDistance);
|
||||
else if(profile)
|
||||
++profileStats_->passageSweepShellSupportSkips;
|
||||
// Rank the tube body by round SDF. Its floor plane is selected
|
||||
// independently above from the nearest centerline position.
|
||||
if(!sample.valid||signedDistance<sample.roundSignedDistance
|
||||
||(signedDistance==sample.roundSignedDistance
|
||||
&&segmentIndex<sample.segmentIndex))
|
||||
{
|
||||
sample.signedDistance=flatDistance;
|
||||
sample.roundSignedDistance=signedDistance;
|
||||
sample.centerZSubvoxels=cz;
|
||||
sample.radiusSubvoxels=radius;
|
||||
@@ -11686,6 +11710,9 @@ inline void FStandaloneShapeWorld::FScopedPassageTileQueries::prepareSweptTubeBa
|
||||
profileStats_->passageSweepNoInfluenceGridSamples=
|
||||
static_cast<std::uint64_t>(std::count(anyPassageInfluence.begin(),
|
||||
anyPassageInfluence.end(),static_cast<std::uint8_t>(0)));
|
||||
profileStats_->passageSweepPrepareNanoseconds+=static_cast<std::uint64_t>(
|
||||
std::max<std::int64_t>(0,std::chrono::duration_cast<std::chrono::nanoseconds>(
|
||||
std::chrono::steady_clock::now()-prepareStart).count()));
|
||||
}
|
||||
passageSweepData_=std::move(sweep);
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user