Skip to content

feat(pbr): expand LabPBR 1.3 material properties matrix (#53) - #231

Merged
BharathASL merged 2 commits into
mainfrom
feat/pbr-material-matrix
Sep 24, 2026
Merged

BharathASL merged 2 commits into
mainfrom
feat/pbr-material-matrix

Conversation

@BharathASL

@BharathASL BharathASL commented Sep 23, 2026 •

Copy link
Copy Markdown
Contributor

Description

Expands tools/lib/pbr-rules.json with LabPBR 1.3 physical and optical properties for stone and deepslate ores, metal blocks, minerals and masonry, and architectural blocks, so the _n/_s pipeline from #186/#187 produces material-specific maps beyond the initial stone, ore and soil set.

Refs #53

  • Stem keys: resolveMaterial matches the texture stem the build derives from the master filename, and masters are named after vanilla textures. Every exact material key is either a vanilla 1.21.6 block texture stem or a pattern target. Vanilla ships no quartz_block, smooth_quartz, basalt or polished_basalt texture, so those faces resolve through quartz_block_*, basalt_* and polished_basalt_* patterns, and blackstone_top through blackstone_*. smooth_quartz is removed: the block reuses quartz_block_bottom.
  • Dielectric F0: the specular green channel stores F0 linearly (0–229 = F0 × 255, LabPBR 1.3). Values are derived from refractive index as ((n-1)/(n+1))^2 * 255: soda-lime glass and tinted glass n = 1.52 → 11; quartz block and amethyst (quartz, nω = 1.544) → 12; obsidian and crying obsidian (volcanic glass, n ≈ 1.49) → 10; emerald gem pixels (beryl, n ≈ 1.57) → 13. Diamond gem pixels keep the 40–50 range shared with diamond_ore on main, which brackets the IOR-derived 44 (n = 2.417).
  • Ores: iron, copper, gold, redstone, emerald, lapis and their deepslate variants, plus deepslate_diamond_ore and deepslate_coal_ore. Where only part of the face differs (redstone dust, emerald and diamond gems), the distinct properties live in colorFeatures alongside host-rock features. Iron, copper, gold, lapis and deepslate coal ores have no vector masters yet, so there are no mineral colours to key; the whole face keeps host-rock F0 10 until each master lands with its own colorFeatures.
  • Emission: redstone ore (host and dust) and all diamond and emerald gem pixels in this PR are at emission 0. Lit and unlit redstone ore share one texture and the unlit state does not glow in vanilla; diamond and emerald ore do not glow either. Crying obsidian base emission is 0 and only tear pixels carry emission 60–180 via colorFeatures (vanilla crying obsidian emits light level 10 at all times).
  • Metals: green-channel hardcoded metal IDs per LabPBR 1.3: iron block 230, gold block 231, copper block 234. Netherite uses 255 (albedo-driven metal) because LabPBR has no netherite preset; 237 is silver. Raw iron, gold and copper blocks are ore chunks with dark crevices, so they stay dielectric (F0 10) rather than applying a metal ID to every pixel.
  • Minerals & masonry: quartz block faces, basalt faces, polished basalt faces, smooth basalt, blackstone and its top face, polished blackstone, obsidian, crying obsidian, amethyst block, tuff, polished tuff, calcite.
  • Architectural: glass, tinted glass, terracotta, glazed terracotta (glossy, porosity 0), concrete and concrete powder (granular, porosity 45). *_glazed_terracotta and *_concrete_powder patterns are declared ahead of the generic *terracotta* and *concrete* globs; *glass* covers stained glass.
  • Tests: tools/test/fixtures/vanilla-1.21.6-block-stems.txt lists the assets/minecraft/textures/block stems of the 1.21.6 client jar. tools/test/pbr-generator.test.mjs checks that every exact material key is a vanilla stem or a pattern target, that every pattern matches at least one vanilla stem, and that every stem it resolves is a real vanilla stem. Dielectric F0 assertions are computed from the cited refractive indices. Pixel-level specular packing covers tear emission, the non-emissive obsidian matrix, redstone dust and host at emission 0, gem pixels at gem F0 and emission 0 with host pixels at F0 10, raw gold packing dielectric green 10, and netherite packing green 255.
  • CHANGELOG.md [Unreleased] entry added.

The colorFeatures hex keys for redstone, emerald and crying obsidian approximate vanilla colours; no vector masters exist for those blocks yet, so the keys should be re-matched against the palette when the masters are authored. Pixels outside the 64-unit match tolerance fall back to the host-rock base values, which are non-emissive.

Affected Assets

  • tools/lib/pbr-rules.json
  • tools/test/pbr-generator.test.mjs
  • tools/test/fixtures/vanilla-1.21.6-block-stems.txt
  • CHANGELOG.md

Type of Change

  • feat: New vector texture master, blockstate, or compiler capability
  • fix: Tiling fix, palette correction, or bugfix
  • docs: Documentation improvement
  • chore / refactor: Maintenance, dependencies, or codebase cleanup

Contributor Checklist

Please check all applicable boxes before requesting review:

Vector Texture Standards (if adding/modifying SVGs)

  • Authored as a clean $512\times512$ SVG (viewBox="0 0 512 512"). Not applicable: no SVG masters changed.
  • Primary shapes are aligned to the $32\text{px}$ texel grid ($16\times16$ grid). Not applicable: no SVG masters changed.
  • Seamless Toroidal Tiling: Checked and verified that elements wrapping across $X$ and $Y$ edges align perfectly without seams or chopped shapes. Not applicable: no SVG masters changed; the tiling audit in npm test passes.
  • Ore Consistency: If adding an ore texture, the stone background geometry and corner radius (rx) match textures/block/stone.svg exactly. Not applicable: no ore textures added.
  • Free of leftover AI generation comments, unnecessary editor namespaces, or embedded raster images.

Build & Verification

  • Ran npm run build locally and verified that the pack compiles successfully.
  • Verified textures in-game or inspected the rasterized PNG outputs in dist/. Not done in-game; specular channel values are verified by npm test (test:pbr).

Git Hygiene & Standards

  • Commit message(s) follow Conventional Commits (e.g., feat(textures): ...).
  • Every commit is signed off with the Developer Certificate of Origin (git commit -s).
  • Branch is rebased cleanly onto latest main with no merge commits.
  • Formatting complies with .editorconfig (2-space indent, LF endings, trailing newline).

@ninja6-agent ninja6-agent Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Blockers

  • tools/lib/pbr-rules.json:L456: netherite_block uses f0: 237, which is the LabPBR 1.3 hardcoded metal ID for silver (230 iron, 231 gold, 232 aluminum, 233 chrome, 234 copper, 235 lead, 236 platinum, 237 silver). Shaderpacks will render netherite with silver's complex IOR. LabPBR has no netherite preset; use 255 (albedo-driven metal) and update the assertions at tools/test/pbr-generator.test.mjs:L301 and :L614.
  • tools/lib/pbr-rules.json:L339, :L381, :L521: redstone_ore, deepslate_redstone_ore and crying_obsidian set a flat emission: 180 with no colorFeatures. evaluatePixel in tools/lib/pbr-generator.mjs applies the material value to every opaque pixel when no feature matches, so the whole face emits, including the stone, deepslate and obsidian matrix. Only the dust and tear pixels should glow. Scope emission to colorFeatures keyed to those pixels, the way diamond_ore does, and keep the base emission at 0. Unlit redstone ore also does not glow in vanilla, and both block states share one texture, so emission on redstone_ore needs a stated rationale or should stay at 0.
  • PR body: the PR does not use the repository's pull_request_template.md. The Description, Related Issues, Type of Change and Checklist sections are all missing (.github/CONTRIBUTING.md §4.3), and no issue is linked. Restore the template and link the tracking issue.

Nits

  • tools/lib/pbr-rules.json:L344, :L400: emerald_ore (f0: 40) and deepslate_diamond_ore (f0: 48) apply gem reflectance to the entire block, including the host rock. The gem F0 belongs in colorFeatures, matching diamond_ore, with host-rock F0 around 10–14 for the rest of the face.
  • tools/lib/pbr-rules.json:L610, :L614: *terracotta* also catches *_glazed_terracotta (glossy glaze, not porosity 15 / smoothness 30), and *concrete* catches *_concrete_powder (loose granular, not smoothness 50 / porosity 2). Add explicit patterns for those ahead of the generic ones, or narrow the globs.
  • tools/lib/pbr-rules.json:L11: the normalStrength change from 1.0 to 1 is an unrelated reformat. Revert it to keep the diff scoped.
  • CHANGELOG.md: no [Unreleased] entry for the material matrix, unlike the preceding feature PRs.

Scope gem F0 and crying obsidian emission to colorFeatures; netherite
uses albedo-driven metal 255.

Signed-off-by: Bharath <bharathasl74185@gmail.com>
@BharathASL
BharathASL force-pushed the feat/pbr-material-matrix branch from 5c31233 to 68904d4 Compare September 23, 2026 19:16
@BharathASL BharathASL changed the title feat(pbr): expand LabPBR 1.3 material physical properties matrix feat(pbr): expand LabPBR 1.3 material properties matrix (#53) Sep 23, 2026

@ninja6-agent ninja6-agent Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Blockers

  • tools/lib/pbr-rules.json:L758, :L765, :L772, :L779, :L793: resolveMaterial matches the texture stem exactly (tools/lib/pbr-generator.mjs:L210), and tools/build.mjs:L311 passes vanilla texture names as that stem. Vanilla ships quartz_block_side/top/bottom, basalt_side/top and polished_basalt_side/top. It has no quartz_block, smooth_quartz, basalt or polished_basalt texture, and smooth quartz reuses quartz_block_bottom. None of those four entries can ever apply. They fall back to defaultMaterial, and so does blackstone_top. Key them to the real stems, either with exact entries or with patterns such as quartz_block_*, basalt_* and polished_basalt_*. Drop smooth_quartz, and point the tests at tools/test/pbr-generator.test.mjs:L325-L352 to real stems. Right now they pass only because they query names the build never produces.
  • tools/lib/pbr-rules.json:L410, :L418, :L426, :L434, and the same entries at :L568-L592: the LabPBR 1.3 green channel is linear F0 (value/255). F0 36–42 is F0 0.14–0.16, which works out to IOR 2.2–2.4, the reflectance of diamond. Emerald (beryl, n ≈ 1.57) has F0 ≈ 0.050, which is about 13. As written, emerald gems render with diamond-level reflectance. Derive the value from IOR, ((n-1)/(n+1))^2 * 255, and update the assertions at tools/test/pbr-generator.test.mjs:L685 and the f0 >= 36 checks.
  • tools/lib/pbr-rules.json:L903, :L910, :L761, :L768, :L810, :L817, :L825-L866, :L875: the same F0 problem affects the dielectrics. 16 is IOR ≈ 1.67 and 22 is IOR ≈ 1.83. Soda-lime glass (n ≈ 1.52) should be about 11, quartz and amethyst (n ≈ 1.54) about 12, and obsidian (n ≈ 1.49) about 10. Amethyst at 22 is almost double the correct reflectance. Correct the values and the matching assertions at tools/test/pbr-generator.test.mjs:L327, :L332, :L358, :L363, :L373, :L392, :L397, :L429, :L668, :L698 and :L703.

Nits

  • tools/lib/pbr-rules.json:L642-L674: deepslate_diamond_ore gem pixels emit 10–35. Diamond ore does not glow in vanilla, and this contradicts the rationale the PR gives for keeping redstone and emerald at emission 0. Set gem emission to 0 here, or state why diamond is the exception.
  • tools/lib/pbr-rules.json:L709-L742: raw_iron_block, raw_gold_block and raw_copper_block apply hardcoded metal IDs to every opaque pixel. Raw iron is ore chunk (dielectric), and the dark crevices on all three textures are not bare metal. Use dielectric F0 as the base and scope the metal ID to highlight colorFeatures, or keep them dielectric.
  • tools/lib/pbr-rules.json:L316, :L323, :L330, :L475, :L482, :L489, :L496, :L625, :L705: the iron, copper, gold, lapis and coal ores, including their deepslate variants, have no colorFeatures. Their elevated F0 (12–15) therefore also covers the host rock, which is the problem this PR fixed for emerald and diamond. Either scope it the same way or keep the host at 10.
  • PR history: the reviewed commit 5c31233 was replaced by a force-push to 68904d4 during active review. .github/CONTRIBUTING.md §4 requires fixes as separate signed-off commits on top. Push later iterations as new commits.

…m IOR

Signed-off-by: Bharath <bharathasl74185@gmail.com>
@BharathASL

Copy link
Copy Markdown
Contributor Author
  • Resolved in f0626d4: stem keys. Checked against assets/minecraft/textures/block in the 1.21.6 client jar: no quartz_block, smooth_quartz, basalt or polished_basalt texture exists. Faces now resolve via quartz_block_*, basalt_*, polished_basalt_* and blackstone_* (covers blackstone_top); smooth_quartz dropped. Added tools/test/fixtures/vanilla-1.21.6-block-stems.txt and a test that every exact key is a vanilla stem or pattern target and every pattern matches a vanilla stem; the resolution tests now query real stems only.
  • Resolved in f0626d4: gem F0. Emerald gem pixels 36–42 → 13 (beryl n ≈ 1.57), derived as ((n-1)/(n+1))^2 * 255; assertions compute the value from n.
  • Resolved in f0626d4: dielectric F0. Glass and tinted glass 16 → 11 (n = 1.52), quartz block 16 → 12 and amethyst 22 → 12 (n = 1.544), obsidian and crying obsidian (base and features) 16 → 10 (n ≈ 1.49).
  • Resolved in f0626d4: deepslate_diamond_ore gem emission set to 0. diamond_ore emission predates this PR on main and is left as is here.
  • Resolved in f0626d4: raw iron, gold and copper blocks are dielectric (F0 10); no masters exist yet to key highlight colours for a scoped metal ID.
  • Resolved in f0626d4: iron, copper, gold, lapis ores, their deepslate variants and deepslate_coal_ore keep host-rock F0 10 across the face; no masters exist to key mineral colours.
  • PR history: noted. This iteration is a new signed-off commit on top of 68904d4, plain push.

@ninja6-agent ninja6-agent Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Blockers

None.

Nits

  • tools/lib/pbr-rules.json:L640, :L648, :L656, :L664, :L672: deepslate_diamond_ore gem F0 values are 44, 48, 48, 50 and 40. Only 44 comes from n = 2.417. The others are copied from diamond_ore and work out to n ≈ 2.3–2.6. CHANGELOG.md:L19-L20 says gem F0 is derived from refractive index, so either set every gem feature to 44 or change the entry to say only emerald is derived.
  • tools/lib/pbr-rules.json:L889, :L917: calcite and glazed terracotta use F0 14 (n ≈ 1.61). Nothing states where that value comes from, unlike glass, quartz and obsidian. Calcite averaged over nω/nε ≈ 1.57 gives 13, and a silicate glaze at n ≈ 1.5 gives 10–11. Either derive these values or name the source in the PR.
  • .gitattributes:L11: *.txt has no rule, so on Windows with core.autocrlf the new tools/test/fixtures/vanilla-1.21.6-block-stems.txt checks out with CRLF, which conflicts with .editorconfig's end_of_line = lf. The index copy is LF and the test splits on \r?\n, so nothing breaks. Add *.txt text eol=lf.

@BharathASL
BharathASL added this pull request to the merge queue Sep 24, 2026
Merged via the queue into main with commit ff92e57 Sep 24, 2026
5 checks passed
@BharathASL
BharathASL deleted the feat/pbr-material-matrix branch September 24, 2026 02:49
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.

1 participant