Skip to content

Fix inverted normal mapping on WebGPU (derivative TBN)#9099

Merged
mvaligursky merged 1 commit into
mainfrom
mv-webgpu-tangents-tbnbasis
Jul 22, 2026
Merged

Fix inverted normal mapping on WebGPU (derivative TBN)#9099
mvaligursky merged 1 commit into
mainfrom
mv-webgpu-tangents-tbnbasis

Conversation

@mvaligursky

@mvaligursky mvaligursky commented Jul 22, 2026

Copy link
Copy Markdown
Contributor

Fixes #5735, fixes #6984, fixes #8905 — inverted normal-mapped lighting on WebGPU for meshes that have no vertex tangents (the tangent frame is derived from screen-space derivatives). Confirmed against the Khronos NormalTangentTest — WebGPU now matches WebGL2 and the reference. (#6984 and #8905 are duplicate reports of the same issue.)

Cause:

  • The derivative-based TBN in TBN.js is scaled by the tbnBasis uniform, which was set purely from the render target's flipY (originally added to correct offscreen render-to-texture on WebGL).
  • On WebGPU, framebuffer space is Y-down, so screen-space dpdy has the opposite sign to WebGL's dFdy. This negates the computed tangent and bitangent, rotating the tangent-space normal 180° and producing inverted lighting.
  • Meshes with vertex tangents (world-space TBN) were unaffected, which is why only some content showed the problem.

Changes:

  • Renderer.setCameraUniforms: fold the backend into the tbnBasis sign — (device.isWebGPU !== !!flipY) ? -1 : 1. WebGL behavior is unchanged; WebGPU picks up the extra inherent flip.

Notes:

  • No effect on meshes using vertex tangents.
  • No public API changes.

The derivative-based tangent frame (TBN.js) is scaled by the tbnBasis
uniform, which only accounted for the projection Y flip applied when
rendering with flipY. On WebGPU, screen-space dpdy has the opposite sign
to WebGL's dFdy (framebuffer space is Y-down), which negates the computed
tangent and bitangent and rotates the tangent-space normal 180 degrees,
producing inverted normal-mapped lighting for meshes without vertex
tangents. Fold the backend into the sign so it stays consistent.

Fixes #5735
@github-actions

Copy link
Copy Markdown

Build size report

This PR changes the size of the minified bundles.

Bundle Minified Gzip Brotli
playcanvas.min.js 2320.9 KB (+0.0 KB, +0.00%) 597.0 KB (+0.0 KB, +0.00%) 464.2 KB (+0.1 KB, +0.03%)
playcanvas.min.mjs 2318.3 KB (+0.0 KB, +0.00%) 595.9 KB (+0.0 KB, +0.00%) 463.7 KB (+0.1 KB, +0.03%)

@mvaligursky
mvaligursky merged commit 4797993 into main Jul 22, 2026
10 checks passed
@mvaligursky
mvaligursky deleted the mv-webgpu-tangents-tbnbasis branch July 22, 2026 11:50
mvaligursky added a commit that referenced this pull request Jul 22, 2026
The derivative-based tangent frame (TBN.js) is scaled by the tbnBasis
uniform, which only accounted for the projection Y flip applied when
rendering with flipY. On WebGPU, screen-space dpdy has the opposite sign
to WebGL's dFdy (framebuffer space is Y-down), which negates the computed
tangent and bitangent and rotates the tangent-space normal 180 degrees,
producing inverted normal-mapped lighting for meshes without vertex
tangents. Fold the backend into the sign so it stays consistent.

Fixes #5735

Co-authored-by: Martin Valigursky <mvaligursky@snapchat.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

1 participant