diff --git a/docs/api/en/textures/CompressedArrayTexture.html b/docs/api/en/textures/CompressedArrayTexture.html
index 7c2d2ba2a25c0..0b1cfcd5ee6f2 100644
--- a/docs/api/en/textures/CompressedArrayTexture.html
+++ b/docs/api/en/textures/CompressedArrayTexture.html
@@ -61,11 +61,32 @@
[property:number wrapR]
[property:Object image]
Overridden with a object containing width, height, and depth.
+ [property:Set layerUpdates]
+
+ A set of all layers which need to be updated in the texture. See
+ [Page:CompressedTextureArray.addLayerUpdate addLayerUpdate].
+
+
[property:Boolean isCompressedArrayTexture]
Read-only flag to check if a given object is of type [name].
Methods
+ [method:addLayerUpdate addLayerUpdate]( layerIndex )
+
+ Describes that a specific layer of the texture needs to be updated.
+ Normally when [page:Texture.needsUpdate needsUpdate] is set to true, the
+ entire compressed texture array is sent to the GPU. Marking specific
+ layers will only transmit subsets of all mipmaps associated with a
+ specific depth in the array which is often much more performant.
+
+
+ [method:clearLayerUpdates clearLayerUpdates]()
+
+ Resets the layer updates registry. See
+ [Page:CompressedTextureArray.addLayerUpdate addLayerUpdate].
+
+
See the base [page:CompressedTexture CompressedTexture] class for common
methods.
diff --git a/docs/api/en/textures/DataArrayTexture.html b/docs/api/en/textures/DataArrayTexture.html
index 2c4d4e94fff4a..0848d826c3185 100644
--- a/docs/api/en/textures/DataArrayTexture.html
+++ b/docs/api/en/textures/DataArrayTexture.html
@@ -143,8 +143,30 @@
[property:number wrapR]
page for details.
+ [property:Set layerUpdates]
+
+ A set of all layers which need to be updated in the texture. See
+ [Page:DataArrayTexture.addLayerUpdate addLayerUpdate].
+
+
Methods
+ [method:addLayerUpdate addLayerUpdate]( layerIndex )
+
+ Describes that a specific layer of the texture needs to be updated.
+ Normally when [page:Texture.needsUpdate needsUpdate] is set to true, the
+ entire compressed texture array is sent to the GPU. Marking specific
+ layers will only transmit subsets of all mipmaps associated with a
+ specific depth in the array which is often much more performant.
+
+
+ [method:clearLayerUpdates clearLayerUpdates]()
+
+ Resets the layer updates registry. See
+ [Page:DataArrayTexture.addLayerUpdate addLayerUpdate].
+
+
+
See the base [page:Texture Texture] class for common methods.
Source
diff --git a/src/renderers/webgl/WebGLTextures.js b/src/renderers/webgl/WebGLTextures.js
index 1d8f9553a1772..1aa1e9f7bdb47 100644
--- a/src/renderers/webgl/WebGLTextures.js
+++ b/src/renderers/webgl/WebGLTextures.js
@@ -820,7 +820,22 @@ function WebGLTextures( _gl, extensions, state, properties, capabilities, utils,
if ( dataReady ) {
- state.compressedTexSubImage3D( _gl.TEXTURE_2D_ARRAY, i, 0, 0, 0, mipmap.width, mipmap.height, image.depth, glFormat, mipmap.data, 0, 0 );
+ if ( texture.layerUpdates.size > 0 ) {
+
+ for ( const layerIndex of texture.layerUpdates ) {
+
+ const layerSize = mipmap.width * mipmap.height;
+ state.compressedTexSubImage3D( _gl.TEXTURE_2D_ARRAY, i, 0, 0, layerIndex, mipmap.width, mipmap.height, 1, glFormat, mipmap.data.slice( layerSize * layerIndex, layerSize * ( layerIndex + 1 ) ), 0, 0 );
+
+ }
+
+ texture.clearLayerUpdates();
+
+ } else {
+
+ state.compressedTexSubImage3D( _gl.TEXTURE_2D_ARRAY, i, 0, 0, 0, mipmap.width, mipmap.height, image.depth, glFormat, mipmap.data, 0, 0 );
+
+ }
}
@@ -926,7 +941,72 @@ function WebGLTextures( _gl, extensions, state, properties, capabilities, utils,
if ( dataReady ) {
- state.texSubImage3D( _gl.TEXTURE_2D_ARRAY, 0, 0, 0, 0, image.width, image.height, image.depth, glFormat, glType, image.data );
+ if ( texture.layerUpdates.size > 0 ) {
+
+ // When type is GL_UNSIGNED_BYTE, each of these bytes is
+ // interpreted as one color component, depending on format. When
+ // type is one of GL_UNSIGNED_SHORT_5_6_5,
+ // GL_UNSIGNED_SHORT_4_4_4_4, GL_UNSIGNED_SHORT_5_5_5_1, each
+ // unsigned value is interpreted as containing all the components
+ // for a single pixel, with the color components arranged
+ // according to format.
+ //
+ // See https://registry.khronos.org/OpenGL-Refpages/es1.1/xhtml/glTexImage2D.xml
+ let texelSize;
+ switch ( glType ) {
+
+ case _gl.UNSIGNED_BYTE:
+ switch ( glFormat ) {
+
+ case _gl.ALPHA:
+ texelSize = 1;
+ break;
+ case _gl.LUMINANCE:
+ texelSize = 1;
+ break;
+ case _gl.LUMINANCE_ALPHA:
+ texelSize = 2;
+ break;
+ case _gl.RGB:
+ texelSize = 3;
+ break;
+ case _gl.RGBA:
+ texelSize = 4;
+ break;
+
+ default:
+ throw new Error( `Unknown texel size for format ${glFormat}.` );
+
+ }
+
+ break;
+
+ case _gl.UNSIGNED_SHORT_4_4_4_4:
+ case _gl.UNSIGNED_SHORT_5_5_5_1:
+ case _gl.UNSIGNED_SHORT_5_6_5:
+ texelSize = 1;
+ break;
+
+ default:
+ throw new Error( `Unknown texel size for type ${glType}.` );
+
+ }
+
+ const layerSize = image.width * image.height * texelSize;
+
+ for ( const layerIndex of texture.layerUpdates ) {
+
+ state.texSubImage3D( _gl.TEXTURE_2D_ARRAY, 0, 0, 0, layerIndex, image.width, image.height, 1, glFormat, glType, image.data.slice( layerSize * layerIndex, layerSize * ( layerIndex + 1 ) ) );
+
+ }
+
+ texture.clearLayerUpdates();
+
+ } else {
+
+ state.texSubImage3D( _gl.TEXTURE_2D_ARRAY, 0, 0, 0, 0, image.width, image.height, image.depth, glFormat, glType, image.data );
+
+ }
}
diff --git a/src/textures/CompressedArrayTexture.js b/src/textures/CompressedArrayTexture.js
index cc062e695d41b..80aa2132b1b86 100644
--- a/src/textures/CompressedArrayTexture.js
+++ b/src/textures/CompressedArrayTexture.js
@@ -11,6 +11,20 @@ class CompressedArrayTexture extends CompressedTexture {
this.image.depth = depth;
this.wrapR = ClampToEdgeWrapping;
+ this.layerUpdates = new Set();
+
+ }
+
+ addLayerUpdates( layerIndex ) {
+
+ this.layerUpdates.add( layerIndex );
+
+ }
+
+ clearLayerUpdates() {
+
+ this.layerUpdates.clear();
+
}
}
diff --git a/src/textures/DataArrayTexture.js b/src/textures/DataArrayTexture.js
index 759973df66378..daac7aad1c3f4 100644
--- a/src/textures/DataArrayTexture.js
+++ b/src/textures/DataArrayTexture.js
@@ -20,6 +20,20 @@ class DataArrayTexture extends Texture {
this.flipY = false;
this.unpackAlignment = 1;
+ this.layerUpdates = new Set();
+
+ }
+
+ addLayerUpdate( layerIndex ) {
+
+ this.layerUpdates.add( layerIndex );
+
+ }
+
+ clearLayerUpdates() {
+
+ this.layerUpdates.clear();
+
}
}