arkavo-org / arkavo-org/VRMMetalKit
GLTFMetalKit: MikkTSpace tangent generation for normal-mapped meshes without authored TANGENT
- Dominant language
- Swift
- Stars
- 6
- Forks
- 2
- Avg merge
- 18h 51m
- Merged PRs (30d)
- 26
Description
## Context
glTF 2.0 §3.6.2 mandates that when a mesh has a `NORMAL` attribute and is rendered with a normal-mapped material but lacks a `TANGENT` attribute, the renderer must generate tangents using the [MikkTSpace algorithm](http://www.mikktspace.com/). This is required for cross-renderer consistency — Khronos sample assets like `NormalTangentMirrorTest` depend on it.
Current behaviour: `Sources/GLTFMetalKit/Loader/GLTFAssetLoader.swift:763` falls back to a default `(1, 0, 0, 1)` per-vertex tangent when `TANGENT` is absent. This is correct for assets without normal mapping but produces wrong shading on assets that need generated tangents.
Surfaced in PR #241 (GLTFMetalKit introduction). The compliance gap is documented in that PR's body and was deemed not blocking the initial MVP.
## What's needed
- Port MikkTSpace to Swift (or wrap a C implementation; the canonical reference is at ).
- Wire it into `makePrimitive` so that when a primitive's material references a normal map AND `TANGENT` is absent, run MikkTSpace over the indexed triangle list to produce per-vertex tangents.
- Caveat: MikkTSpace operates per-triangle and produces tangents that depend on UV winding. Skip generation when `TEXCOORD_0` is also missing (degenerate).
## Acceptance
- `NormalTangentMirrorTest.glb` from `glTF-Sample-Assets` renders identical (within tolerance) to the Khronos reference renderer.
- Existing test corpus continues to pass — non-normal-mapped assets must still avoid the generator path (it's not cheap).
## Estimate
~500 LOC of careful tangent-space math, plus a test or two against the mirror-test fixture. No readily-available Swift port; either a fresh implementation or a C bridge.
Contributor guide
Research direction
Start at Sources/GLTFMetalKit/Loader/GLTFAssetLoader.swift:763 and trace makePrimitive, then review how normal maps, NORMAL, TANGENT, TEXCOORD_0, and indexed triangles are represented. Use NormalTangentMirrorTest.glb and the existing test corpus as validation; done means matching the Khronos reference within tolerance while preserving the non-normal-mapped path.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- swift
- Domain
- computer-graphics
- Issue type
- Feature
- Difficulty
- 5/5
- Estimated time
- Over a week
- Activity status
- Quiet
- Clarity
- Clearly specified
- Newbie friendliness
- 48/100