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: Support render target textures in copyTextureToTexture(). #29662

Merged
merged 3 commits into from
Oct 19, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 6 additions & 8 deletions docs/api/en/renderers/WebGLRenderer.html
Original file line number Diff line number Diff line change
Expand Up @@ -383,20 +383,18 @@ <h3>
[method:undefined copyTextureToTexture]( [param:Texture srcTexture], [param:Texture dstTexture], [param:Box2 srcRegion], [param:Vector2 dstPosition], [param:Number level] )
</h3>
<p>
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].
Copies the pixels of a texture in the bounds '[page:Box2 srcRegion]' in the destination texture starting from the given position.
The `depthTexture` and `texture` property of render targets are supported as well.<br />
When using render target textures as `srcTexture` and `dstTexture`, you must make sure both render targets are intitialized e.g. via [page:.initRenderTarget]().
</p>

<h3>
[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 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].
Copies the pixels of a texture in the bounds '[page:Box3 srcRegion]' in the destination texture starting from the given position.
The `depthTexture` and `texture` property of 3D render targets are supported as well.<br />
When using render target textures as `srcTexture` and `dstTexture`, you must make sure both render targets are intitialized e.g. via [page:.initRenderTarget]().
</p>

<h3>[method:undefined dispose]( )</h3>
Expand Down
71 changes: 61 additions & 10 deletions src/renderers/WebGLRenderer.js
Original file line number Diff line number Diff line change
Expand Up @@ -2627,19 +2627,42 @@ class WebGLRenderer {
_gl.pixelStorei( _gl.UNPACK_SKIP_PIXELS, minX );
_gl.pixelStorei( _gl.UNPACK_SKIP_ROWS, minY );

if ( srcTexture.isDataTexture ) {
if ( srcTexture.isRenderTargetTexture || srcTexture.isDepthTexture ) {

_gl.texSubImage2D( _gl.TEXTURE_2D, level, dstX, dstY, width, height, glFormat, glType, image.data );
const srcTextureProperties = properties.get( srcTexture );
const dstTextureProperties = properties.get( dstTexture );
const srcRenderTargetProperties = properties.get( srcTextureProperties.__renderTarget );
const dstRenderTargetProperties = properties.get( dstTextureProperties.__renderTarget );

state.bindFramebuffer( _gl.READ_FRAMEBUFFER, srcRenderTargetProperties.__webglFramebuffer );
state.bindFramebuffer( _gl.DRAW_FRAMEBUFFER, dstRenderTargetProperties.__webglFramebuffer );

let mask = _gl.COLOR_BUFFER_BIT;

if ( srcTexture.isDepthTexture ) mask = _gl.DEPTH_BUFFER_BIT;

_gl.blitFramebuffer( minX, minY, width, height, dstX, dstY, width, height, mask, _gl.NEAREST );

state.bindFramebuffer( _gl.READ_FRAMEBUFFER, null );
state.bindFramebuffer( _gl.DRAW_FRAMEBUFFER, null );

} else {

if ( srcTexture.isCompressedTexture ) {
if ( srcTexture.isDataTexture ) {

_gl.compressedTexSubImage2D( _gl.TEXTURE_2D, level, dstX, dstY, image.width, image.height, glFormat, image.data );
_gl.texSubImage2D( _gl.TEXTURE_2D, level, dstX, dstY, width, height, glFormat, glType, image.data );

} else {

_gl.texSubImage2D( _gl.TEXTURE_2D, level, dstX, dstY, width, height, glFormat, glType, image );
if ( srcTexture.isCompressedTexture ) {

_gl.compressedTexSubImage2D( _gl.TEXTURE_2D, level, dstX, dstY, image.width, image.height, glFormat, image.data );

} else {

_gl.texSubImage2D( _gl.TEXTURE_2D, level, dstX, dstY, width, height, glFormat, glType, image );

}

}

Expand Down Expand Up @@ -2748,19 +2771,47 @@ class WebGLRenderer {
_gl.pixelStorei( _gl.UNPACK_SKIP_ROWS, minY );
_gl.pixelStorei( _gl.UNPACK_SKIP_IMAGES, minZ );

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

const srcTextureProperties = properties.get( srcTexture );
const dstTextureProperties = properties.get( dstTexture );
const srcRenderTargetProperties = properties.get( srcTextureProperties.__renderTarget );
const dstRenderTargetProperties = properties.get( dstTextureProperties.__renderTarget );

state.bindFramebuffer( _gl.READ_FRAMEBUFFER, srcRenderTargetProperties.__webglFramebuffer );

_gl.texSubImage3D( glTarget, level, dstX, dstY, dstZ, width, height, depth, glFormat, glType, image.data );
_gl.framebufferTextureLayer( _gl.READ_FRAMEBUFFER, _gl.COLOR_ATTACHMENT0, properties.get( srcTexture ).__webglTexture, level, 0 );

state.bindFramebuffer( _gl.DRAW_FRAMEBUFFER, dstRenderTargetProperties.__webglFramebuffer );

_gl.framebufferTextureLayer( _gl.DRAW_FRAMEBUFFER, _gl.COLOR_ATTACHMENT0, properties.get( dstTexture ).__webglTexture, level, 0 );

let mask = _gl.COLOR_BUFFER_BIT;

if ( srcTexture.isDepthTexture ) mask = _gl.DEPTH_BUFFER_BIT;

_gl.blitFramebuffer( minX, minY, width, height, dstX, dstY, width, height, mask, _gl.NEAREST );

state.bindFramebuffer( _gl.READ_FRAMEBUFFER, null );
state.bindFramebuffer( _gl.DRAW_FRAMEBUFFER, null );

} else {

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

_gl.compressedTexSubImage3D( glTarget, level, dstX, dstY, dstZ, width, height, depth, glFormat, image.data );
_gl.texSubImage3D( glTarget, level, dstX, dstY, dstZ, width, height, depth, glFormat, glType, image.data );

} else {

_gl.texSubImage3D( glTarget, level, dstX, dstY, dstZ, width, height, depth, glFormat, glType, image );
if ( dstTexture.isCompressedArrayTexture ) {

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

} else {

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

}

}

Expand Down
14 changes: 10 additions & 4 deletions src/renderers/webgl/WebGLTextures.js
Original file line number Diff line number Diff line change
Expand Up @@ -1408,6 +1408,9 @@ function WebGLTextures( _gl, extensions, state, properties, capabilities, utils,
const glType = utils.convert( texture.type );
const glInternalFormat = getInternalFormat( texture.internalFormat, glFormat, glType, texture.colorSpace );
const renderTargetProperties = properties.get( renderTarget );
const textureProperties = properties.get( texture );

textureProperties.__renderTarget = renderTarget;

if ( ! renderTargetProperties.__hasExternalTextures ) {

Expand All @@ -1430,11 +1433,11 @@ function WebGLTextures( _gl, extensions, state, properties, capabilities, utils,

if ( useMultisampledRTT( renderTarget ) ) {

multisampledRTTExt.framebufferTexture2DMultisampleEXT( _gl.FRAMEBUFFER, attachment, textureTarget, properties.get( texture ).__webglTexture, 0, getRenderTargetSamples( renderTarget ) );
multisampledRTTExt.framebufferTexture2DMultisampleEXT( _gl.FRAMEBUFFER, attachment, textureTarget, textureProperties.__webglTexture, 0, getRenderTargetSamples( renderTarget ) );

} else if ( textureTarget === _gl.TEXTURE_2D || ( textureTarget >= _gl.TEXTURE_CUBE_MAP_POSITIVE_X && textureTarget <= _gl.TEXTURE_CUBE_MAP_NEGATIVE_Z ) ) { // see #24753

_gl.framebufferTexture2D( _gl.FRAMEBUFFER, attachment, textureTarget, properties.get( texture ).__webglTexture, level );
_gl.framebufferTexture2D( _gl.FRAMEBUFFER, attachment, textureTarget, textureProperties.__webglTexture, level );

}

Expand Down Expand Up @@ -1523,8 +1526,11 @@ function WebGLTextures( _gl, extensions, state, properties, capabilities, utils,

}

const textureProperties = properties.get( renderTarget.depthTexture );
textureProperties.__renderTarget = renderTarget;

// upload an empty depth texture with framebuffer size
if ( ! properties.get( renderTarget.depthTexture ).__webglTexture ||
if ( ! textureProperties.__webglTexture ||
renderTarget.depthTexture.image.width !== renderTarget.width ||
renderTarget.depthTexture.image.height !== renderTarget.height ) {

Expand All @@ -1536,7 +1542,7 @@ function WebGLTextures( _gl, extensions, state, properties, capabilities, utils,

setTexture2D( renderTarget.depthTexture, 0 );

const webglDepthTexture = properties.get( renderTarget.depthTexture ).__webglTexture;
const webglDepthTexture = textureProperties.__webglTexture;
const samples = getRenderTargetSamples( renderTarget );

if ( renderTarget.depthTexture.format === DepthFormat ) {
Expand Down