|
@@ -4742,6 +4742,37 @@
|
|
|
|
|
|
} );
|
|
|
|
|
|
+ /**
|
|
|
+ * @author Mugen87 / https://github.com/Mugen87
|
|
|
+ * @author Matt DesLauriers / @mattdesl
|
|
|
+ */
|
|
|
+
|
|
|
+ function WebGLMultisampleRenderTarget( width, height, options ) {
|
|
|
+
|
|
|
+ WebGLRenderTarget.call( this, width, height, options );
|
|
|
+
|
|
|
+ this.samples = 4;
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+ WebGLMultisampleRenderTarget.prototype = Object.assign( Object.create( WebGLRenderTarget.prototype ), {
|
|
|
+
|
|
|
+ constructor: WebGLMultisampleRenderTarget,
|
|
|
+
|
|
|
+ isWebGLMultisampleRenderTarget: true,
|
|
|
+
|
|
|
+ copy: function ( source ) {
|
|
|
+
|
|
|
+ WebGLRenderTarget.prototype.copy.call( this, source );
|
|
|
+
|
|
|
+ this.samples = source.samples;
|
|
|
+
|
|
|
+ return this;
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+ } );
|
|
|
+
|
|
|
/**
|
|
|
* @author alteredq / http://alteredqualia.com
|
|
|
*/
|
|
@@ -13120,6 +13151,13 @@
|
|
|
value: value.toArray()
|
|
|
};
|
|
|
|
|
|
+ } else if ( value && value.isMatrix3 ) {
|
|
|
+
|
|
|
+ data.uniforms[ name ] = {
|
|
|
+ type: 'm3',
|
|
|
+ value: value.toArray()
|
|
|
+ };
|
|
|
+
|
|
|
} else if ( value && value.isMatrix4 ) {
|
|
|
|
|
|
data.uniforms[ name ] = {
|
|
@@ -14940,6 +14978,8 @@
|
|
|
var floatFragmentTextures = isWebGL2 || !! extensions.get( 'OES_texture_float' );
|
|
|
var floatVertexTextures = vertexTextures && floatFragmentTextures;
|
|
|
|
|
|
+ var maxSamples = isWebGL2 ? gl.getParameter( 36183 ) : 0;
|
|
|
+
|
|
|
return {
|
|
|
|
|
|
isWebGL2: isWebGL2,
|
|
@@ -14962,7 +15002,9 @@
|
|
|
|
|
|
vertexTextures: vertexTextures,
|
|
|
floatFragmentTextures: floatFragmentTextures,
|
|
|
- floatVertexTextures: floatVertexTextures
|
|
|
+ floatVertexTextures: floatVertexTextures,
|
|
|
+
|
|
|
+ maxSamples: maxSamples
|
|
|
|
|
|
};
|
|
|
|
|
@@ -17892,6 +17934,16 @@
|
|
|
|
|
|
var lists = {};
|
|
|
|
|
|
+ function onSceneDispose( event ) {
|
|
|
+
|
|
|
+ var scene = event.target;
|
|
|
+
|
|
|
+ scene.removeEventListener( 'dispose', onSceneDispose );
|
|
|
+
|
|
|
+ delete lists[ scene.id ];
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
function get( scene, camera ) {
|
|
|
|
|
|
var cameras = lists[ scene.id ];
|
|
@@ -17902,6 +17954,8 @@
|
|
|
lists[ scene.id ] = {};
|
|
|
lists[ scene.id ][ camera.id ] = list;
|
|
|
|
|
|
+ scene.addEventListener( 'dispose', onSceneDispose );
|
|
|
+
|
|
|
} else {
|
|
|
|
|
|
list = cameras[ camera.id ];
|
|
@@ -18327,6 +18381,16 @@
|
|
|
|
|
|
var renderStates = {};
|
|
|
|
|
|
+ function onSceneDispose( event ) {
|
|
|
+
|
|
|
+ var scene = event.target;
|
|
|
+
|
|
|
+ scene.removeEventListener( 'dispose', onSceneDispose );
|
|
|
+
|
|
|
+ delete renderStates[ scene.id ];
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
function get( scene, camera ) {
|
|
|
|
|
|
var renderState;
|
|
@@ -18337,6 +18401,8 @@
|
|
|
renderStates[ scene.id ] = {};
|
|
|
renderStates[ scene.id ][ camera.id ] = renderState;
|
|
|
|
|
|
+ scene.addEventListener( 'dispose', onSceneDispose );
|
|
|
+
|
|
|
} else {
|
|
|
|
|
|
if ( renderStates[ scene.id ][ camera.id ] === undefined ) {
|
|
@@ -19931,60 +19997,55 @@
|
|
|
|
|
|
//
|
|
|
|
|
|
- function clampToMaxSize( image, maxSize ) {
|
|
|
+ function resizeImage( image, needsPowerOfTwo, needsNewCanvas, maxSize ) {
|
|
|
|
|
|
- if ( image.width > maxSize || image.height > maxSize ) {
|
|
|
+ var scale = 1;
|
|
|
|
|
|
- if ( 'data' in image ) {
|
|
|
+ // handle case if texture exceeds max size
|
|
|
|
|
|
- console.warn( 'THREE.WebGLRenderer: image in DataTexture is too big (' + image.width + 'x' + image.height + ').' );
|
|
|
- return;
|
|
|
+ if ( image.width > maxSize || image.height > maxSize ) {
|
|
|
|
|
|
- }
|
|
|
+ scale = maxSize / Math.max( image.width, image.height );
|
|
|
|
|
|
- // Warning: Scaling through the canvas will only work with images that use
|
|
|
- // premultiplied alpha.
|
|
|
+ }
|
|
|
|
|
|
- var scale = maxSize / Math.max( image.width, image.height );
|
|
|
+ // only perform resize if necessary
|
|
|
|
|
|
- var canvas = document.createElementNS( 'http://www.w3.org/1999/xhtml', 'canvas' );
|
|
|
- canvas.width = Math.floor( image.width * scale );
|
|
|
- canvas.height = Math.floor( image.height * scale );
|
|
|
+ if ( scale < 1 || needsPowerOfTwo === true ) {
|
|
|
|
|
|
- var context = canvas.getContext( '2d' );
|
|
|
- context.drawImage( image, 0, 0, image.width, image.height, 0, 0, canvas.width, canvas.height );
|
|
|
+ // only perform resize for certain image types
|
|
|
|
|
|
- console.warn( 'THREE.WebGLRenderer: image is too big (' + image.width + 'x' + image.height + '). Resized to ' + canvas.width + 'x' + canvas.height );
|
|
|
+ if ( image instanceof HTMLImageElement || image instanceof HTMLCanvasElement || image instanceof ImageBitmap ) {
|
|
|
|
|
|
- return canvas;
|
|
|
+ if ( _canvas === undefined ) _canvas = document.createElementNS( 'http://www.w3.org/1999/xhtml', 'canvas' );
|
|
|
|
|
|
- }
|
|
|
+ // cube textures can't reuse the same canvas
|
|
|
|
|
|
- return image;
|
|
|
+ var canvas = needsNewCanvas ? document.createElementNS( 'http://www.w3.org/1999/xhtml', 'canvas' ) : _canvas;
|
|
|
|
|
|
- }
|
|
|
+ var floor = needsPowerOfTwo ? _Math.floorPowerOfTwo : Math.floor;
|
|
|
|
|
|
- function isPowerOfTwo( image ) {
|
|
|
+ canvas.width = floor( scale * image.width );
|
|
|
+ canvas.height = floor( scale * image.height );
|
|
|
|
|
|
- return _Math.isPowerOfTwo( image.width ) && _Math.isPowerOfTwo( image.height );
|
|
|
+ var context = canvas.getContext( '2d' );
|
|
|
+ context.drawImage( image, 0, 0, canvas.width, canvas.height );
|
|
|
|
|
|
- }
|
|
|
+ console.warn( 'THREE.WebGLRenderer: Texture has been resized from (' + image.width + 'x' + image.height + ') to (' + canvas.width + 'x' + canvas.height + ').' );
|
|
|
|
|
|
- function makePowerOfTwo( image ) {
|
|
|
+ return canvas;
|
|
|
|
|
|
- if ( image instanceof HTMLImageElement || image instanceof HTMLCanvasElement || image instanceof ImageBitmap ) {
|
|
|
+ } else {
|
|
|
|
|
|
- if ( _canvas === undefined ) _canvas = document.createElementNS( 'http://www.w3.org/1999/xhtml', 'canvas' );
|
|
|
+ if ( 'data' in image ) {
|
|
|
|
|
|
- _canvas.width = _Math.floorPowerOfTwo( image.width );
|
|
|
- _canvas.height = _Math.floorPowerOfTwo( image.height );
|
|
|
+ console.warn( 'THREE.WebGLRenderer: Image in DataTexture is too big (' + image.width + 'x' + image.height + ').' );
|
|
|
|
|
|
- var context = _canvas.getContext( '2d' );
|
|
|
- context.drawImage( image, 0, 0, _canvas.width, _canvas.height );
|
|
|
+ }
|
|
|
|
|
|
- console.warn( 'THREE.WebGLRenderer: image is not power of two (' + image.width + 'x' + image.height + '). Resized to ' + _canvas.width + 'x' + _canvas.height );
|
|
|
+ return image;
|
|
|
|
|
|
- return _canvas;
|
|
|
+ }
|
|
|
|
|
|
}
|
|
|
|
|
@@ -19992,6 +20053,12 @@
|
|
|
|
|
|
}
|
|
|
|
|
|
+ function isPowerOfTwo( image ) {
|
|
|
+
|
|
|
+ return _Math.isPowerOfTwo( image.width ) && _Math.isPowerOfTwo( image.height );
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
function textureNeedsPowerOfTwo( texture ) {
|
|
|
|
|
|
if ( capabilities.isWebGL2 ) return false;
|
|
@@ -20262,7 +20329,7 @@
|
|
|
|
|
|
if ( ! isCompressed && ! isDataTexture ) {
|
|
|
|
|
|
- cubeImage[ i ] = clampToMaxSize( texture.image[ i ], capabilities.maxCubemapSize );
|
|
|
+ cubeImage[ i ] = resizeImage( texture.image[ i ], false, true, capabilities.maxCubemapSize );
|
|
|
|
|
|
} else {
|
|
|
|
|
@@ -20454,13 +20521,8 @@
|
|
|
_gl.pixelStorei( 37441, texture.premultiplyAlpha );
|
|
|
_gl.pixelStorei( 3317, texture.unpackAlignment );
|
|
|
|
|
|
- var image = clampToMaxSize( texture.image, capabilities.maxTextureSize );
|
|
|
-
|
|
|
- if ( textureNeedsPowerOfTwo( texture ) && isPowerOfTwo( image ) === false ) {
|
|
|
-
|
|
|
- image = makePowerOfTwo( image );
|
|
|
-
|
|
|
- }
|
|
|
+ var needsPowerOfTwo = textureNeedsPowerOfTwo( texture ) && isPowerOfTwo( texture.image ) === false;
|
|
|
+ var image = resizeImage( texture.image, needsPowerOfTwo, false, capabilities.maxTextureSize );
|
|
|
|
|
|
var isPowerOfTwoImage = isPowerOfTwo( image ),
|
|
|
glFormat = utils.convert( texture.format ),
|
|
@@ -20642,24 +20704,60 @@
|
|
|
}
|
|
|
|
|
|
// Setup storage for internal depth/stencil buffers and bind to correct framebuffer
|
|
|
- function setupRenderBufferStorage( renderbuffer, renderTarget ) {
|
|
|
+ function setupRenderBufferStorage( renderbuffer, renderTarget, isMultisample ) {
|
|
|
|
|
|
_gl.bindRenderbuffer( 36161, renderbuffer );
|
|
|
|
|
|
if ( renderTarget.depthBuffer && ! renderTarget.stencilBuffer ) {
|
|
|
|
|
|
- _gl.renderbufferStorage( 36161, 33189, renderTarget.width, renderTarget.height );
|
|
|
+ if ( isMultisample ) {
|
|
|
+
|
|
|
+ var samples = getRenderTargetSamples( renderTarget );
|
|
|
+
|
|
|
+ _gl.renderbufferStorageMultisample( 36161, samples, 33189, renderTarget.width, renderTarget.height );
|
|
|
+
|
|
|
+ } else {
|
|
|
+
|
|
|
+ _gl.renderbufferStorage( 36161, 33189, renderTarget.width, renderTarget.height );
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
_gl.framebufferRenderbuffer( 36160, 36096, 36161, renderbuffer );
|
|
|
|
|
|
} else if ( renderTarget.depthBuffer && renderTarget.stencilBuffer ) {
|
|
|
|
|
|
- _gl.renderbufferStorage( 36161, 34041, renderTarget.width, renderTarget.height );
|
|
|
+ if ( isMultisample ) {
|
|
|
+
|
|
|
+ var samples = getRenderTargetSamples( renderTarget );
|
|
|
+
|
|
|
+ _gl.renderbufferStorageMultisample( 36161, samples, 34041, renderTarget.width, renderTarget.height );
|
|
|
+
|
|
|
+ } else {
|
|
|
+
|
|
|
+ _gl.renderbufferStorage( 36161, 34041, renderTarget.width, renderTarget.height );
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
_gl.framebufferRenderbuffer( 36160, 33306, 36161, renderbuffer );
|
|
|
|
|
|
} else {
|
|
|
|
|
|
- // FIXME: We don't support !depth !stencil
|
|
|
- _gl.renderbufferStorage( 36161, 32854, renderTarget.width, renderTarget.height );
|
|
|
+ var glFormat = utils.convert( renderTarget.texture.format );
|
|
|
+ var glType = utils.convert( renderTarget.texture.type );
|
|
|
+ var glInternalFormat = getInternalFormat( glFormat, glType );
|
|
|
+
|
|
|
+ if ( isMultisample ) {
|
|
|
+
|
|
|
+ var samples = getRenderTargetSamples( renderTarget );
|
|
|
+
|
|
|
+ _gl.renderbufferStorageMultisample( 36161, samples, glInternalFormat, renderTarget.width, renderTarget.height );
|
|
|
+
|
|
|
+ } else {
|
|
|
+
|
|
|
+ _gl.renderbufferStorage( 36161, glInternalFormat, renderTarget.width, renderTarget.height );
|
|
|
+
|
|
|
+ }
|
|
|
|
|
|
}
|
|
|
|
|
@@ -20766,6 +20864,7 @@
|
|
|
info.memory.textures ++;
|
|
|
|
|
|
var isCube = ( renderTarget.isWebGLRenderTargetCube === true );
|
|
|
+ var isMultisample = ( renderTarget.isWebGLMultisampleRenderTarget === true );
|
|
|
var isTargetPowerOfTwo = isPowerOfTwo( renderTarget );
|
|
|
|
|
|
// Setup framebuffer
|
|
@@ -20784,6 +20883,42 @@
|
|
|
|
|
|
renderTargetProperties.__webglFramebuffer = _gl.createFramebuffer();
|
|
|
|
|
|
+ if ( isMultisample ) {
|
|
|
+
|
|
|
+ if ( capabilities.isWebGL2 ) {
|
|
|
+
|
|
|
+ renderTargetProperties.__webglMultisampledFramebuffer = _gl.createFramebuffer();
|
|
|
+ renderTargetProperties.__webglColorRenderbuffer = _gl.createRenderbuffer();
|
|
|
+
|
|
|
+ _gl.bindRenderbuffer( 36161, renderTargetProperties.__webglColorRenderbuffer );
|
|
|
+ var glFormat = utils.convert( renderTarget.texture.format );
|
|
|
+ var glType = utils.convert( renderTarget.texture.type );
|
|
|
+ var glInternalFormat = getInternalFormat( glFormat, glType );
|
|
|
+ var samples = getRenderTargetSamples( renderTarget );
|
|
|
+ _gl.renderbufferStorageMultisample( 36161, samples, glInternalFormat, renderTarget.width, renderTarget.height );
|
|
|
+
|
|
|
+ _gl.bindFramebuffer( 36160, renderTargetProperties.__webglMultisampledFramebuffer );
|
|
|
+ _gl.framebufferRenderbuffer( 36160, 36064, 36161, renderTargetProperties.__webglColorRenderbuffer );
|
|
|
+ _gl.bindRenderbuffer( 36161, null );
|
|
|
+
|
|
|
+ if ( renderTarget.depthBuffer ) {
|
|
|
+
|
|
|
+ renderTargetProperties.__webglDepthRenderbuffer = _gl.createRenderbuffer();
|
|
|
+ setupRenderBufferStorage( renderTargetProperties.__webglDepthRenderbuffer, renderTarget, true );
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+ _gl.bindFramebuffer( 36160, null );
|
|
|
+
|
|
|
+
|
|
|
+ } else {
|
|
|
+
|
|
|
+ console.warn( 'THREE.WebGLRenderer: WebGLMultisampleRenderTarget can only be used with WebGL2.' );
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
}
|
|
|
|
|
|
// Setup color buffer
|
|
@@ -20851,6 +20986,43 @@
|
|
|
|
|
|
}
|
|
|
|
|
|
+ function updateMultisampleRenderTarget( renderTarget ) {
|
|
|
+
|
|
|
+ if ( renderTarget.isWebGLMultisampleRenderTarget ) {
|
|
|
+
|
|
|
+ if ( capabilities.isWebGL2 ) {
|
|
|
+
|
|
|
+ var renderTargetProperties = properties.get( renderTarget );
|
|
|
+
|
|
|
+ _gl.bindFramebuffer( 36008, renderTargetProperties.__webglMultisampledFramebuffer );
|
|
|
+ _gl.bindFramebuffer( 36009, renderTargetProperties.__webglFramebuffer );
|
|
|
+
|
|
|
+ var width = renderTarget.width;
|
|
|
+ var height = renderTarget.height;
|
|
|
+ var mask = 16384;
|
|
|
+
|
|
|
+ if ( renderTarget.depthBuffer ) mask |= 256;
|
|
|
+ if ( renderTarget.stencilBuffer ) mask |= 1024;
|
|
|
+
|
|
|
+ _gl.blitFramebuffer( 0, 0, width, height, 0, 0, width, height, mask, 9728 );
|
|
|
+
|
|
|
+ } else {
|
|
|
+
|
|
|
+ console.warn( 'THREE.WebGLRenderer: WebGLMultisampleRenderTarget can only be used with WebGL2.' );
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+ function getRenderTargetSamples( renderTarget ) {
|
|
|
+
|
|
|
+ return ( capabilities.isWebGL2 && renderTarget.isWebGLMultisampleRenderTarget ) ?
|
|
|
+ Math.min( capabilities.maxSamples, renderTarget.samples ) : 0;
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
function updateVideoTexture( texture ) {
|
|
|
|
|
|
var id = texture.id;
|
|
@@ -20873,6 +21045,7 @@
|
|
|
this.setTextureCubeDynamic = setTextureCubeDynamic;
|
|
|
this.setupRenderTarget = setupRenderTarget;
|
|
|
this.updateRenderTargetMipmap = updateRenderTargetMipmap;
|
|
|
+ this.updateMultisampleRenderTarget = updateMultisampleRenderTarget;
|
|
|
|
|
|
}
|
|
|
|
|
@@ -23237,12 +23410,18 @@
|
|
|
|
|
|
}
|
|
|
|
|
|
- // Generate mipmap if we're using any kind of mipmap filtering
|
|
|
+ //
|
|
|
|
|
|
if ( renderTarget ) {
|
|
|
|
|
|
+ // Generate mipmap if we're using any kind of mipmap filtering
|
|
|
+
|
|
|
textures.updateRenderTargetMipmap( renderTarget );
|
|
|
|
|
|
+ // resolve multisample renderbuffers to a single-sample texture if necessary
|
|
|
+
|
|
|
+ textures.updateMultisampleRenderTarget( renderTarget );
|
|
|
+
|
|
|
}
|
|
|
|
|
|
// Ensure depth buffer writing is enabled so it can be cleared on next render
|
|
@@ -24598,6 +24777,10 @@
|
|
|
framebuffer = __webglFramebuffer[ renderTarget.activeCubeFace ];
|
|
|
isCube = true;
|
|
|
|
|
|
+ } else if ( renderTarget.isWebGLMultisampleRenderTarget ) {
|
|
|
+
|
|
|
+ framebuffer = properties.get( renderTarget ).__webglMultisampledFramebuffer;
|
|
|
+
|
|
|
} else {
|
|
|
|
|
|
framebuffer = __webglFramebuffer;
|
|
@@ -24859,6 +25042,12 @@
|
|
|
|
|
|
return data;
|
|
|
|
|
|
+ },
|
|
|
+
|
|
|
+ dispose: function () {
|
|
|
+
|
|
|
+ this.dispatchEvent( { type: 'dispose' } );
|
|
|
+
|
|
|
}
|
|
|
|
|
|
} );
|
|
@@ -37349,6 +37538,9 @@
|
|
|
material.uniforms[ name ].value = new Vector4().fromArray( uniform.value );
|
|
|
break;
|
|
|
|
|
|
+ case 'm3':
|
|
|
+ material.uniforms[ name ].value = new Matrix3().fromArray( uniform.value );
|
|
|
+
|
|
|
case 'm4':
|
|
|
material.uniforms[ name ].value = new Matrix4().fromArray( uniform.value );
|
|
|
break;
|
|
@@ -39676,6 +39868,8 @@
|
|
|
|
|
|
if ( this.parent === null ) this.updateMatrixWorld();
|
|
|
|
|
|
+ var currentRenderTarget = renderer.getRenderTarget();
|
|
|
+
|
|
|
var renderTarget = this.renderTarget;
|
|
|
var generateMipmaps = renderTarget.texture.generateMipmaps;
|
|
|
|
|
@@ -39701,12 +39895,14 @@
|
|
|
renderTarget.activeCubeFace = 5;
|
|
|
renderer.render( scene, cameraNZ, renderTarget );
|
|
|
|
|
|
- renderer.setRenderTarget( null );
|
|
|
+ renderer.setRenderTarget( currentRenderTarget );
|
|
|
|
|
|
};
|
|
|
|
|
|
this.clear = function ( renderer, color, depth, stencil ) {
|
|
|
|
|
|
+ var currentRenderTarget = renderer.getRenderTarget();
|
|
|
+
|
|
|
var renderTarget = this.renderTarget;
|
|
|
|
|
|
for ( var i = 0; i < 6; i ++ ) {
|
|
@@ -39718,7 +39914,7 @@
|
|
|
|
|
|
}
|
|
|
|
|
|
- renderer.setRenderTarget( null );
|
|
|
+ renderer.setRenderTarget( currentRenderTarget );
|
|
|
|
|
|
};
|
|
|
|
|
@@ -47343,6 +47539,7 @@
|
|
|
|
|
|
}
|
|
|
|
|
|
+ exports.WebGLMultisampleRenderTarget = WebGLMultisampleRenderTarget;
|
|
|
exports.WebGLRenderTargetCube = WebGLRenderTargetCube;
|
|
|
exports.WebGLRenderTarget = WebGLRenderTarget;
|
|
|
exports.WebGLRenderer = WebGLRenderer;
|