Skip to content

Commit

Permalink
WebGLRenderer: Enable subframe upload in copyTextureToTexture, align …
Browse files Browse the repository at this point in the history
…API to 3d version (#28281)

* align WebGLRenderer.copyTextureToTexture with copyTextureToTexture3D

* Make the function backwards compatible

* Add import statement

* Fix example

* rename local state variables

* Add deprecation comment

* Update docs

* Update API signatures

* Simplify

* Update examples

* Remove unused Box2

* Add comment

* Update function signatures

* examples update

* docs update

* Fix docs
  • Loading branch information
gkjohnson committed May 7, 2024
1 parent 7a02475 commit 3bc0cc7
Show file tree
Hide file tree
Showing 4 changed files with 143 additions and 35 deletions.
11 changes: 6 additions & 5 deletions docs/api/en/renderers/WebGLRenderer.html
Expand Up @@ -376,19 +376,20 @@ <h3>
</p>

<h3>
[method:undefined copyTextureToTexture]( [param:Vector2 position], [param:Texture srcTexture], [param:Texture dstTexture], [param:Number level] )
[method:undefined copyTextureToTexture]( [param:Texture srcTexture], [param:Texture dstTexture], [param:Box2 srcRegion], [param:Vector2 dstPosition], [param:Number level] )
</h3>
<p>
Copies all pixels of a texture to an existing texture starting from the
given position. Enables access to
Copies the pixels of a texture in the bounds '[page:Box2 srcRegion]' in
the destination texture starting from the given position. Enables access
to
[link:https://developer.mozilla.org/en-US/docs/Web/API/WebGLRenderingContext/texSubImage2D WebGLRenderingContext.texSubImage2D].
</p>

<h3>
[method:undefined copyTextureToTexture3D]( [param:Box3 sourceBox], [param:Vector3 position], [param:Texture srcTexture], [param:Texture dstTexture], [param:Number level] )
[method:undefined copyTextureToTexture3D]( [param:Texture srcTexture], [param:Texture dstTexture], [param:Box3 srcRegion], [param:Vector3 dstPosition], [param:Number level] )
</h3>
<p>
Copies the pixels of a texture in the bounds '[page:Box3 sourceBox]' in
Copies the pixels of a texture in the bounds '[page:Box3 srcRegion]' in
the destination texture starting from the given position. Enables access
to
[link:https://developer.mozilla.org/en-US/docs/Web/API/WebGL2RenderingContext/texSubImage3D WebGL2RenderingContext.texSubImage3D].
Expand Down
2 changes: 1 addition & 1 deletion examples/webgl2_materials_texture3d_partialupdate.html
Expand Up @@ -343,7 +343,7 @@
const scaleFactor = ( Math.random() + 0.5 ) * 0.5;
const source = generateCloudTexture( perElementPaddedSize, scaleFactor );

renderer.copyTextureToTexture3D( box, position, source, cloudTexture );
renderer.copyTextureToTexture3D( source, cloudTexture, box, position );

prevTime = time;

Expand Down
2 changes: 1 addition & 1 deletion examples/webgl_materials_texture_partialupdate.html
Expand Up @@ -103,7 +103,7 @@

// perform copy from src to dest texture to a random position

renderer.copyTextureToTexture( position, dataTexture, diffuseMap );
renderer.copyTextureToTexture( dataTexture, diffuseMap, null, position );

}

Expand Down
163 changes: 135 additions & 28 deletions src/renderers/WebGLRenderer.js
Expand Up @@ -2450,10 +2450,52 @@ class WebGLRenderer {

};

this.copyTextureToTexture = function ( position, srcTexture, dstTexture, level = 0 ) {
this.copyTextureToTexture = function ( srcTexture, dstTexture, srcRegion = null, dstPosition = null, level = 0 ) {

// support previous signature with source box first
if ( srcTexture.isTexture !== true ) {

// @deprecated, r165
console.warn( 'WebGLRenderer: copyTextureToTexture function signature has changed.' );

dstPosition = arguments[ 0 ] || null;
srcTexture = arguments[ 1 ];
dstTexture = arguments[ 2 ];
level = arguments[ 3 ] || 0;
srcRegion = null;

}

let width, height, minX, minY;
let dstX, dstY;
if ( srcRegion !== null ) {

width = srcRegion.max.x - srcRegion.min.x;
height = srcRegion.max.y - srcRegion.min.y;
minX = srcRegion.min.x;
minY = srcRegion.min.y;

} else {

width = srcTexture.image.width;
height = srcTexture.image.height;
minX = 0;
minY = 0;

}

if ( dstPosition !== null ) {

dstX = dstPosition.x;
dstY = dstPosition.y;

} else {

dstX = 0;
dstY = 0;

}

const width = srcTexture.image.width;
const height = srcTexture.image.height;
const glFormat = utils.convert( dstTexture.format );
const glType = utils.convert( dstTexture.type );

Expand All @@ -2465,36 +2507,103 @@ class WebGLRenderer {
_gl.pixelStorei( _gl.UNPACK_PREMULTIPLY_ALPHA_WEBGL, dstTexture.premultiplyAlpha );
_gl.pixelStorei( _gl.UNPACK_ALIGNMENT, dstTexture.unpackAlignment );

const currentUnpackRowLen = _gl.getParameter( _gl.UNPACK_ROW_LENGTH );
const currentUnpackImageHeight = _gl.getParameter( _gl.UNPACK_IMAGE_HEIGHT );
const currentUnpackSkipPixels = _gl.getParameter( _gl.UNPACK_SKIP_PIXELS );
const currentUnpackSkipRows = _gl.getParameter( _gl.UNPACK_SKIP_ROWS );
const currentUnpackSkipImages = _gl.getParameter( _gl.UNPACK_SKIP_IMAGES );

const image = srcTexture.isCompressedTexture ? srcTexture.mipmaps[ level ] : srcTexture.image;

_gl.pixelStorei( _gl.UNPACK_ROW_LENGTH, image.width );
_gl.pixelStorei( _gl.UNPACK_IMAGE_HEIGHT, image.height );
_gl.pixelStorei( _gl.UNPACK_SKIP_PIXELS, minX );
_gl.pixelStorei( _gl.UNPACK_SKIP_ROWS, minY );

if ( srcTexture.isDataTexture ) {

_gl.texSubImage2D( _gl.TEXTURE_2D, level, position.x, position.y, width, height, glFormat, glType, srcTexture.image.data );
_gl.texSubImage2D( _gl.TEXTURE_2D, level, dstX, dstY, width, height, glFormat, glType, image.data );

} else {

if ( srcTexture.isCompressedTexture ) {

_gl.compressedTexSubImage2D( _gl.TEXTURE_2D, level, position.x, position.y, srcTexture.mipmaps[ 0 ].width, srcTexture.mipmaps[ 0 ].height, glFormat, srcTexture.mipmaps[ 0 ].data );
_gl.compressedTexSubImage2D( _gl.TEXTURE_2D, level, dstX, dstY, image.width, image.height, glFormat, image.data );

} else {

_gl.texSubImage2D( _gl.TEXTURE_2D, level, position.x, position.y, glFormat, glType, srcTexture.image );
_gl.texSubImage2D( _gl.TEXTURE_2D, level, dstX, dstY, glFormat, glType, image );

}

}

_gl.pixelStorei( _gl.UNPACK_ROW_LENGTH, currentUnpackRowLen );
_gl.pixelStorei( _gl.UNPACK_IMAGE_HEIGHT, currentUnpackImageHeight );
_gl.pixelStorei( _gl.UNPACK_SKIP_PIXELS, currentUnpackSkipPixels );
_gl.pixelStorei( _gl.UNPACK_SKIP_ROWS, currentUnpackSkipRows );
_gl.pixelStorei( _gl.UNPACK_SKIP_IMAGES, currentUnpackSkipImages );

// Generate mipmaps only when copying level 0
if ( level === 0 && dstTexture.generateMipmaps ) _gl.generateMipmap( _gl.TEXTURE_2D );

state.unbindTexture();

};

this.copyTextureToTexture3D = function ( sourceBox, position, srcTexture, dstTexture, level = 0 ) {
this.copyTextureToTexture3D = function ( srcTexture, dstTexture, srcRegion = null, dstPosition = null, level = 0 ) {

// support previous signature with source box first
if ( srcTexture.isTexture !== true ) {

// @deprecated, r165
console.warn( 'WebGLRenderer: copyTextureToTexture3D function signature has changed.' );

srcRegion = arguments[ 0 ] || null;
dstPosition = arguments[ 1 ] || null;
srcTexture = arguments[ 2 ];
dstTexture = arguments[ 3 ];
level = arguments[ 4 ] || 0;

}

let width, height, depth, minX, minY, minZ;
let dstX, dstY, dstZ;
const image = srcTexture.isCompressedTexture ? srcTexture.mipmaps[ level ] : srcTexture.image;
if ( srcRegion !== null ) {

width = srcRegion.max.x - srcRegion.min.x;
height = srcRegion.max.y - srcRegion.min.y;
depth = srcRegion.max.z - srcRegion.min.z;
minX = srcRegion.min.x;
minY = srcRegion.min.y;
minZ = srcRegion.min.z;

} else {

width = image.width;
height = image.height;
depth = image.depth;
minX = 0;
minY = 0;
minZ = 0;

}

if ( dstPosition !== null ) {

dstX = dstPosition.x;
dstY = dstPosition.y;
dstZ = dstPosition.z;

} else {

dstX = 0;
dstY = 0;
dstZ = 0;

}

const width = sourceBox.max.x - sourceBox.min.x;
const height = sourceBox.max.y - sourceBox.min.y;
const depth = sourceBox.max.z - sourceBox.min.z;
const glFormat = utils.convert( dstTexture.format );
const glType = utils.convert( dstTexture.type );
let glTarget;
Expand All @@ -2520,43 +2629,41 @@ class WebGLRenderer {
_gl.pixelStorei( _gl.UNPACK_PREMULTIPLY_ALPHA_WEBGL, dstTexture.premultiplyAlpha );
_gl.pixelStorei( _gl.UNPACK_ALIGNMENT, dstTexture.unpackAlignment );

const unpackRowLen = _gl.getParameter( _gl.UNPACK_ROW_LENGTH );
const unpackImageHeight = _gl.getParameter( _gl.UNPACK_IMAGE_HEIGHT );
const unpackSkipPixels = _gl.getParameter( _gl.UNPACK_SKIP_PIXELS );
const unpackSkipRows = _gl.getParameter( _gl.UNPACK_SKIP_ROWS );
const unpackSkipImages = _gl.getParameter( _gl.UNPACK_SKIP_IMAGES );

const image = srcTexture.isCompressedTexture ? srcTexture.mipmaps[ level ] : srcTexture.image;
const currentUnpackRowLen = _gl.getParameter( _gl.UNPACK_ROW_LENGTH );
const currentUnpackImageHeight = _gl.getParameter( _gl.UNPACK_IMAGE_HEIGHT );
const currentUnpackSkipPixels = _gl.getParameter( _gl.UNPACK_SKIP_PIXELS );
const currentUnpackSkipRows = _gl.getParameter( _gl.UNPACK_SKIP_ROWS );
const currentUnpackSkipImages = _gl.getParameter( _gl.UNPACK_SKIP_IMAGES );

_gl.pixelStorei( _gl.UNPACK_ROW_LENGTH, image.width );
_gl.pixelStorei( _gl.UNPACK_IMAGE_HEIGHT, image.height );
_gl.pixelStorei( _gl.UNPACK_SKIP_PIXELS, sourceBox.min.x );
_gl.pixelStorei( _gl.UNPACK_SKIP_ROWS, sourceBox.min.y );
_gl.pixelStorei( _gl.UNPACK_SKIP_IMAGES, sourceBox.min.z );
_gl.pixelStorei( _gl.UNPACK_SKIP_PIXELS, minX );
_gl.pixelStorei( _gl.UNPACK_SKIP_ROWS, minY );
_gl.pixelStorei( _gl.UNPACK_SKIP_IMAGES, minZ );

if ( srcTexture.isDataTexture || srcTexture.isData3DTexture ) {

_gl.texSubImage3D( glTarget, level, position.x, position.y, position.z, width, height, depth, glFormat, glType, image.data );
_gl.texSubImage3D( glTarget, level, dstX, dstY, dstZ, width, height, depth, glFormat, glType, image.data );

} else {

if ( dstTexture.isCompressedArrayTexture ) {

_gl.compressedTexSubImage3D( glTarget, level, position.x, position.y, position.z, width, height, depth, glFormat, image.data );
_gl.compressedTexSubImage3D( glTarget, level, dstX, dstY, dstZ, width, height, depth, glFormat, image.data );

} else {

_gl.texSubImage3D( glTarget, level, position.x, position.y, position.z, width, height, depth, glFormat, glType, image );
_gl.texSubImage3D( glTarget, level, dstX, dstY, dstZ, width, height, depth, glFormat, glType, image );

}

}

_gl.pixelStorei( _gl.UNPACK_ROW_LENGTH, unpackRowLen );
_gl.pixelStorei( _gl.UNPACK_IMAGE_HEIGHT, unpackImageHeight );
_gl.pixelStorei( _gl.UNPACK_SKIP_PIXELS, unpackSkipPixels );
_gl.pixelStorei( _gl.UNPACK_SKIP_ROWS, unpackSkipRows );
_gl.pixelStorei( _gl.UNPACK_SKIP_IMAGES, unpackSkipImages );
_gl.pixelStorei( _gl.UNPACK_ROW_LENGTH, currentUnpackRowLen );
_gl.pixelStorei( _gl.UNPACK_IMAGE_HEIGHT, currentUnpackImageHeight );
_gl.pixelStorei( _gl.UNPACK_SKIP_PIXELS, currentUnpackSkipPixels );
_gl.pixelStorei( _gl.UNPACK_SKIP_ROWS, currentUnpackSkipRows );
_gl.pixelStorei( _gl.UNPACK_SKIP_IMAGES, currentUnpackSkipImages );

// Generate mipmaps only when copying level 0
if ( level === 0 && dstTexture.generateMipmaps ) _gl.generateMipmap( glTarget );
Expand Down

0 comments on commit 3bc0cc7

Please sign in to comment.