Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

WebGLRenderer: Enable subframe upload in copyTextureToTexture, align API to 3d version #28281

Merged
merged 17 commits into from
May 7, 2024
Merged
9 changes: 5 additions & 4 deletions docs/api/en/renderers/WebGLRenderer.html
Original file line number Diff line number Diff line change
Expand Up @@ -376,16 +376,17 @@ <h3>
</p>

<h3>
[method:undefined copyTextureToTexture]( [param:Vector2 position], [param:Texture srcTexture], [param:Texture dstTexture], [param:Number level] )
[method:undefined copyTextureToTexture]( [param:Vector2 position], [param:Texture srcTexture], [param:Texture dstTexture], [param:Number level], [param:Box2 sourceBox] )
</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 sourceBox]' 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:Vector3 position], [param:Texture srcTexture], [param:Texture dstTexture], [param:Number level], [param:Box3 sourceBox] )
</h3>
<p>
Copies the pixels of a texture in the bounds '[page:Box3 sourceBox]' in
Expand Down
2 changes: 1 addition & 1 deletion examples/webgl2_materials_texture3d_partialupdate.html
Original file line number Diff line number Diff line change
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( position, source, cloudTexture, 0, box );

prevTime = time;

Expand Down
115 changes: 90 additions & 25 deletions src/renderers/WebGLRenderer.js
Original file line number Diff line number Diff line change
Expand Up @@ -2371,10 +2371,25 @@ class WebGLRenderer {

};

this.copyTextureToTexture = function ( position, srcTexture, dstTexture, level = 0 ) {
this.copyTextureToTexture = function ( position, srcTexture, dstTexture, level = 0, sourceBox = null ) {
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think srcRegion is more clear and follows the rest of the parameter names.


let width, height, minX, minY;
if ( sourceBox !== null ) {

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

} else {

width = srcTexture.image.width;
height = srcTexture.image.height;
minX = 0;
minY = 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 @@ -2386,36 +2401,88 @@ 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 );

gkjohnson marked this conversation as resolved.
Show resolved Hide resolved
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, position.x, position.y, 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, position.x, position.y, image.width, image.height, glFormat, image.data );
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

One other discrepancy I noticed between the copyTextureToTexture and copyTextureToTexture3D implementations is that the 3D variant used "level" to index into the source textures mipmap array whereas it was always 0 in the 2d version. I've aligned to what the 3d function was doing but am happy to change it either way.


} else {

_gl.texSubImage2D( _gl.TEXTURE_2D, level, position.x, position.y, glFormat, glType, srcTexture.image );
_gl.texSubImage2D( _gl.TEXTURE_2D, level, position.x, position.y, 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 ( position, srcTexture, dstTexture, level = 0, sourceBox = null ) {

// support previous signature with source box first
if ( position.isBox3 === true ) {

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

sourceBox = arguments[ 0 ];
position = arguments[ 1 ];
srcTexture = arguments[ 2 ];
dstTexture = arguments[ 3 ];
level = arguments[ 4 ] || 0;

}

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

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

} else {

width = image.width;
height = image.height;
depth = image.depth;
minX = 0;
minY = 0;
minZ = 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 @@ -2441,19 +2508,17 @@ 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 ) {

Expand All @@ -2473,11 +2538,11 @@ class WebGLRenderer {

}

_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