Add support for texture_storage_2d_array
#31167
This is initially a draft to be able to use texture_starage_2d_array in threejs.webgpu. I see in the code that preparations for the extension have already been made in some places and therefore I would like to share my ideas here before I unnecessarily go in the wrong direction.
📦 Bundle size
Full ESM build, minified and gzipped.
| Before | After | Diff | |
|---|---|---|---|
| WebGL | 337.65 78.76 |
337.65 78.76 |
+0 B +0 B |
| WebGPU | 556.95 154.24 |
557.6 154.28 |
+646 B +44 B |
| WebGPU Nodes | 556.3 154.01 |
556.52 154.07 |
+217 B +54 B |
🌳 Bundle size after tree-shaking
Minimal build including a renderer, camera, empty scene, and dependencies.
| Before | After | Diff | |
|---|---|---|---|
| WebGL | 468.89 113.45 |
468.89 113.45 |
+0 B +0 B |
| WebGPU | 632.75 171.25 |
632.96 171.3 |
+217 B +54 B |
| WebGPU Nodes | 587.8 160.56 |
588.01 160.61 |
+217 B +54 B |
I've started by creating a StorageTexture node for array textures. I see in the code that some things like texture_storage_2d_array and 2d-array for the viewDimension have already been created.
This code at the end of StorageTextureNode.js makes me think. uvNode and storeNode are currently undefined
/**
* TODO: Explain difference to `storageTexture()`.
*
* @tsl
* @function
* @param {StorageTexture} value - The storage texture.
* @param {Node<vec2|vec3>} uvNode - The uv node.
* @param {?Node} [storeNode=null] - The value node that should be stored in the texture.
* @returns {StorageTextureNode}
*/
export const textureStore = ( value, uvNode, storeNode ) => {
const node = storageTexture( value, uvNode, storeNode );
if ( storeNode !== null ) node.toStack();
return node;
};
Here, however, the possibility of 3 dimensionality is already hinted at @param {Node<vec2|vec3>} uvNode - The uv node.
My idea was to use this.isStorageTextureArray = true; as an indicator for a StorageTextureArray and then to incorporate the appropriate case distinctions wherever necessary in the threejs code. But that only makes sense if my thoughts are in line with any ideas that may already be in the planning.
@sunag Have you already considered arrays and 3D textures with the uvNode, or does the uvNode have a different background? Currently, it's nonfunctional.
If that doesn't mean anything, I'll continue with my approach with the StorageTextureArray and this.isStorageTextureArray = true; if you think that's a good way.
I can now use the texture with the textureStorage node in the compute shader with texture_storage_2d_array.
However, the extension for correctly reading it into the fragment shader with the texture node is still missing. I'm working on that. Currently, it's still recognized as texture_2d.
@Spiri0 What do you think about creating just a new parameter (depth) in StorageTexture and removing the StorageTextureArray.
@Spiri0 What do you think about creating just a new parameter (depth) in
StorageTextureand removing theStorageTextureArray.
I originally had it that way. Then I just imagined that you might have preferred to separate it. I had depth = 0 in the constructor so that it would be treated as a 2D texture by default. With depth greater than 0, it would be treated as a texture array. I can continue working on it this evening (CET). I'll then look for the reason why the fragment shader recognizes it as texture_2d. I already have an idea where to look.
Here, I'm using texture arrays and copyTextureToTexture to stream large numbers of tiles (4 tiles per layer). Please excuse the poor video quality. I'm new to making videos.
https://youtu.be/UXe4SPWI_8U
All textures are upscaled to 32k. Unfortunately, I can't find any models with very high-quality, detailed textures. I would like to have a city as a model. With storage texture arrays, shared storage buffers and compute shaders this can be done without copyTextureToTexture.
Now it's working. But I'm not satisfied with it yet. I admit I still don't understand why there are two indicators for texture arrays.
isArrayTexture isTextureArray
I used isTextureArray because I saw it in the StorageTexture when reading it from the console. However, isArrayTexture is from Texture. I would prefer to use isArrayTexture if that's okay. If so, I'll rework that
@Spiri0
All textures are upscaled to 32k. Unfortunately, I can't find any models with very high-quality, detailed textures. I would like to have a city as a model.
If you want a challenge...
https://disneyanimation.com/resources/moana-island-scene/
😁
If you want a challenge...
https://disneyanimation.com/resources/moana-island-scene/
😁
Wow, I'm downloading this right now. I'm curious to see what it looks like. With such high-resolution models, I'll surely need my virtual texture system and my virtual geometry system in conjunction to manage the models efficiently. I hope it's possible to open the models in Blender to convert them to gltf and open the textures in GIMP. The download will take a while, but I'm really curious to see the data.
Thank you very much mrdoob
@Mugen87 I think I've found the cause. On the left is the current release, r176, and on the right is the current dev. I updated before I started the PR 4 days ago. The best thing to do will be to wait for r177 and then I test it with all the changes made then, and with isArrayTexture to ensure it's ready for r178.
@sunag Now it's ready for review. Thanks for changing isTextureArray to isArrayTexture. I assume you did that. I didn't want to change a global state parameter without asking. Now the PR looks much more elegant
@sunag Can it be merged as it is now or do you have any changes you would like?
Okay, both are working as they should. The 3DTexture was a good idea, @sunag. It's important for fog and clouds, like in my first repo, which I made in threejs with WebGL: https://github.com/Spiri0/volumetric-clouds?tab=readme-ov-file These were my first steps in threejs. With the Storage3DTexture on GPU side, I can create higher resolution cloud structures much faster than with the Data3DTextures on CPU side.
I changed the order in "getUniforms(shaderStage)" in the WGSLNodeBuilder. The reason was that if normal 3DTextures or arrayTextures were checked first, the storage condition would not be met, and this required complicated extra conditions and restrictions. The changed order makes it simple.
isSampledTexture3D replaced by is3DTexture, since it does not matter for the viewDimension whether sampled or not. This avoids unnecessary extra conditions
I've removed the storage3DTexture and storageArrayTexture exports from Three.TSL.js for now. The reason is that these exports aren't necessary for three.webgpu.js, and I don't yet understand Three.TSL.js well enough to say whether it would even make sense there.