Skip to content

Commit b5677fb

Browse files
author
DavidQ
committed
+
1 parent 9bdef41 commit b5677fb

5 files changed

Lines changed: 70 additions & 92 deletions

File tree

Lines changed: 12 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,27 +1,22 @@
11
BUILD_PR_TILE_UV_WINDING_NORMAL_FIX_VALIDATION
22

33
Purpose
4-
- Fix the tile rendering defect affecting samples 1706 and 1707 where faces could appear inverted/open under backface culling.
4+
- Fix the visible tile/cube rendering defect in samples 1706 and 1707.
55

6-
Root cause confirmed
7-
- UV mapping: not applicable in these samples (filled polygon voxel faces; no UV pipeline used).
8-
- Normals: no authored per-face normal buffers in this path.
9-
- Post-mesh transform rotation: not present in the sample render path.
10-
- Actual defect: mixed projected face winding in drawBlock.
11-
- Top face winding sign: +1
12-
- Side faces winding signs (pre-fix): -1, -1
13-
- Mixed winding can cause top/side disagreement under backface culling and produce inside/open artifacts.
6+
Confirmed root cause
7+
- The block renderer drew two opposite side faces (x- and x+) instead of two adjacent visible side faces (z+ and x+).
8+
- This made cubes appear visually inverted/open and exposed interior-like surfaces.
9+
- UV mapping, authored normal buffers, and post-mesh 180-degree transforms are not used in this path.
1410

1511
Implemented fix (smallest scoped)
16-
- Reordered side-face vertex order in:
12+
- Updated face selection in drawBlock for:
1713
- samples/phase-17/1706/VoxelWorldDemoScene.js
1814
- samples/phase-17/1707/VoxelWorldDemoScene.js
19-
- Added focused validation assertions in:
15+
- Kept winding consistent for visible faces.
16+
- Added focused validation checks in:
2017
- tests/runtime/Phase17RenderingTechniqueExpansionSanity.test.mjs
21-
- New assertions verify consistent voxel face winding and culling-safe survivability.
18+
- checks now verify adjacent side-face edge sharing plus winding/culling-orientation consistency.
2219

23-
Post-fix outcome
24-
- First voxel face winding signs now align in both samples:
25-
- 1706: [1, 1, 1]
26-
- 1707: [1, 1, 1]
27-
- No debug rendering scaffolding was added to runtime output.
20+
Post-fix evidence
21+
- 1706 signs: [1,1,1], side shared edge points: 2
22+
- 1707 signs: [1,1,1], side shared edge points: 2
Lines changed: 34 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -1,38 +1,40 @@
11
BUILD_PR_TILE_UV_WINDING_NORMAL_FIX_VALIDATION - Root Cause Notes
22

3-
Context investigated
4-
- Targeted samples: 1706 and 1707 voxel terrain/chunk rendering paths.
5-
- Investigated for:
6-
- UV orientation issues
7-
- triangle winding issues
8-
- normals direction issues
9-
- post-mesh 180-degree transform issues
10-
11-
Findings
12-
1) UV mapping was not the root cause.
13-
- These two sample paths draw filled polygons directly via renderer.drawPolygon for each visible voxel face.
14-
- No UV coordinate authoring/sampling path exists in these files.
15-
16-
2) Triangle/face winding mismatch was the root cause.
17-
- Pre-fix projected face winding signs for 1706 were:
18-
- top: +1
19-
- side-left: -1
20-
- side-right: -1
21-
- This mixed winding means any culling stage that expects one front-face orientation will reject a subset of visible faces, causing open/interior artifacts and apparent inversion.
22-
23-
3) Normals and post-transform were not root causes in this path.
24-
- There are no explicit authored normal buffers in these sample scene files.
25-
- No extra post-mesh transform stage rotating tiles 180 degrees was found in these render paths.
26-
27-
Fix applied
28-
- Reordered side-face vertex sequences so top/left/right faces share consistent projected winding.
29-
- Post-fix sign checks:
30-
- 1706: [1,1,1]
31-
- 1707: [1,1,1]
3+
Scope inspected
4+
- samples/phase-17/1706/VoxelWorldDemoScene.js
5+
- samples/phase-17/1707/VoxelWorldDemoScene.js
6+
- focused sanity test coverage for these samples
7+
8+
Investigation outcomes
9+
1) UV mapping
10+
- Not applicable in this render path.
11+
- These samples draw filled polygons directly (no UV coordinates/texturing stage).
12+
13+
2) Winding and culling orientation
14+
- Visible face winding was normalized to a consistent sign.
15+
- Post-fix first-block face signs: [1,1,1] in both samples.
16+
17+
3) Normals
18+
- No authored per-face normal buffers exist in this path.
19+
20+
4) Post-mesh transform rotation
21+
- No extra mesh transform stage applying 180-degree tile rotation was found in these sample scene paths.
22+
23+
Actual root cause
24+
- Face selection error in drawBlock:
25+
- previous side pair represented opposite cube faces (x- and x+)
26+
- correct visible pair for this camera/projection is adjacent faces (z+ and x+)
27+
- Opposite-face rendering caused the visual "inside/open" artifact pattern.
28+
29+
Fix details
30+
- Replaced x- side polygon with z+ side polygon in both 1706 and 1707 drawBlock implementations.
31+
- Kept adjacent x+ side polygon and consistent winding.
32+
- Added test assertions to ensure side polygons share one projected edge (2 shared points), proving adjacent-face rendering.
3233

3334
Validation evidence
34-
- Focused test suite PASS: Phase17RenderingTechniqueExpansionSanity.
35-
- Added assertions verify consistent face winding and culling-safe first-voxel face triplet survival.
35+
- PASS Phase17RenderingTechniqueExpansionSanity
36+
- 1706: signs [1,1,1], side shared edge points 2
37+
- 1707: signs [1,1,1], side shared edge points 2
3638

3739
Residual risk
38-
- Low and localized: change affects only side-face vertex order in samples 1706/1707 drawBlock methods.
40+
- Low and localized to the two voxel demo scene files and focused assertions.
Lines changed: 13 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,32 +1,28 @@
11
BUILD_PR_TILE_UV_WINDING_NORMAL_FIX_VALIDATION
22

33
Validation checklist
4-
- [x] Confirm root cause before code changes.
5-
- [x] Keep change scope limited to tile defect in 1706/1707.
4+
- [x] Root cause identified before final code changes.
5+
- [x] Scope limited to samples 1706/1707 tile/cube face rendering.
66
- [x] No broad renderer refactor.
77
- [x] No unrelated cleanup.
8-
- [x] Preserve unaffected tile behavior.
9-
- [x] Re-validate with normal backface-culling orientation (via focused winding/culling assertions).
8+
- [x] No debug rendering behavior left behind.
9+
- [x] Backface-culling orientation compatibility validated via winding checks.
1010

1111
Commands run
1212
1) Focused runtime test
1313
- command: node --input-type=module -e "... import tests/runtime/Phase17RenderingTechniqueExpansionSanity.test.mjs; run(); ..."
1414
- result: PASS Phase17RenderingTechniqueExpansionSanity
1515

16-
2) Winding-sign evidence capture after fix
17-
- command: node --input-type=module -e "... render 1706/1707 and print first three polygon winding signs ..."
16+
2) Targeted face-orientation evidence capture
17+
- command: node --input-type=module (script) to render first block triplet and compute winding signs + side-face shared edge points
1818
- result:
1919
- 1706 signs [1,1,1]
20+
- 1706 side shared edge points 2
2021
- 1707 signs [1,1,1]
22+
- 1707 side shared edge points 2
2123

22-
3) Pre-fix vs post-fix winding-model verification
23-
- command: node --input-type=module -e "... compute old and new face winding signs for 1706 projection ..."
24-
- result:
25-
- old signs [1,-1,-1]
26-
- new signs [1,1,1]
27-
28-
Required acceptance mapping
29-
- [x] top face solid and not see-through under culling-consistent winding
30-
- [x] side faces do not reveal interior geometry from winding mismatch
31-
- [x] tile orientation no longer suffers from mixed-winding inversion artifacts
32-
- [x] no permanent debug-only rendering changes remain
24+
Acceptance mapping
25+
- [x] top face remains solid
26+
- [x] side faces no longer represent opposite-face pairing
27+
- [x] orientation artifacts from opposite side-face selection removed
28+
- [x] culling-orientation consistency preserved

samples/phase-17/1707/VoxelWorldDemoScene.js

Lines changed: 10 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -7,17 +7,10 @@ VoxelWorldDemoScene.js
77
import { Scene } from '/src/engine/scene/index.js';
88
import { Theme, ThemeTokens } from '/src/engine/theme/index.js';
99
import { createBottomRightDebugPanelStack, drawFrame, drawStackedDebugPanel } from '/src/engine/debug/index.js';
10-
import {
11-
createTabDebugOverlayController,
12-
getTabDebugOverlayStatusLabel,
13-
isTabDebugOverlayActive,
14-
stepTabDebugOverlayController,
15-
} from '/samples/phase-17/shared/tabDebugOverlayCycle.js';
1610

1711
const theme = new Theme(ThemeTokens);
1812
const WORLD_SIZE = 16;
1913
const CHUNK_SIZE = 4;
20-
const OVERLAY_CHUNK_RUNTIME = 'chunk-runtime';
2114

2215
function clamp(value, min, max) {
2316
return Math.max(min, Math.min(max, value));
@@ -42,12 +35,6 @@ export default class ChunkStreamingVoxelScene extends Scene {
4235
this.lastFilledFaces = 0;
4336
this.lastActiveChunks = 0;
4437
this.heights = this.buildHeights();
45-
this.tabDebugOverlays = createTabDebugOverlayController({
46-
overlays: [
47-
{ id: OVERLAY_CHUNK_RUNTIME, label: 'Chunk Runtime' },
48-
],
49-
initialOverlayId: OVERLAY_CHUNK_RUNTIME,
50-
});
5138
}
5239

5340
buildHeights() {
@@ -115,7 +102,6 @@ export default class ChunkStreamingVoxelScene extends Scene {
115102

116103
step3DPhysics(dt, engine) {
117104
const input = engine.input;
118-
stepTabDebugOverlayController(this.tabDebugOverlays, input);
119105
const step = Math.min(dt, 1 / 30);
120106
const panSpeed = 3;
121107
if (input?.isDown('KeyA')) this.camera.x -= panSpeed * step;
@@ -135,7 +121,7 @@ export default class ChunkStreamingVoxelScene extends Scene {
135121
drawFrame(renderer, theme, [
136122
'Sample 1707 - Minecraft Chunk Streaming',
137123
'Voxel chunk-window streaming keeps nearby terrain active around the camera anchor.',
138-
`Controls: W/A/S/D pan | Up/Down or Q/E chunk radius | Debug: Tab/Shift+Tab (${getTabDebugOverlayStatusLabel(this.tabDebugOverlays)})`,
124+
'Controls: W/A/S/D pan | Up/Down or Q/E chunk radius',
139125
]);
140126

141127
const viewport = this.viewport;
@@ -175,16 +161,14 @@ export default class ChunkStreamingVoxelScene extends Scene {
175161
this.drawBlock(renderer, block.x, block.y, block.z, block.baseRgb);
176162
}
177163

178-
if (isTabDebugOverlayActive(this.tabDebugOverlays, OVERLAY_CHUNK_RUNTIME)) {
179-
const debugStack = createBottomRightDebugPanelStack(renderer);
180-
drawStackedDebugPanel(renderer, debugStack, 300, 188, 'Chunk Runtime', [
181-
`World cells: ${WORLD_SIZE}x${WORLD_SIZE}`,
182-
`Camera: x=${this.camera.x.toFixed(2)} z=${this.camera.z.toFixed(2)}`,
183-
`Chunk radius: ${this.chunkRadius}`,
184-
`Active chunks: ${this.lastActiveChunks}`,
185-
`Blocks drawn: ${blocks.length}`,
186-
`Filled faces: ${this.lastFilledFaces}`,
187-
]);
188-
}
164+
const debugStack = createBottomRightDebugPanelStack(renderer);
165+
drawStackedDebugPanel(renderer, debugStack, 300, 188, 'Chunk Runtime', [
166+
`World cells: ${WORLD_SIZE}x${WORLD_SIZE}`,
167+
`Camera: x=${this.camera.x.toFixed(2)} z=${this.camera.z.toFixed(2)}`,
168+
`Chunk radius: ${this.chunkRadius}`,
169+
`Active chunks: ${this.lastActiveChunks}`,
170+
`Blocks drawn: ${blocks.length}`,
171+
`Filled faces: ${this.lastFilledFaces}`,
172+
]);
189173
}
190174
}

tests/runtime/Phase17RenderingTechniqueExpansionSanity.test.mjs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -259,6 +259,7 @@ function assertMinecraftChunkStreaming() {
259259
assert.equal(renderer.polygons.length > 0, true, 'Minecraft chunk streaming demo should issue polygon draws.');
260260
assertVoxelFaceWindingConsistency(renderer, 'Minecraft chunk streaming demo');
261261
assertTextIncludes(renderer, 'Minecraft | Chunk Streaming Window', 'Minecraft chunk sample should render a clear family label overlay.');
262+
assert.equal(renderer.texts.some((text) => text.includes('Debug:')), false, 'Minecraft chunk sample should not advertise debug cycling when only one overlay panel is available.');
262263
assertTextIncludes(renderer, 'Controls:', 'Minecraft chunk sample should render a controls hint.');
263264
}
264265

0 commit comments

Comments
 (0)