Browse Source

WebGLMultiviewRenderTarget added and refactored WebGLMultiview

Fernando Serrano 6 years ago
parent
commit
ea60c3b7c0

+ 37 - 0
src/renderers/WebGLMultiviewRenderTarget.js

@@ -0,0 +1,37 @@
+/**
+ * @author fernandojsg / http://fernandojsg.com
+ * @author Takahiro https://github.com/takahirox
+ */
+
+import { WebGLRenderTarget } from './WebGLRenderTarget.js';
+
+function WebGLMultiviewRenderTarget( width, height, numViews, options ) {
+
+	WebGLRenderTarget.call( this, width, height, options );
+
+	this.depthBuffer = false;
+	this.stencilBuffer = false;
+
+	this.numViews = numViews;
+
+}
+
+WebGLMultiviewRenderTarget.prototype = Object.assign( Object.create( WebGLRenderTarget.prototype ), {
+
+	constructor: WebGLMultiviewRenderTarget,
+
+	isWebGLMultiviewRenderTarget: true,
+
+	copy: function ( source ) {
+
+		WebGLRenderTarget.prototype.copy.call( this, source );
+
+		this.numViews = source.numViews;
+
+		return this;
+
+	}
+
+} );
+
+export { WebGLMultiviewRenderTarget };

+ 13 - 11
src/renderers/WebGLRenderer.js

@@ -315,7 +315,9 @@ function WebGLRenderer( parameters ) {
 
 	this.vr = vr;
 
-	var multiview = this.multiview = new WebGLMultiview( _multiviewRequested, _gl, _canvas, extensions, capabilities, properties );
+	var multiview = new WebGLMultiview( _this, _multiviewRequested );
+
+	this.multiview = multiview;
 
 	// shadow map
 
@@ -1178,13 +1180,13 @@ function WebGLRenderer( parameters ) {
 
 			this.setRenderTarget( renderTarget );
 
-		} else if ( this.multiview.isEnabled() ) {
+		}
 
-			this.setRenderTarget( this.multiview.renderTarget );
-			this.multiview.bindFramebuffer( camera );
+		if ( multiview.isEnabled() ) {
 
-		}
+			multiview.attachRenderTarget( camera );
 
+		}
 
 		//
 
@@ -1230,12 +1232,6 @@ function WebGLRenderer( parameters ) {
 
 			textures.updateMultisampleRenderTarget( _currentRenderTarget );
 
-			if ( this.multiview.isEnabled() ) {
-
-				this.multiview.unbindFramebuffer( camera );
-
-			}
-
 		}
 
 		// Ensure depth buffer writing is enabled so it can be cleared on next render
@@ -1246,6 +1242,12 @@ function WebGLRenderer( parameters ) {
 
 		state.setPolygonOffset( false );
 
+		if ( this.multiview.isEnabled() ) {
+
+			this.multiview.detachRenderTarget( camera );
+
+		}
+
 		if ( vr.enabled ) {
 
 			vr.submitFrame();

+ 25 - 73
src/renderers/webgl/WebGLMultiview.js

@@ -1,12 +1,18 @@
 /**
  * @author fernandojsg / http://fernandojsg.com
+ * @author Takahiro https://github.com/takahirox
  */
 
-import { WebGLRenderTarget } from '../WebGLRenderTarget.js';
+import { WebGLMultiviewRenderTarget } from '../WebGLMultiviewRenderTarget.js';
 import { Matrix3 } from '../../math/Matrix3.js';
 import { Matrix4 } from '../../math/Matrix4.js';
 
-function WebGLMultiview( requested, gl, canvas, extensions, capabilities, properties ) {
+function WebGLMultiview( renderer, requested ) {
+
+	var gl = renderer.context;
+	var canvas = renderer.domElement;
+	var capabilities = renderer.capabilities;
+	var properties = renderer.properties;
 
 	this.isAvailable = function () {
 
@@ -43,15 +49,7 @@ function WebGLMultiview( requested, gl, canvas, extensions, capabilities, proper
 	}
 
 	var numViews = 2;
-	var framebuffer; // multiview framebuffer.
-	var viewFramebuffer; // single views inside the multiview framebuffer.
-	var framebufferWidth = 0;
-	var framebufferHeight = 0;
-
-	var texture = {
-		color: null,
-		depthStencil: null
-	};
+	var renderTarget, currentRenderTarget;
 
 	this.computeCameraMatrices = function ( camera ) {
 
@@ -133,51 +131,11 @@ function WebGLMultiview( requested, gl, canvas, extensions, capabilities, proper
 
 	};
 
-	// @todo Get ArrayCamera
-	this.createMultiviewRenderTargetTexture = function () {
-
-		var halfWidth = Math.floor( canvas.width * 0.5 );
-
-		framebuffer = gl.createFramebuffer();
-		gl.bindFramebuffer( gl.FRAMEBUFFER, framebuffer );
-
-		var ext = extensions.get( 'OVR_multiview2' );
-
-		texture.color = gl.createTexture();
-		gl.bindTexture( gl.TEXTURE_2D_ARRAY, texture.color );
-		gl.texParameteri( gl.TEXTURE_2D_ARRAY, gl.TEXTURE_MAG_FILTER, gl.NEAREST );
-		gl.texParameteri( gl.TEXTURE_2D_ARRAY, gl.TEXTURE_MIN_FILTER, gl.NEAREST );
-		gl.texImage3D( gl.TEXTURE_2D_ARRAY, 0, gl.RGBA8, halfWidth, canvas.height, numViews, 0, gl.RGBA, gl.UNSIGNED_BYTE, null );
-		ext.framebufferTextureMultiviewOVR( gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, texture.color, 0, 0, numViews );
-
-		texture.depthStencil = gl.createTexture();
-		gl.bindTexture( gl.TEXTURE_2D_ARRAY, texture.depthStencil );
-		gl.texParameteri( gl.TEXTURE_2D_ARRAY, gl.TEXTURE_MAG_FILTER, gl.NEAREST );
-		gl.texParameteri( gl.TEXTURE_2D_ARRAY, gl.TEXTURE_MIN_FILTER, gl.NEAREST );
-		gl.texImage3D( gl.TEXTURE_2D_ARRAY, 0, gl.DEPTH24_STENCIL8, halfWidth, canvas.height, numViews, 0, gl.DEPTH_STENCIL, gl.UNSIGNED_INT_24_8, null );
-		ext.framebufferTextureMultiviewOVR( gl.FRAMEBUFFER, gl.DEPTH_STENCIL_ATTACHMENT, texture.depthStencil, 0, 0, numViews );
-
-		viewFramebuffer = new Array( numViews );
-		for ( var viewIndex = 0; viewIndex < numViews; ++ viewIndex ) {
-
-			viewFramebuffer[ viewIndex ] = gl.createFramebuffer();
-			gl.bindFramebuffer( gl.FRAMEBUFFER, viewFramebuffer[ viewIndex ] );
-			gl.framebufferTextureLayer( gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, texture.color, 0, viewIndex );
-
-		}
-
-		framebufferWidth = halfWidth;
-		framebufferHeight = canvas.height;
-
-		this.renderTarget = new WebGLRenderTarget( framebufferWidth, framebufferHeight );
-
-		// @hack This should be done in WebGLTextures?
-		properties.get( this.renderTarget ).__webglFramebuffer = framebuffer;
+	this.attachRenderTarget = function ( camera ) {
 
-	};
-
-	this.bindFramebuffer = function ( camera ) {
+		currentRenderTarget = renderer.getRenderTarget();
 
+		// Resize if needed
 		var width = canvas.width;
 		var height = canvas.height;
 
@@ -191,27 +149,18 @@ function WebGLMultiview( requested, gl, canvas, extensions, capabilities, proper
 
 		}
 
-		if ( framebufferWidth < width || framebufferHeight < height ) {
-
-			console.log( 'WebGLMultiview: Updating multiview FBO with dimensions: ', width, height );
-			gl.bindTexture( gl.TEXTURE_2D_ARRAY, texture.color );
-			gl.texImage3D( gl.TEXTURE_2D_ARRAY, 0, gl.RGBA8, width, height, numViews, 0, gl.RGBA, gl.UNSIGNED_BYTE, null );
-			gl.bindTexture( gl.TEXTURE_2D_ARRAY, texture.depthStencil );
-			gl.texImage3D( gl.TEXTURE_2D_ARRAY, 0, gl.DEPTH24_STENCIL8, width, height, numViews, 0, gl.DEPTH_STENCIL, gl.UNSIGNED_INT_24_8, null );
-			framebufferWidth = width;
-			framebufferHeight = height;
+		renderTarget.setSize( width, height );
 
-			this.renderTarget.setSize( width, height );
-
-		}
-
-		gl.bindFramebuffer( gl.DRAW_FRAMEBUFFER, framebuffer );
+		renderer.setRenderTarget( renderTarget );
 
 	};
 
-	this.unbindFramebuffer = function ( camera ) {
+	this.detachRenderTarget = function ( camera ) {
 
-		gl.bindFramebuffer( gl.DRAW_FRAMEBUFFER, null );
+		var viewFramebuffers = properties.get( renderTarget ).__webglViewFramebuffers;
+
+		// @todo Use actual framebuffer
+		gl.bindFramebuffer( gl.FRAMEBUFFER, null );
 
 		if ( camera.isArrayCamera ) {
 
@@ -224,24 +173,27 @@ function WebGLMultiview( requested, gl, canvas, extensions, capabilities, proper
 				var width = bounds.z * canvas.width;
 				var height = bounds.w * canvas.height;
 
-				gl.bindFramebuffer( gl.READ_FRAMEBUFFER, viewFramebuffer[ i ] );
+				gl.bindFramebuffer( gl.READ_FRAMEBUFFER, viewFramebuffers[ i ] );
 				gl.blitFramebuffer( 0, 0, width, height, x, y, x + width, y + height, gl.COLOR_BUFFER_BIT, gl.NEAREST );
 
 			}
 
 		} else {
 
-			gl.bindFramebuffer( gl.READ_FRAMEBUFFER, viewFramebuffer[ 0 ] );
+			// If no array camera, blit just one view
+			gl.bindFramebuffer( gl.READ_FRAMEBUFFER, viewFramebuffers[ 0 ] );
 			gl.blitFramebuffer( 0, 0, canvas.width, canvas.height, 0, 0, canvas.width, canvas.height, gl.COLOR_BUFFER_BIT, gl.NEAREST );
 
 		}
 
+		renderer.setRenderTarget( currentRenderTarget );
+
 	};
 
 
 	if ( this.isEnabled() ) {
 
-		this.createMultiviewRenderTargetTexture();
+		renderTarget = new WebGLMultiviewRenderTarget( canvas.width, canvas.height, numViews );
 
 	}
 

+ 50 - 1
src/renderers/webgl/WebGLTextures.js

@@ -944,6 +944,7 @@ function WebGLTextures( _gl, extensions, state, properties, capabilities, utils,
 
 		var isCube = ( renderTarget.isWebGLRenderTargetCube === true );
 		var isMultisample = ( renderTarget.isWebGLMultisampleRenderTarget === true );
+		var isMultiview = ( renderTarget.isWebGLMultiviewRenderTarget === true );
 		var supportsMips = isPowerOfTwo( renderTarget ) || capabilities.isWebGL2;
 
 		// Setup framebuffer
@@ -996,6 +997,54 @@ function WebGLTextures( _gl, extensions, state, properties, capabilities, utils,
 
 				}
 
+			} else if ( isMultiview ) {
+
+				if ( capabilities.multiview ) {
+
+					var width = renderTarget.width;
+					var height = renderTarget.height;
+					var numViews = renderTarget.numViews;
+
+					_gl.bindFramebuffer( _gl.FRAMEBUFFER, renderTargetProperties.__webglFramebuffer );
+
+					var ext = extensions.get( 'OVR_multiview2' );
+
+					var colorTexture = _gl.createTexture();
+					_gl.bindTexture( _gl.TEXTURE_2D_ARRAY, colorTexture );
+					_gl.texParameteri( _gl.TEXTURE_2D_ARRAY, _gl.TEXTURE_MAG_FILTER, _gl.NEAREST );
+					_gl.texParameteri( _gl.TEXTURE_2D_ARRAY, _gl.TEXTURE_MIN_FILTER, _gl.NEAREST );
+					_gl.texImage3D( _gl.TEXTURE_2D_ARRAY, 0, _gl.RGBA8, width, height, numViews, 0, _gl.RGBA, _gl.UNSIGNED_BYTE, null );
+					ext.framebufferTextureMultiviewOVR( _gl.FRAMEBUFFER, _gl.COLOR_ATTACHMENT0, colorTexture, 0, 0, numViews );
+
+					var depthStencilTexture = _gl.createTexture();
+					_gl.bindTexture( _gl.TEXTURE_2D_ARRAY, depthStencilTexture );
+					_gl.texParameteri( _gl.TEXTURE_2D_ARRAY, _gl.TEXTURE_MAG_FILTER, _gl.NEAREST );
+					_gl.texParameteri( _gl.TEXTURE_2D_ARRAY, _gl.TEXTURE_MIN_FILTER, _gl.NEAREST );
+					_gl.texImage3D( _gl.TEXTURE_2D_ARRAY, 0, _gl.DEPTH24_STENCIL8, width, height, numViews, 0, _gl.DEPTH_STENCIL, _gl.UNSIGNED_INT_24_8, null );
+					ext.framebufferTextureMultiviewOVR( _gl.FRAMEBUFFER, _gl.DEPTH_STENCIL_ATTACHMENT, depthStencilTexture, 0, 0, numViews );
+
+					var viewFramebuffers = new Array( numViews );
+					for ( var viewIndex = 0; viewIndex < numViews; ++ viewIndex ) {
+
+						viewFramebuffers[ viewIndex ] = _gl.createFramebuffer();
+						_gl.bindFramebuffer( _gl.FRAMEBUFFER, viewFramebuffers[ viewIndex ] );
+						_gl.framebufferTextureLayer( _gl.FRAMEBUFFER, _gl.COLOR_ATTACHMENT0, colorTexture, 0, viewIndex );
+
+					}
+
+					renderTargetProperties.__webglColorTexture = colorTexture;
+					renderTargetProperties.__webglDepthStencilTexture = depthStencilTexture;
+					renderTargetProperties.__webglViewFramebuffers = viewFramebuffers;
+
+					_gl.bindFramebuffer( _gl.FRAMEBUFFER, null );
+					_gl.bindTexture( _gl.TEXTURE_2D_ARRAY, null );
+
+				}
+
+			} else {
+
+				console.warn( 'THREE.WebGLRenderer: WebGLMultiviewRenderTarget can only be used with WebGL2 and Multiview extension support.' );
+
 			}
 
 		}
@@ -1021,7 +1070,7 @@ function WebGLTextures( _gl, extensions, state, properties, capabilities, utils,
 
 			state.bindTexture( _gl.TEXTURE_CUBE_MAP, null );
 
-		} else {
+		} else if ( ! isMultiview ) {
 
 			state.bindTexture( _gl.TEXTURE_2D, textureProperties.__webglTexture );
 			setTextureParameters( _gl.TEXTURE_2D, renderTarget.texture, supportsMips );