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

WebGLRenderTarget: Add support for swapping textures #19851

Closed
wants to merge 3 commits into from
Closed
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
5 changes: 5 additions & 0 deletions docs/api/en/renderers/WebGLRenderTarget.html
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,11 @@ <h3>[method:null setSize]( [param:Number width], [param:Number height] )</h3>
Sets the size of the render target.
</p>

<h3>[method:Texture swapTexture]( [param:Texture newTexture] )</h3>
<p>
Detaches the color texture from the render target and returns it. A new replacement texture can be passed in, and if it is not passed in then one is created automatically with the same parameters as the old texture.
</p>

<h3>[method:WebGLRenderTarget clone]()</h3>
<p>
Creates a copy of this render target.
Expand Down
35 changes: 11 additions & 24 deletions examples/webgl_materials_cubemap_dynamic.html
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
var camera, scene, renderer;
var cube, sphere, torus, material;

var count = 0, cubeCamera1, cubeCamera2, cubeRenderTarget1, cubeRenderTarget2;
var cubeCamera, cubeRenderTarget;

var onPointerDownPointerX, onPointerDownPointerY, onPointerDownLon, onPointerDownLat;

Expand All @@ -26,6 +26,8 @@

var textureLoader = new THREE.TextureLoader();

var frontBuffer = undefined;

textureLoader.load( 'textures/2294472375_24a3b8ef46_o.jpg', function ( texture ) {

texture.mapping = THREE.UVMapping;
Expand Down Expand Up @@ -57,21 +59,15 @@

//

cubeRenderTarget1 = new THREE.WebGLCubeRenderTarget( 256, { format: THREE.RGBFormat, generateMipmaps: true, minFilter: THREE.LinearMipmapLinearFilter } );
cubeCamera1 = new THREE.CubeCamera( 1, 1000, cubeRenderTarget1 );
scene.add( cubeCamera1 );

cubeRenderTarget2 = new THREE.WebGLCubeRenderTarget( 256, { format: THREE.RGBFormat, generateMipmaps: true, minFilter: THREE.LinearMipmapLinearFilter } );
cubeCamera2 = new THREE.CubeCamera( 1, 1000, cubeRenderTarget2 );
scene.add( cubeCamera2 );
cubeRenderTarget = new THREE.WebGLCubeRenderTarget( 256, { format: THREE.RGBFormat, generateMipmaps: true, minFilter: THREE.LinearMipmapLinearFilter } );
cubeCamera = new THREE.CubeCamera( 1, 1000, cubeRenderTarget );
scene.add( cubeCamera );

document.body.appendChild( renderer.domElement );

//

material = new THREE.MeshBasicMaterial( {
envMap: cubeRenderTarget2.texture
} );
material = new THREE.MeshBasicMaterial();

sphere = new THREE.Mesh( new THREE.IcosahedronBufferGeometry( 20, 3 ), material );
scene.add( sphere );
Expand Down Expand Up @@ -178,19 +174,10 @@

// pingpong

if ( count % 2 === 0 ) {

cubeCamera1.update( renderer, scene );
material.envMap = cubeRenderTarget1.texture;

} else {

cubeCamera2.update( renderer, scene );
material.envMap = cubeRenderTarget2.texture;

}

count ++;
cubeCamera.update( renderer, scene );
frontBuffer = cubeRenderTarget.swapTexture( frontBuffer );
material.envMap = frontBuffer;
material.needsUpdate = true;

renderer.render( scene, camera );

Expand Down
1 change: 1 addition & 0 deletions src/renderers/WebGLRenderTarget.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,7 @@ export class WebGLRenderTarget extends EventDispatcher {
generateMipmaps: any;

setSize( width: number, height: number ): void;
swapTexture( newTexture?: Texture ): Texture;
clone(): this;
copy( source: WebGLRenderTarget ): this;
dispose(): void;
Expand Down
58 changes: 58 additions & 0 deletions src/renderers/WebGLRenderTarget.js
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,64 @@ WebGLRenderTarget.prototype = Object.assign( Object.create( EventDispatcher.prot

},

swapTexture: function ( newTexture ) {

var oldTexture = this.texture;

if ( ! newTexture ) {

newTexture = new Texture( undefined, oldTexture.mapping, oldTexture.wrapS, oldTexture.wrapT, oldTexture.magFilter, oldTexture.minFilter, oldTexture.format, oldTexture.type, oldTexture.anisotropy, oldTexture.encoding );

newTexture.image = {};
newTexture.image.width = this.width;
newTexture.image.height = this.height;

} else {

// Check that the format and type of the new texture match the old - otherwise we can't swap.

if ( newTexture.isCubeTexture === true || newTexture.isCanvasTexture === true || newTexture.isCompressedTexture === true || newTexture.isDataTexture === true || newTexture.isDepthTexture === true || newTexture.isVideoTexture === true || newTexture.isDataTexture3D === true || newTexture.isDataTexture2DArray === true ) {

console.error( "Can only swap a regular Texture on a WebGLRenderTarget" );
return null;

}

if ( newTexture.format !== oldTexture.format ) {

console.error( "Render target texture can only be swapped with a texture with the same format." );
return null;

}

if ( newTexture.type !== oldTexture.type ) {

console.error( "Render target texture can only be swapped with a texture with the same type." );
return null;

}

if ( newTexture.image !== undefined ) {

if ( newTexture.image.width !== undefined && newTexture.image.height !== undefined ) {

this.width = newTexture.image.width;
this.height = newTexture.image.height;

}

}

}

this.texture = newTexture;

this.dispatchEvent( { type: 'textureAttachmentChange' } );

return oldTexture;

},

clone: function () {

return new this.constructor().copy( this );
Expand Down
9 changes: 4 additions & 5 deletions src/renderers/WebGLRenderer.js
Original file line number Diff line number Diff line change
Expand Up @@ -128,7 +128,6 @@ function WebGLRenderer( parameters ) {
let _currentActiveCubeFace = 0;
let _currentActiveMipmapLevel = 0;
let _currentRenderTarget = null;
let _currentFramebuffer = null;
let _currentMaterialId = - 1;

let _currentCamera = null;
Expand Down Expand Up @@ -1833,10 +1832,10 @@ function WebGLRenderer( parameters ) {

}

if ( _currentFramebuffer !== framebuffer ) {
if ( textures.currentFramebuffer !== framebuffer ) {

_gl.bindFramebuffer( _gl.FRAMEBUFFER, framebuffer );
_currentFramebuffer = framebuffer;
textures.currentFramebuffer = framebuffer;

}

Expand Down Expand Up @@ -1874,7 +1873,7 @@ function WebGLRenderer( parameters ) {

let restore = false;

if ( framebuffer !== _currentFramebuffer ) {
if ( framebuffer !== textures.currentFramebuffer ) {

_gl.bindFramebuffer( _gl.FRAMEBUFFER, framebuffer );

Expand Down Expand Up @@ -1924,7 +1923,7 @@ function WebGLRenderer( parameters ) {

if ( restore ) {

_gl.bindFramebuffer( _gl.FRAMEBUFFER, _currentFramebuffer );
_gl.bindFramebuffer( _gl.FRAMEBUFFER, textures.currentFramebuffer );

}

Expand Down
93 changes: 72 additions & 21 deletions src/renderers/webgl/WebGLTextures.js
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@ function WebGLTextures( _gl, extensions, state, properties, capabilities, utils,

let useOffscreenCanvas = false;

let currentFramebuffer = null;

try {

useOffscreenCanvas = typeof OffscreenCanvas !== 'undefined'
Expand Down Expand Up @@ -232,13 +234,52 @@ function WebGLTextures( _gl, extensions, state, properties, capabilities, utils,

}

function onRenderTargetTextureAttachmentChange( event ) {

const renderTarget = event.target;

const renderTargetProperties = properties.get( renderTarget );

const textureProperties = properties.get( renderTarget.texture );

if ( textureProperties.__webglTexture === undefined ) {

// Framebuffer has been set up but the texture has not.
setupColorBuffer( renderTarget, renderTargetProperties );
return;

}

const isCube = ( renderTarget.isWebGLCubeRenderTarget === true );

if ( isCube ) {

for ( let i = 0; i < 6; i ++ ) {

_gl.bindFramebuffer( _gl.FRAMEBUFFER, renderTargetProperties.__webglFramebuffer[ i ] );
_gl.framebufferTexture2D( _gl.FRAMEBUFFER, _gl.COLOR_ATTACHMENT0, _gl.TEXTURE_CUBE_MAP_POSITIVE_X + i, textureProperties.__webglTexture, 0 );

}

_gl.bindFramebuffer( _gl.FRAMEBUFFER, currentFramebuffer );

} else {

_gl.bindFramebuffer( _gl.FRAMEBUFFER, renderTargetProperties.__webglFramebuffer );
_gl.framebufferTexture2D( _gl.FRAMEBUFFER, _gl.COLOR_ATTACHMENT0, _gl.TEXTURE_2D, textureProperties.__webglTexture, 0 );
_gl.bindFramebuffer( _gl.FRAMEBUFFER, currentFramebuffer );

}

}

//

function deallocateTexture( texture ) {

const textureProperties = properties.get( texture );

if ( textureProperties.__webglInit === undefined ) return;
if ( textureProperties.__webglTexture === undefined ) return;

_gl.deleteTexture( textureProperties.__webglTexture );

Expand Down Expand Up @@ -605,9 +646,7 @@ function WebGLTextures( _gl, extensions, state, properties, capabilities, utils,

function initTexture( textureProperties, texture ) {

if ( textureProperties.__webglInit === undefined ) {

textureProperties.__webglInit = true;
if ( textureProperties.__webglTexture === undefined ) {

texture.addEventListener( 'dispose', onTextureDispose );

Expand Down Expand Up @@ -842,7 +881,7 @@ function WebGLTextures( _gl, extensions, state, properties, capabilities, utils,
state.texImage2D( textureTarget, 0, glInternalFormat, renderTarget.width, renderTarget.height, 0, glFormat, glType, null );
_gl.bindFramebuffer( _gl.FRAMEBUFFER, framebuffer );
_gl.framebufferTexture2D( _gl.FRAMEBUFFER, attachment, textureTarget, properties.get( renderTarget.texture ).__webglTexture, 0 );
_gl.bindFramebuffer( _gl.FRAMEBUFFER, null );
_gl.bindFramebuffer( _gl.FRAMEBUFFER, currentFramebuffer );

}

Expand Down Expand Up @@ -1008,25 +1047,21 @@ function WebGLTextures( _gl, extensions, state, properties, capabilities, utils,

}

_gl.bindFramebuffer( _gl.FRAMEBUFFER, null );
_gl.bindFramebuffer( _gl.FRAMEBUFFER, currentFramebuffer );

}

// Set up GL resources for the render target
function setupRenderTarget( renderTarget ) {

const renderTargetProperties = properties.get( renderTarget );
const textureProperties = properties.get( renderTarget.texture );

renderTarget.addEventListener( 'dispose', onRenderTargetDispose );

textureProperties.__webglTexture = _gl.createTexture();

info.memory.textures ++;
renderTarget.addEventListener( 'textureAttachmentChange', onRenderTargetTextureAttachmentChange );

const isCube = ( renderTarget.isWebGLCubeRenderTarget === true );
const isMultisample = ( renderTarget.isWebGLMultisampleRenderTarget === true );
const supportsMips = isPowerOfTwo( renderTarget ) || isWebGL2;

// Handles WebGL2 RGBFormat fallback - #18858

Expand Down Expand Up @@ -1080,7 +1115,7 @@ function WebGLTextures( _gl, extensions, state, properties, capabilities, utils,

}

_gl.bindFramebuffer( _gl.FRAMEBUFFER, null );
_gl.bindFramebuffer( _gl.FRAMEBUFFER, currentFramebuffer );


} else {
Expand All @@ -1093,7 +1128,29 @@ function WebGLTextures( _gl, extensions, state, properties, capabilities, utils,

}

// Setup color buffer
setupColorBuffer( renderTarget, renderTargetProperties );

// Setup depth and stencil buffers

if ( renderTarget.depthBuffer ) {

setupDepthRenderbuffer( renderTarget );

}

}

// Set up GL resources for the non-multisampled color buffer
function setupColorBuffer( renderTarget, renderTargetProperties ) {

const textureProperties = properties.get( renderTarget.texture );

const isCube = ( renderTarget.isWebGLCubeRenderTarget === true );
const supportsMips = isPowerOfTwo( renderTarget ) || isWebGL2;

textureProperties.__webglTexture = _gl.createTexture();

info.memory.textures ++;

if ( isCube ) {

Expand Down Expand Up @@ -1130,14 +1187,6 @@ function WebGLTextures( _gl, extensions, state, properties, capabilities, utils,

}

// Setup depth and stencil buffers

if ( renderTarget.depthBuffer ) {

setupDepthRenderbuffer( renderTarget );

}

}

function updateRenderTargetMipmap( renderTarget ) {
Expand Down Expand Up @@ -1287,6 +1336,8 @@ function WebGLTextures( _gl, extensions, state, properties, capabilities, utils,
this.safeSetTexture2D = safeSetTexture2D;
this.safeSetTextureCube = safeSetTextureCube;

Object.defineProperty(this, "currentFramebuffer", { get() { return currentFramebuffer; }, set(newValue) { currentFramebuffer = newValue; } })

}

export { WebGLTextures };