Unified pixel readback. Hides three backend differences from callers:
Method-signature dispatch — WebGL2's readRenderTargetPixelsAsync
takes a destination buffer; WebGPU's returns the result.
WebGPU row padding — WebGPU's copyTextureToBuffer rounds
bytesPerRow up to 256; this primitive runs
compactWebGPUReadbackRows unconditionally (no-op for
aligned widths or under WebGL2).
Framebuffer Y orientation — both renderer surfaces return
bottom-up rows from readRenderTargetPixelsAsync:
WebGLRenderer is calling gl.readPixels underneath, and
WebGPURenderer's compat layer maintains the same contract on
both its real-WebGPU and WebGL2 backends. (caps.framebufferYDown
describes the sampling convention used by
createFullscreenTriangleGeometry, NOT the readback
memory layout — empirically the two have diverged on
WebGPURenderer.) The primitive canonicalises to top-down
by default. Pass flipY: true to get bottom-up rows out
instead — only the EXR exporter does this today, to preserve
the orientation external tools (Nuke, Houdini, oiiotool)
expect.
Unified pixel readback. Hides three backend differences from callers:
readRenderTargetPixelsAsynctakes a destination buffer; WebGPU's returns the result.copyTextureToBufferroundsbytesPerRowup to 256; this primitive runs compactWebGPUReadbackRows unconditionally (no-op for aligned widths or under WebGL2).readRenderTargetPixelsAsync: WebGLRenderer is callinggl.readPixelsunderneath, and WebGPURenderer's compat layer maintains the same contract on both its real-WebGPU and WebGL2 backends. (caps.framebufferYDowndescribes the sampling convention used by createFullscreenTriangleGeometry, NOT the readback memory layout — empirically the two have diverged on WebGPURenderer.) The primitive canonicalises to top-down by default. PassflipY: trueto get bottom-up rows out instead — only the EXR exporter does this today, to preserve the orientation external tools (Nuke, Houdini, oiiotool) expect.