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
6 changes: 5 additions & 1 deletion examples/webgl_materials_texture_partialupdate.html
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
let last = 0;
const position = new THREE.Vector2();
const color = new THREE.Color();
const box = new THREE.Box2();

init();

Expand Down Expand Up @@ -103,7 +104,10 @@

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

renderer.copyTextureToTexture( position, dataTexture, diffuseMap );
box.min.set( 0, 0 );
box.max.set( dataTexture.image.width, dataTexture.image.height );

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

}

Expand Down
48 changes: 42 additions & 6 deletions src/renderers/WebGLRenderer.js
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ import { WebGLMaterials } from './webgl/WebGLMaterials.js';
import { WebGLUniformsGroups } from './webgl/WebGLUniformsGroups.js';
import { createCanvasElement } from '../utils.js';
import { ColorManagement } from '../math/ColorManagement.js';
import { Box2 } from '../math/Box2.js';

class WebGLRenderer {

Expand Down Expand Up @@ -2371,10 +2372,26 @@ class WebGLRenderer {

};

this.copyTextureToTexture = function ( position, srcTexture, dstTexture, level = 0 ) {
this.copyTextureToTexture = function ( sourceBox, position, srcTexture, dstTexture, level = 0 ) {
gkjohnson marked this conversation as resolved.
Show resolved Hide resolved

const width = srcTexture.image.width;
const height = srcTexture.image.height;
if ( sourceBox.isBox2 !== true ) {

console.warn( 'WebGLRenderer: copyTextureToTexture function signature has changed.' );

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

const image = srcTexture.isCompressedTexture ? srcTexture.mipmaps[ level ] : srcTexture.image;
sourceBox = new Box2();
sourceBox.min.set( 0, 0 );
sourceBox.max.set( image.width, image.height );

}
gkjohnson marked this conversation as resolved.
Show resolved Hide resolved

const width = sourceBox.max.x - sourceBox.min.x;
const height = sourceBox.max.y - sourceBox.min.y;
const glFormat = utils.convert( dstTexture.format );
const glType = utils.convert( dstTexture.type );

Expand All @@ -2386,24 +2403,43 @@ 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 );

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, sourceBox.min.x );
_gl.pixelStorei( _gl.UNPACK_SKIP_ROWS, sourceBox.min.y );

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, 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 );

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

Expand Down