-
-
Notifications
You must be signed in to change notification settings - Fork 36k
Description
Description
Rendering custom mipmaps can be valuable for a number of use cases for post processing, stylization, etc but it's not something that three.js supports currently. Use cases include:
- Mipmap generation for non-color data maps such as normal, depth maps (useful for postprocessing, etc).
- Manual generation of per-layer mipmaps in array textures, 3d textures.
- Manual generation of mipmaps to account for wrapping constants
- etc
I think there are a few concept disconnects currently. One is that "generateMipmaps" indicates that both mipmap storage should be generated and the mip chain should be generated. When generating custom mipmaps though these concepts should be separate. Ie you may want an option that says "generateMipmapStorage" and "generateMipmapContents". Or a setting that enumerates the three options. Another is that you cannot currently render into just any textures storage.
Solution
These are some solutions that come to mind - there are no doubt others. I can't say these are optimal or align with what's possible in WebGPU but I'll list them here to start the discussion:
Generating Mipmap Storage w/o Contents
The generateMipmaps
setting could be changed to take three options so attaching storage does not implicitly mean generating content: NO_MIPMAPS
(current false
), MIPMAP_STORAGE
, or MIPMAP_CONTENTS
(current true
).
Rendering to Mipmaps (#29844)
Currently setRenderTarget
supports taking a activeMipmapLevel
but as far as I can tell this will only work if the user has specified textures in the texture.mipmaps
array, is a 3d texture, or cube map. The active mipmap level could also apply to the automatically-generated mipmap storage using the framebufferTexture2D.
Writing to Regular Texture Mipmaps
The above solutions only really apply to RenderTargets but generating custom mipmaps for regular textures, normals maps, data textures, etc are all relevant. A simple solution would be to enable setting a regular non-rendertarget texture as a depth buffer-less renderable target.
Alternatives
Generating Mipmap Storage w/o Contents
To do this currently you can create a render target, initialize it with generateMipmaps = true
, and then disable it to ensure the storage is available. This however still incurs the overhead of generating mipmaps on creation:
const map = new THREE.WebGLRenderTarget( 32, 32, { generateMipmaps: true } );
renderer.initRenderTarget( map );
map.texture.generateMipmaps = false;
Rendering to Mipmaps / Writing to Regular Texture Mipmaps
Using copyTextureToTexture
, custom mipmaps can be generated with render targets and then copied into the appropriate mipmap level. The additions in #29769 allow for copying any existing mip map data, as well.
This solutions incurs unneeded overhead copying and an additional render target, however.
Additional Context
WebGPU does not support automatic generation of mipmaps: gpuweb/gpuweb#386
The answer to this stackoverflow question shows that it's possible to render into a mipmap storage while sampling from the immediate parent mip by setting the TEXTURE_MAX_LEVEL
, TEXTURE_BASE_LEVEL
, TEXTURE_MAX_LOD
. Setting these can probably be left to the user.