Skip to content

fix(oot): mesh shader primitive outputs read from the primitive blocks (Forest Temple paintings, chain v28) - #2166

Merged
ly05010419 merged 1 commit into
ly05010419:mainfrom
victormlourenco:fix/oot-paintings
Nov 14, 2026
Merged

ly05010419 merged 1 commit into
ly05010419:mainfrom
victormlourenco:fix/oot-paintings

Conversation

@victormlourenco

Copy link
Copy Markdown
Contributor

Summary

  • Bug: The Metal mesh export read the guest's mesh output area as interleaved vertex and primitive blocks. The guest actually stores all vertex blocks first, then all primitive blocks. Shaders with no primitive outputs, or with a single 32-entry block, got the same addresses either way. Bigger meshes (e.g. 128 vertices / 64 primitives) read every vertex from 32 on, and every primitive output, from the wrong words.
  • What players saw: The Forest Temple paintings (mesh ee4ef51a, fragment a75838cd: about 12,000 brush strokes, each coloured by a primitive output) showed up black, or green from uninitialised memory.
  • Fix: MeshStage.cs now uses separate vertex and primitive strides, and the primitive base sits after all vertex blocks.
  • Chain: The OOT chain goes to v28 (oot-native-v28-mesh-primitive-blocks) so cached mesh translations are rebuilt. It keeps main's v27 blend-zero guard. test_oot_blend_zero now accepts any chain from v27 up, as long as the line still names nvn_blend_zero.h.
  • Binaries: Prebuilt totk_xlate and oot_write_proof.dylib are rebuilt; checksums updated.

Tests

  • test_oot_blend_zero, test_shader_scope, test_shader_startup_memory pass.

🤖 Generated with Claude Code

…s (Forest Temple paintings, chain v28)

The guest's mesh attribute area holds every vertex block first, then every
primitive block: vertex component k of vertex v at output + (v/32)*V*32 + k*32
+ v%32, primitive component k of primitive p at output + blocks*V*32 +
(p/32)*P*32 + k*32 + p%32. The Metal export read them interleaved, (V+P)*32
words a block with the primitive rows after each vertex block. That gives the
same addresses for a shader without primitive outputs or with a single block,
but for 128 vertices / 64 primitives every vertex from 32 on and every
primitive output came from the wrong words.

Ocarina of Time's Forest Temple paintings (task 2d324024, mesh ee4ef51a,
fragment a75838cd: 12,000 brush strokes, each coloured from the Poe picture as
a primitive output) were black or showed uninitialised memory (green).

The OOT chain goes to v28 (oot-native-v28-mesh-primitive-blocks) so cached
mesh translations are made again; v27's blend-zero guard is kept.
test_oot_blend_zero's chain check now accepts v27 or later as long as the line
still names nvn_blend_zero.h. Prebuilt totk_xlate and oot_write_proof.dylib
rebuilt with the fix.

Tests: test_oot_blend_zero, test_shader_scope, test_shader_startup_memory.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@ly05010419
ly05010419 merged commit ff3d9f3 into ly05010419:main Nov 14, 2026
1 check passed

Copy link
Copy Markdown
Owner

已合并并推送,原作者提交完整保留。补充提交:e44ad81b。

按预编译工具规范,用仓库源码和固定 .NET SDK 重建 totk_xlate / oot_write_proof,再替换为本机构建产物。同一批 970 个实际着色器请求(含 500 mesh、20 task)回放,3,880 份 MSL/SPIR-V/反射文件逐字节一致;write-proof 的 144 份回复也一致。新增原生布局回归覆盖多 block、单 block、无 primitive outputs 等形态,旧二进制负对照失败、新版通过。

本轮没有进入森林神殿做画面验收。谢谢修复。

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants