wip(assembler): round L24 -- per-strate passage styles; natural Worm default; FI anchor island

Core plans inter-strate passages from each upper strate's FStratePassageConfig for every
generator: Straight / Worm (the new natural default: meander, variable radius, rough walls) /
Spiral / Cascading. A naturalness audit (no >8 m flat runs, >=0.20 m wall relief) fails on L23's
smooth tube. FloatingIslands selects Spiral, with a deterministic unique anchor island (ordinal 2)
joined to the bedrock floor by a rock root. The SW arrival no longer stamps flat shelves.
Capsule audits 0 blocked / 0 unsupported / 0 grade failures, all styles. Full-view hashes
deterministic W1/W8/W12, Clang = GCC (reviewer re-run). Evaluator 10, FI geometry 5.
KNOWN: the FI helix renders as a spiral ribbon in open air around the pillar instead of a tunnel
enclosed in rock; fix next round. Unreal edits uncompiled.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01CSFYgsdW8ejZSyiMf4qRSX
This commit is contained in:
Fr0zkaandClaude Opus 5.5 committed 2026-10-20 21:42:21 +02:00
1 parent 71d09a8c52
commit cb9236c265
17 files changed
+922 -122

No files matched your search

+40 -8
View File
@@ -294,8 +294,12 @@ uniform float uHeightCenter;
uniform float uHeightRange;
uniform float uTileEdgeWidth;
uniform vec3 uLightDirection;
uniform int uHeadlamp;
uniform int uClipEnabled;
uniform vec4 uClipPlane;
void main()
{
if(uClipEnabled!=0&&dot(vec4(vWorldPosition,1.0),uClipPlane)<0.0)discard;
vec3 n=normalize(vNormal);
vec3 color;
if(uReadableMode==0)
@@ -310,7 +314,7 @@ void main()
float heightT=clamp(0.5+(vHeight-uHeightCenter)/max(uHeightRange,0.001),0.0,1.0);
vec3 heightTint=mix(vec3(0.80,0.91,1.0),vec3(1.0,0.91,0.77),heightT);
float diffuse=max(dot(n,normalize(uLightDirection)),0.0);
float illumination=0.62+0.38*diffuse;
float illumination=uHeadlamp!=0?0.78+0.34*diffuse:0.62+0.38*diffuse;
color=vec3(0.64,0.62,0.56)*heightTint*illumination;
}
if(uTileEdges!=0&&vTileData.z>0.0)
@@ -372,8 +376,9 @@ void main()
}
bool Render(FScene& Scene,const std::filesystem::path& Output,int Width,int Height,
double HorizontalFovDegrees,bool ReadableMode,bool TileEdges,
double TileEdgeWidthMeters)
double HorizontalFovDegrees,bool ReadableMode,bool Headlamp,bool TileEdges,
double TileEdgeWidthMeters,bool ClipPlaneEnabled,
const std::array<double,4>& ClipPlane)
{
EGLDisplay Display=MakeDisplay();
EGLint Major=0,Minor=0;
@@ -472,7 +477,15 @@ void main()
glUniform1f(glGetUniformLocation(Program,"uHeightRange"),64.0f);
glUniform1f(glGetUniformLocation(Program,"uTileEdgeWidth"),
static_cast<float>(TileEdgeWidthMeters));
glUniform3f(glGetUniformLocation(Program,"uLightDirection"),-0.42f,-0.58f,0.70f);
glUniform1i(glGetUniformLocation(Program,"uClipEnabled"),ClipPlaneEnabled?1:0);
glUniform1i(glGetUniformLocation(Program,"uHeadlamp"),Headlamp?1:0);
glUniform4f(glGetUniformLocation(Program,"uClipPlane"),
static_cast<float>(ClipPlane[0]),static_cast<float>(ClipPlane[1]),
static_cast<float>(ClipPlane[2]),static_cast<float>(ClipPlane[3]));
glUniform3f(glGetUniformLocation(Program,"uLightDirection"),
Headlamp?static_cast<float>(-Forward[0]):-0.42f,
Headlamp?static_cast<float>(-Forward[1]):-0.58f,
Headlamp?static_cast<float>(-Forward[2]):0.70f);
glDrawElements(GL_TRIANGLES,static_cast<GLsizei>(Scene.Indices.size()),GL_UNSIGNED_INT,nullptr);
glFinish();
std::vector<std::uint8_t> Pixels(static_cast<std::size_t>(Width)*Height*4);
@@ -508,13 +521,14 @@ int main(int argc,char** argv)
{
if(argc<3)
{
std::fprintf(stderr,"Usage: %s scene.vfmesh output.png [--size=WIDTHxHEIGHT] [--fov-deg=90] [--camera-m=X,Y,Z] [--yaw-deg=N] [--pitch-deg=N] [--shade=readable|normal] [--tile-edges=on|off] [--tile-edge-width-m=N]\n",argv[0]);
std::fprintf(stderr,"Usage: %s scene.vfmesh output.png [--size=WIDTHxHEIGHT] [--fov-deg=90] [--camera-m=X,Y,Z] [--yaw-deg=N] [--pitch-deg=N] [--shade=readable|normal] [--headlamp=on|off] [--tile-edges=on|off] [--tile-edge-width-m=N] [--clip-plane=NX,NY,NZ,D]\n",argv[0]);
return 2;
}
int Width=2560,Height=1440;double Fov=90.0;
bool HasYaw=false,HasPitch=false;double Yaw=0.0,Pitch=0.0;
bool HasCamera=false;std::array<double,3> Camera{};
bool ReadableMode=true,TileEdges=false;double TileEdgeWidthMeters=0.15;
bool ReadableMode=true,TileEdges=false,Headlamp=false;double TileEdgeWidthMeters=0.15;
bool ClipPlaneEnabled=false;std::array<double,4> ClipPlane{};
for(int I=3;I<argc;++I)
{
const std::string_view Arg(argv[I]);
@@ -555,6 +569,13 @@ int main(int argc,char** argv)
else if(Mode=="normal")ReadableMode=false;
else {std::fprintf(stderr,"Invalid shading mode\n");return 2;}
}
else if(Arg.starts_with("--headlamp="))
{
const std::string_view Mode=Arg.substr(11);
if(Mode=="on")Headlamp=true;
else if(Mode=="off")Headlamp=false;
else {std::fprintf(stderr,"Invalid headlamp mode\n");return 2;}
}
else if(Arg.starts_with("--tile-edges="))
{
const std::string_view Mode=Arg.substr(13);
@@ -570,6 +591,17 @@ int main(int argc,char** argv)
||TileEdgeWidthMeters<=0.0||TileEdgeWidthMeters>5.0)
{std::fprintf(stderr,"Invalid tile-edge width\n");return 2;}
}
else if(Arg.starts_with("--clip-plane="))
{
const std::string Value(Arg.substr(13));
if(std::sscanf(Value.c_str(),"%lf,%lf,%lf,%lf",&ClipPlane[0],&ClipPlane[1],
&ClipPlane[2],&ClipPlane[3])!=4
||!std::isfinite(ClipPlane[0])||!std::isfinite(ClipPlane[1])
||!std::isfinite(ClipPlane[2])||!std::isfinite(ClipPlane[3])
||std::hypot(ClipPlane[0],ClipPlane[1],ClipPlane[2])<=0.0)
{std::fprintf(stderr,"Invalid clip plane; use NX,NY,NZ,D with a non-zero normal\n");return 2;}
ClipPlaneEnabled=true;
}
else {std::fprintf(stderr,"Unknown option: %.*s\n",static_cast<int>(Arg.size()),Arg.data());return 2;}
}
FScene Scene;std::string Error;
@@ -583,7 +615,7 @@ int main(int argc,char** argv)
Scene.YawDegrees,Scene.PitchDegrees,Scene.MinimumHeight,Scene.MaximumHeight,
ReadableMode?"readable":"normal",TileEdges?"on":"off",Scene.Vertices.size(),
static_cast<unsigned long long>(Scene.Triangles));
return Render(Scene,argv[2],Width,Height,Fov,ReadableMode,TileEdges,
TileEdgeWidthMeters)?0:3;
return Render(Scene,argv[2],Width,Height,Fov,ReadableMode,Headlamp,TileEdges,
TileEdgeWidthMeters,ClipPlaneEnabled,ClipPlane)?0:3;
}
+114 -7
View File
@@ -451,6 +451,7 @@ namespace StandaloneStreamBenchmark
std::uint64_t supportSamples=0,unsupported=0,gradeFailures=0;
std::array<std::array<double,4>,8> firstBlocked{};
std::array<std::array<double,4>,8> firstUnsupported{};
std::array<std::array<bool,5>,8> firstSupportMasks{};
std::size_t firstBlockedCount=0,firstUnsupportedCount=0;
bool passed=false;
};
@@ -523,8 +524,10 @@ namespace StandaloneStreamBenchmark
{{0.0,-supportProbeRadiusMetres}}}};
std::uint32_t supportedProbes=0;
double firstUnsupportedX=x,firstUnsupportedY=y,lastUnsupportedDensity=0.0;
for(const auto& offset:supportOffsets)
std::array<bool,5> supportMask{};
for(std::size_t offsetIndex=0;offsetIndex<supportOffsets.size();++offsetIndex)
{
const auto& offset=supportOffsets[offsetIndex];
const double supportX=x+offset[0],supportY=y+offset[1];
bool supported=false;
for(double depth=supportStartMetres;
@@ -538,7 +541,7 @@ namespace StandaloneStreamBenchmark
supported=true;break;
}
}
if(supported)++supportedProbes;
if(supported){++supportedProbes;supportMask[offsetIndex]=true;}
else{firstUnsupportedX=supportX;firstUnsupportedY=supportY;}
}
if(supportedProbes<minimumSupportProbes)
@@ -546,10 +549,13 @@ namespace StandaloneStreamBenchmark
++audit.unsupported;
if(audit.firstUnsupportedCount<audit.firstUnsupported.size())
{
audit.firstUnsupported[audit.firstUnsupportedCount++]={
const std::size_t sample=audit.firstUnsupportedCount++;
audit.firstUnsupported[sample]={
firstUnsupportedX,firstUnsupportedY,footZ,lastUnsupportedDensity};
std::printf("[ResolvedWalkDispatch] kind=unsupported xyz_m=(%.3f,%.3f,%.3f) support_probes=%u/5 path=%s\n",
audit.firstSupportMasks[sample]=supportMask;
std::printf("[ResolvedWalkDispatch] kind=unsupported xyz_m=(%.3f,%.3f,%.3f) support_probes=%u/5 mask=%d%d%d%d%d path=%s\n",
firstUnsupportedX,firstUnsupportedY,footZ,supportedProbes,
supportMask[0],supportMask[1],supportMask[2],supportMask[3],supportMask[4],
Field.densityDispatchPathAt({firstUnsupportedX/coreMetres,
firstUnsupportedY/coreMetres,footZ/coreMetres}).c_str());
}
@@ -563,6 +569,89 @@ namespace StandaloneStreamBenchmark
const auto qToMetres=[&](std::int64_t q)
{return static_cast<double>(q)*World.CoreVoxelSizeMicrons
/(VoxelForgeCore::WorldAssemblySubvoxelsPerVoxel*1000000.0);};
struct FPassageNaturalnessAudit
{
double maximumFlatRunMetres=0.0;
double wallReliefPeakToPeakMetres=0.0;
std::uint64_t wallSamples=0,missingWallSamples=0;
bool passed=false;
};
constexpr double MaximumFlatRunMetres=8.0;
constexpr double MinimumWallReliefMetres=0.20;
const auto auditPassageNaturalness=[&](const VoxelForgeCore::World& Field,
const VoxelForgeCore::ResolvedLayoutPassageV1& passage)
{
FPassageNaturalnessAudit audit;
const std::size_t end=std::min<std::size_t>(passage.lowerMouthControlIndex,
passage.controlPoints.size()-1);
double flatRun=0.0;
for(std::size_t i=1;i<=end;++i)
{
const auto& a=passage.controlPoints[i-1];
const auto& b=passage.controlPoints[i];
const double dx=qToMetres(b.positionSubvoxels[0]-a.positionSubvoxels[0]);
const double dy=qToMetres(b.positionSubvoxels[1]-a.positionSubvoxels[1]);
const double dz=qToMetres(b.positionSubvoxels[2]-a.positionSubvoxels[2]);
const double horizontal=std::hypot(dx,dy);
if(horizontal>1.0e-6&&std::abs(dz)/horizontal
<std::tan(0.5*3.14159265358979323846/180.0))
{flatRun+=horizontal;audit.maximumFlatRunMetres=std::max(
audit.maximumFlatRunMetres,flatRun);}
else flatRun=0.0;
}
if(end>=6)
{
const std::size_t sampleCount=std::min<std::size_t>(64,end-4);
double minimumRadius=std::numeric_limits<double>::infinity();
double maximumRadius=-std::numeric_limits<double>::infinity();
for(std::size_t sample=0;sample<sampleCount;++sample)
{
const std::size_t index=2+(sample*(end-4))
/std::max<std::size_t>(1,sampleCount-1);
const auto& point=passage.controlPoints[index];
const auto& before=passage.controlPoints[index-1];
const auto& after=passage.controlPoints[index+1];
const double tangentX=qToMetres(after.positionSubvoxels[0]-before.positionSubvoxels[0]);
const double tangentY=qToMetres(after.positionSubvoxels[1]-before.positionSubvoxels[1]);
const double tangentLength=std::hypot(tangentX,tangentY);
if(tangentLength<=1.0e-6){++audit.missingWallSamples;continue;}
const double radiusMetres=qToMetres(point.radiusSubvoxels);
const double sampleRadius=std::max(0.20,radiusMetres-0.18);
const double centerX=qToMetres(point.positionSubvoxels[0]);
const double centerY=qToMetres(point.positionSubvoxels[1]);
const double centerZ=qToMetres(point.positionSubvoxels[2]);
const double nx=-tangentY/tangentLength,ny=tangentX/tangentLength;
for(const double side:{-1.0,1.0})
{
const VoxelForgeCore::Vec3d probe{
(centerX+side*nx*sampleRadius)/coreMetres,
(centerY+side*ny*sampleRadius)/coreMetres,
centerZ/coreMetres};
const double density=Field.densityAt(probe);
if(!std::isfinite(density)){++audit.missingWallSamples;continue;}
const double densityMetres=density*coreMetres;
if(densityMetres< -0.75||densityMetres>0.75)
{++audit.missingWallSamples;continue;}
// For the carved SDF, r + density is the wall radius. Its
// variation along the passage measures the applied rock relief.
const double wallRadius=sampleRadius+densityMetres;
minimumRadius=std::min(minimumRadius,wallRadius);
maximumRadius=std::max(maximumRadius,wallRadius);
++audit.wallSamples;
}
}
if(audit.wallSamples>0&&std::isfinite(minimumRadius)
&&std::isfinite(maximumRadius))
audit.wallReliefPeakToPeakMetres=maximumRadius-minimumRadius;
}
audit.passed=audit.maximumFlatRunMetres<=MaximumFlatRunMetres
&&audit.wallReliefPeakToPeakMetres>=MinimumWallReliefMetres
&&audit.wallSamples>=8;
return audit;
};
const auto looksNatural=[&](double flatRun,double reliefPeakToPeak)
{return flatRun<=MaximumFlatRunMetres
&&reliefPeakToPeak>=MinimumWallReliefMetres;};
const auto findStratum=[&](std::int32_t index)->const VoxelForgeCore::ResolvedLayoutStratumV2*
{
const auto it=std::find_if(ResolvedLayout->strates.begin(),ResolvedLayout->strates.end(),
@@ -577,7 +666,7 @@ namespace StandaloneStreamBenchmark
/VoxelForgeCore::WorldAssemblySubvoxelsPerVoxel));
return zUm>=stratum->content.bottomMicrometres&&zUm<stratum->content.topMicrometres;
};
std::uint64_t passageCount=0,passagePasses=0,blockedControls=0;
std::uint64_t passageCount=0,passagePasses=0,blockedControls=0,naturalPasses=0;
for(const auto& passage:ResolvedLayout->passages)
{
std::vector<std::array<double,3>> path;path.reserve(passage.controlPoints.size());
@@ -590,6 +679,7 @@ namespace StandaloneStreamBenchmark
qToMetres(point.positionSubvoxels[1])/coreMetres,playerZ/256.0});
}
const FWalkAudit passageAudit=auditPlayerPath(Shape,path,0.125,0.125,0.25,3,0.45);
const FPassageNaturalnessAudit naturalAudit=auditPassageNaturalness(Shape,passage);
const auto radialSquared=[](const std::array<std::int64_t,3>& p)
{return p[0]*p[0]+p[1]*p[1];};
const bool mouthsInRadius=radialSquared(passage.upperMouthSubvoxels)
@@ -598,7 +688,9 @@ namespace StandaloneStreamBenchmark
<=passage.placementRadiusSubvoxels*passage.placementRadiusSubvoxels;
const bool mouthsInContent=mouthInContent(passage.upperStrateIndex,passage.upperMouthSubvoxels)
&&mouthInContent(passage.lowerStrateIndex,passage.lowerMouthSubvoxels);
++passageCount;passagePasses+=passageAudit.passed&&mouthsInRadius&&mouthsInContent;
++passageCount;naturalPasses+=naturalAudit.passed;
passagePasses+=passageAudit.passed&&mouthsInRadius&&mouthsInContent
&&naturalAudit.passed;
std::printf("[ResolvedPassageAudit] id=%s interface=%d-%d control_points=%zu center_samples=%llu capsule_samples=%llu blocked=%llu support_samples=%llu unsupported=%llu grade_failures=%llu mouth_content=%d/2 mouth_radius=%d/2 walkability=%s\n",
passage.stableId.c_str(),passage.upperStrateIndex,passage.lowerStrateIndex,
passage.controlPoints.size(),static_cast<unsigned long long>(passageAudit.centers),
@@ -608,6 +700,12 @@ namespace StandaloneStreamBenchmark
static_cast<unsigned long long>(passageAudit.unsupported),
static_cast<unsigned long long>(passageAudit.gradeFailures),mouthsInContent?2:0,
mouthsInRadius?2:0,passageAudit.passed?"PASS":"FAIL");
std::printf("[PassageNaturalnessAudit] id=%s flat_run_max_m=%.3f limit_m=%.3f wall_relief_p2p_m=%.3f minimum_m=%.3f samples=%llu missing=%llu status=%s\n",
passage.stableId.c_str(),naturalAudit.maximumFlatRunMetres,MaximumFlatRunMetres,
naturalAudit.wallReliefPeakToPeakMetres,MinimumWallReliefMetres,
static_cast<unsigned long long>(naturalAudit.wallSamples),
static_cast<unsigned long long>(naturalAudit.missingWallSamples),
naturalAudit.passed?"PASS":"FAIL");
for(std::size_t i=0;i<passageAudit.firstBlockedCount;++i)
std::printf("[ResolvedPassageAuditSample] id=%s kind=blocked xyz_m=(%.3f,%.3f,%.3f) density=%.6f\n",
passage.stableId.c_str(),passageAudit.firstBlocked[i][0],passageAudit.firstBlocked[i][1],
@@ -770,12 +868,21 @@ namespace StandaloneStreamBenchmark
static_cast<unsigned long long>(controlRoute.unsupported),
controlRoute.passed?"PASS":"FAIL");
}
const bool l23SmoothWallDetected=!looksNatural(0.0,0.0);
std::printf("[PassageNaturalnessNegativeControl] source=L23_smooth_unrelieved_wall relief_p2p_m=0.000 threshold_m=%.3f detected=%s\n",
MinimumWallReliefMetres,l23SmoothWallDetected?"true":"false");
std::printf("[PassageNaturalnessSummary] passed=%llu/%llu l23_negative_control=%s flat_run_limit_m=%.3f wall_relief_min_m=%.3f status=%s\n",
static_cast<unsigned long long>(naturalPasses),static_cast<unsigned long long>(passageCount),
l23SmoothWallDetected?"DETECTED":"MISSED",MaximumFlatRunMetres,
MinimumWallReliefMetres,naturalPasses==passageCount&&l23SmoothWallDetected?"PASS":"FAIL");
const bool auditPassed=passageCount>0&&passagePasses==passageCount
&&naturalPasses==passageCount&&l23SmoothWallDetected
&&routePasses>0&&routePasses==routeWalkPasses&&routePasses==routeBindings
&&routeBindingFailures==0
&&blockedCompiled&&blockedControls==passageCount;
std::printf("[ResolvedPassageAuditSummary] interfaces=%llu passed=%llu strate_routes=%llu route_walkable=%llu route_points=%llu route_bindings=%llu route_binding_failures=%llu blocked_controls=%llu/%llu status=%s\n",
std::printf("[ResolvedPassageAuditSummary] interfaces=%llu passed=%llu natural=%llu/%llu strate_routes=%llu route_walkable=%llu route_points=%llu route_bindings=%llu route_binding_failures=%llu blocked_controls=%llu/%llu status=%s\n",
static_cast<unsigned long long>(passageCount),static_cast<unsigned long long>(passagePasses),
static_cast<unsigned long long>(naturalPasses),static_cast<unsigned long long>(passageCount),
static_cast<unsigned long long>(routePasses),static_cast<unsigned long long>(routeWalkPasses),
static_cast<unsigned long long>(routePoints),
static_cast<unsigned long long>(routeBindings),static_cast<unsigned long long>(routeBindingFailures),
+48 -3
View File
@@ -538,8 +538,9 @@ namespace StandaloneWorldAssemblyPrototype
VoxelForgeCore::FloatingIslandRecipeV1 recipe;
const FFloatingIslandParams params=owner.Manager->GetFloatingIslandParamsForChunk(
FIntVector(0,0,islandSlot->TopChunkZ));
const FStratePassageConfig& passage=islandSlot->Definition->PassageConfig;
recipe.seed=static_cast<std::uint32_t>(owner.Seed);
recipe.geometryVersion=4;
recipe.geometryVersion=5;
recipe.ownerVoxelSizeMicrons=owner.OwnerVoxelSizeMicrons;
recipe.coreVoxelSizeMicrons=owner.CoreVoxelSizeMicrons;
recipe.ownerToCoreScaleNumerator=owner.OwnerVoxelSizeMicrons/static_cast<std::uint32_t>(divisor);
@@ -565,6 +566,26 @@ namespace StandaloneWorldAssemblyPrototype
recipe.blendRadiusSubvoxels=WorldAssemblyFixed(params.SDFBlendRadius*ownerToCoreScale);
recipe.roughnessSubvoxels=WorldAssemblyFixed(params.SurfaceRoughness*ownerToCoreScale);
recipe.boundarySealSubvoxels=WorldAssemblyFixed(params.BoundarySealThickness*ownerToCoreScale);
const auto ownerVoxelsToCoreQ=[&](double value)
{return static_cast<std::int64_t>(std::llround(value*owner.OwnerVoxelSizeMicrons
*VoxelForgeCore::WorldAssemblySubvoxelsPerVoxel/owner.CoreVoxelSizeMicrons));};
recipe.anchorIslandOrdinal=recipe.primaryIslandCount-1;
recipe.anchorPlacementRadiusSubvoxels=ownerVoxelsToCoreQ(passage.DistanceMax);
const std::int64_t spiralRadius=ownerVoxelsToCoreQ(passage.SpiralRadius);
const std::int64_t mouthBore=std::max(ownerVoxelsToCoreQ(passage.MouthRadius),
ownerVoxelsToCoreQ(12.0));
const std::int64_t bore=std::max(ownerVoxelsToCoreQ(passage.MidRadius),
ownerVoxelsToCoreQ(12.0));
const std::int64_t wallReserve=ownerVoxelsToCoreQ(12.0);
// Put the mouth near the island rim, with enough island and root around the
// first coil to read as a cave entrance instead of a hole in open air.
recipe.anchorMouthOffsetSubvoxels=spiralRadius+mouthBore+ownerVoxelsToCoreQ(4.0);
const std::int64_t excursion=std::max(ownerVoxelsToCoreQ(passage.Wander),spiralRadius);
recipe.anchorRootRadiusSubvoxels=excursion+bore+wallReserve;
recipe.anchorIslandMinimumRadiusSubvoxels=std::max(recipe.minimumRadiusSubvoxels,
recipe.anchorMouthOffsetSubvoxels+mouthBore+ownerVoxelsToCoreQ(4.0));
recipe.anchorRootBottomZSubvoxels=recipe.layoutMinimumZSubvoxels
+recipe.boundarySealSubvoxels;
auto planned=VoxelForgeCore::PlanFloatingIslandCluster(recipe,error);
if(!planned)return false;
@@ -703,6 +724,21 @@ namespace StandaloneWorldAssemblyPrototype
anchor.kind="island_anchor";anchor.stableId="island/"+std::to_string(n);anchor.units="1/256 Core voxel";
anchor.values={a.centerSubvoxels[0],a.centerSubvoxels[1],a.centerSubvoxels[2],a.radiusSubvoxels,a.topHalfSubvoxels};
s.anchors.push_back(std::move(anchor));
if(n==it->manifest.recipe.anchorIslandOrdinal
&&it->manifest.recipe.geometryVersion>=5)
{
ResolvedLayoutAnchorV2 passageAnchor;
passageAnchor.kind="passage_anchor";
passageAnchor.stableId="passage-anchor/island/"+std::to_string(n);
passageAnchor.units="1/256 Core voxel";
passageAnchor.values={a.centerSubvoxels[0],a.centerSubvoxels[1],
it->manifest.recipe.anchorRootRadiusSubvoxels,
it->manifest.recipe.anchorMouthOffsetSubvoxels,
it->manifest.recipe.anchorPlacementRadiusSubvoxels,
it->manifest.recipe.anchorRootBottomZSubvoxels,
a.radiusSubvoxels};
s.anchors.push_back(std::move(passageAnchor));
}
}
for(std::size_t n=0;n<it->manifest.plan.route.size();++n)
{
@@ -765,13 +801,22 @@ namespace StandaloneWorldAssemblyPrototype
*WorldAssemblySubvoxelsPerVoxel/owner.CoreVoxelSizeMicrons));};
ResolvedLayoutPassageConfigV1 config;config.upperStrateIndex=slot.StrateIndex;
config.connections=authored.Connections;
config.mouthRadiusSubvoxels=ownerVoxelsToCoreQ(authored.MouthRadius);
config.midRadiusSubvoxels=ownerVoxelsToCoreQ(authored.MidRadius);
config.style=static_cast<std::uint32_t>(authored.Style);
config.mouthRadiusSubvoxels=std::max(ownerVoxelsToCoreQ(authored.MouthRadius),
ownerVoxelsToCoreQ(12.0));
config.midRadiusSubvoxels=std::max(ownerVoxelsToCoreQ(authored.MidRadius),
ownerVoxelsToCoreQ(12.0));
config.reachMinimumSubvoxels=ownerVoxelsToCoreQ(authored.ReachMin);
config.reachMaximumSubvoxels=ownerVoxelsToCoreQ(authored.ReachMax);
config.distanceMinimumSubvoxels=ownerVoxelsToCoreQ(authored.DistanceMin);
config.distanceMaximumSubvoxels=ownerVoxelsToCoreQ(authored.DistanceMax);
config.wanderSubvoxels=ownerVoxelsToCoreQ(authored.Wander);
config.segments=static_cast<std::uint32_t>(std::clamp(authored.Segments,1,48));
config.verticalWobbleSubvoxels=ownerVoxelsToCoreQ(authored.VerticalWobble);
config.spiralRadiusSubvoxels=ownerVoxelsToCoreQ(authored.SpiralRadius);
config.spiralTurnsQ16=static_cast<std::int64_t>(std::llround(authored.SpiralTurns*65536.0));
config.cascadeSteps=static_cast<std::uint32_t>(std::clamp(authored.CascadeSteps,1,16));
config.cascadeLedgeSubvoxels=ownerVoxelsToCoreQ(authored.CascadeLedge);
passageConfigs.push_back(config);
}
if(!PlanResolvedLayoutPassagesV1(out,owner.Seed,passageConfigs,error))return false;