Trim cross corner sidewalk tip and fix outer arc skirt

Drop the sidewalk fan to (±jr,±jr) that made a sharp property-corner
spike, and emit a walk-height sidewalk vertical on the outer gray arc
so the skirt faces render instead of showing through.

Co-authored-by: 西风逍遥游 <sunxfancy@gmail.com>
This commit is contained in:
Cursor Agentand西风逍遥游 committed 2026-09-18 13:51:06 +00:00
1 parent 3bebb8704c
commit c83da07ee4
2 files changed
+18 -9

No files matched your search

+7 -7
View File
@@ -574,24 +574,24 @@ Result<void> bakeJunction(MeshBuild& mesh, const RoadNetwork& network, const Roa
const V3 b1 = arcPt(r1, t1);
const V3 c0 = arcPt(r2, t0);
const V3 c1 = arcPt(r2, t1);
// Toward the outer corner center (sidewalk side).
// Toward the outer corner center (property side) / toward asphalt.
const V3 inToCorner = normalize(V3{cx - a0.x, 0.f, cz - a0.z});
const V3 outToRoad = inToCorner * -1.f;
// Tops: asphalt-face → curb → sidewalk → corner disk, all +Y.
// Tops: asphalt-face → curb → sidewalk ring. No fan to (jr,jr) —
// that disk tip is the sharp property-corner spike.
appendOrientedQuad(mesh, V3{a0.x, curbTop, a0.z}, V3{b0.x, curbTop, b0.z},
V3{b1.x, curbTop, b1.z}, V3{a1.x, curbTop, a1.z}, upN, 0.f, 1.f, 0.f, 1.f,
RoadMaterial::Curb);
appendOrientedQuad(mesh, V3{b0.x, walkY, b0.z}, V3{c0.x, walkY, c0.z}, V3{c1.x, walkY, c1.z},
V3{b1.x, walkY, b1.z}, upN, 0.f, 1.f, 0.f, 1.f, RoadMaterial::Sidewalk);
appendOrientedTri(mesh, V3{cx, walkY, cz}, V3{c0.x, walkY, c0.z}, V3{c1.x, walkY, c1.z}, upN,
RoadMaterial::Sidewalk);
// Vertical curb face toward asphalt / toward corner.
// Vertical curb toward asphalt; sidewalk skirt on the outer gray arc.
appendOrientedQuad(mesh, V3{a0.x, y, a0.z}, V3{a1.x, y, a1.z}, V3{a1.x, curbTop, a1.z},
V3{a0.x, curbTop, a0.z}, outToRoad, 0.f, 1.f, 0.f, 1.f, RoadMaterial::Curb);
appendOrientedQuad(mesh, V3{c0.x, y, c0.z}, V3{c1.x, y, c1.z}, V3{c1.x, curbTop, c1.z},
V3{c0.x, curbTop, c0.z}, inToCorner, 0.f, 1.f, 0.f, 1.f, RoadMaterial::Curb);
appendOrientedQuad(mesh, V3{c0.x, y, c0.z}, V3{c1.x, y, c1.z}, V3{c1.x, walkY, c1.z},
V3{c0.x, walkY, c0.z}, inToCorner, 0.f, 1.f, 0.f, 1.f,
RoadMaterial::Sidewalk);
}
}
}
+11 -2
View File
@@ -327,9 +327,11 @@ TEST_CASE("procgen.road.scenes.crossJunctionCornerSidewalks") {
CHECK_GE(sidewalkGroup, 0);
auto sw = baked.value().mesh.copyGroup(sidewalkGroup);
REQUIRE(sw);
// Outward-center curb returns: sidewalks sit near (jr,jr) inside the corner disk.
// Outward-center curb returns: sidewalk ring around (jr,jr), no tip disk to the center.
const float jr = hubJr;
int arcHits = 0;
int tipHits = 0;
int outerSkirtHits = 0;
for (int i = 0; i < sw->getVertexCount(); ++i) {
const float x = std::fabs(sw->getPositionX(i));
const float z = std::fabs(sw->getPositionZ(i));
@@ -337,10 +339,17 @@ TEST_CASE("procgen.road.scenes.crossJunctionCornerSidewalks") {
const float dz = jr - z;
if (dx < 0.05f || dz < 0.05f) continue;
const float r = std::sqrt(dx * dx + dz * dz);
// Between sidewalk outer and curb face radii from the outer corner center.
// Sidewalk annulus between outer skirt and curb (no fan into r≈0 tip).
if (r > 0.9f && r < 2.9f) ++arcHits;
if (r < 0.55f) ++tipHits;
const float nx = sw->getNormalX(i);
const float nz = sw->getNormalZ(i);
// Outer skirt faces toward the property corner (±jr,±jr).
if (r > 0.7f && r < 1.4f && (nx * dx + nz * dz) > 0.3f) ++outerSkirtHits;
}
CHECK_GT(arcHits, 16);
CHECK_EQ(tipHits, 0);
CHECK_GT(outerSkirtHits, 8);
// Top faces must carry +Y normals (mesh3D CCW / lighting); flipped windings show dark.
int upHits = 0, downHits = 0;