mrdoob / three.js

JavaScript 3D Library.
https://threejs.org/
MIT License
101.83k stars 35.31k forks source link

WebGPURenderer: `CubeRenderTarget.fromEquirectangularTexture()` does not work with sRGB input. #28826

Closed Mugen87 closed 2 months ago

Mugen87 commented 2 months ago

Description

WebGPURenderer should be able to automatically convert equirectangular texture to the cube map format. I've tried to implement auto-conversion for envMap in BasicEnvironmentNode but then encountered an issue.

CubeRenderTarget.fromEquirectangularTexture() (which internally uses CubeCamera.update()) only works if the input is linear-srgb. If it is srgb which is more or less always true for non HDR textures, the rendering fails with the following WebGPU warnings:

Texture view array layer range (baseArrayLayer: 1, arrayLayerCount: 1) exceeds the texture's array layer count (1).
 - While validating [TextureViewDescriptor] against [Texture (unlabeled 2734x1288 px, TextureFormat::RGBA16Float)].
 - While calling [Texture (unlabeled 2734x1288 px, TextureFormat::RGBA16Float)].CreateView([TextureViewDescriptor]).

_display/:1 [Invalid TextureView] is invalid.
 - While validating colorAttachments[0].
 - While encoding [CommandEncoder "renderContext_2"].BeginRenderPass([null]).

_display/:1 [Invalid CommandBuffer from CommandEncoder "renderContext_2"] is invalid.
 - While calling [Queue].Submit([[Invalid CommandBuffer from CommandEncoder "renderContext_2"]])

The renderer logs this for the baseArrayLayer 1-5 which means for the cube sides 1-5. The first one seems to render as expected.

Reproduction steps

  1. Go to https://jsfiddle.net/hvoju7bw/1/.
  2. Check browser console.

Code

const renderer = new THREE.WebGPURenderer();
renderer.setPixelRatio(window.devicePixelRatio);
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);

await renderer.init();

const loader = new THREE.TextureLoader();

const texture = await loader.loadAsync('https://threejs.org/examples/textures/2294472375_24a3b8ef46_o.jpg');
texture.mapping = THREE.EquirectangularReflectionMapping;
texture.colorSpace = THREE.SRGBColorSpace;

const renderTarget = new CubeRenderTarget(texture.image.height);
renderTarget.fromEquirectangularTexture(renderer, texture);

Live example

https://jsfiddle.net/hLcnrsfb/

Screenshots

No response

Version

r167dev

Device

Desktop

Browser

Chrome

OS

MacOS

Mugen87 commented 2 months ago

When rendering into a sRGB marked render target, the renderer does not have to perform sRGB output conversion. E.g. the SRGB8_ALPHA8 format from WebGL 2 automatically stores the written fragments as sRGB and decodes them back to linear-srgb as part of the filtering.

It seems WebGPURenderer tries to force output color space conversion which should not be done in this case.