WebGLMultiview.js 6.7 KB
Newer Older
1 2 3 4
/**
 * @author fernandojsg / http://fernandojsg.com
 */

5
import { WebGLRenderTarget } from '../WebGLRenderTarget.js';
6 7
import { Matrix3 } from '../../math/Matrix3.js';
import { Matrix4 } from '../../math/Matrix4.js';
8 9

function WebGLMultiview( requested, gl, canvas, extensions, capabilities, properties ) {
10

F
Fernando Serrano 已提交
11
	this.isAvailable = function () {
12

F
Fernando Serrano 已提交
13
		return capabilities.multiview;
14

F
Fernando Serrano 已提交
15
	};
16

17 18 19 20 21 22
	this.getNumViews = function () {

		return numViews;

	};

F
Fernando Serrano 已提交
23
	this.getMaxViews = function () {
24

F
Fernando Serrano 已提交
25
		return capabilities.maxMultiviewViews;
26

F
Fernando Serrano 已提交
27
	};
28

F
Fernando Serrano 已提交
29
	this.isEnabled = function () {
30

F
Fernando Serrano 已提交
31
		return requested && this.isAvailable();
32

F
Fernando Serrano 已提交
33
	};
34

35 36 37 38 39 40 41 42
	if ( requested && ! this.isAvailable() ) {

		console.warn( 'WebGLRenderer: Multiview requested but not supported by the browser' );

	} else if ( requested !== false && this.isAvailable() ) {

		console.info( 'WebGLRenderer: Multiview enabled' );

F
Fernando Serrano 已提交
43
	}
44

45
	var numViews = 2;
F
Fernando Serrano 已提交
46
	var framebuffer; // multiview framebuffer.
47 48 49 50
	var viewFramebuffer; // single views inside the multiview framebuffer.
	var framebufferWidth = 0;
	var framebufferHeight = 0;

51 52 53 54 55
	var texture = {
		color: null,
		depthStencil: null
	};

56 57 58 59 60 61 62 63 64 65 66 67 68 69
	this.computeCameraMatrices = function ( camera ) {

		if ( ! camera.projectionMatrices ) {

			camera.projectionMatrices = new Array( numViews );
			camera.viewMatrices = new Array( numViews );

			for ( var i = 0; i < numViews; i ++ ) {

				camera.projectionMatrices[ i ] = new Matrix4();
				camera.viewMatrices[ i ] = new Matrix4();

			}

70
		}
71

72
		if ( camera.isArrayCamera ) {
73

74
			for ( var i = 0; i < numViews; i ++ ) {
75

76 77
				camera.projectionMatrices[ i ].copy( camera.cameras[ i ].projectionMatrix );
				camera.viewMatrices[ i ].copy( camera.cameras[ i ].matrixWorldInverse );
78

79
			}
80

81
		} else {
82

83
			for ( var i = 0; i < numViews; i ++ ) {
84

85 86
				camera.projectionMatrices[ i ].copy( camera.projectionMatrix );
				camera.viewMatrices[ i ].copy( camera.matrixWorldInverse );
87 88 89 90 91 92 93

			}

		}

	};

94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124
	this.computeObjectMatrices = function ( object, camera ) {

		if ( ! object.modelViewMatrices ) {

			object.modelViewMatrices = new Array( numViews );
			object.normalMatrices = new Array( numViews );

			for ( var i = 0; i < numViews; i ++ ) {

				object.modelViewMatrices[ i ] = new Matrix4();
				object.normalMatrices[ i ] = new Matrix3();

			}

		}

		if ( camera.isArrayCamera ) {

			for ( var i = 0; i < numViews; i ++ ) {

				object.modelViewMatrices[ i ].multiplyMatrices( camera.cameras[ i ].matrixWorldInverse, object.matrixWorld );
				object.normalMatrices[ i ].getNormalMatrix( object.modelViewMatrices[ i ] );

			}

		} else {

			// In this case we still need to provide an array of matrices but just the first one will be used
			object.modelViewMatrices[ 0 ].multiplyMatrices( camera.matrixWorldInverse, object.matrixWorld );
			object.normalMatrices[ 0 ].getNormalMatrix( object.modelViewMatrices[ 0 ] );

125
			for ( var i = 1; i < numViews; i ++ ) {
126 127 128 129 130 131 132 133 134

				object.modelViewMatrices[ i ].copy( object.modelViewMatrices[ 0 ] );
				object.normalMatrices[ i ].copy( object.normalMatrices[ 0 ] );

			}

		}

	};
135

136
	// @todo Get ArrayCamera
137 138
	this.createMultiviewRenderTargetTexture = function () {

F
Fernando Serrano 已提交
139
		var halfWidth = Math.floor( canvas.width * 0.5 );
140 141 142 143

		framebuffer = gl.createFramebuffer();
		gl.bindFramebuffer( gl.FRAMEBUFFER, framebuffer );

F
Fernando Serrano 已提交
144
		var ext = extensions.get( 'OVR_multiview2' );
145

146 147 148 149
		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 );
150 151
		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 );
152 153 154 155 156

		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 );
157 158
		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 );
159

160 161
		viewFramebuffer = new Array( numViews );
		for ( var viewIndex = 0; viewIndex < numViews; ++ viewIndex ) {
162

163 164
			viewFramebuffer[ viewIndex ] = gl.createFramebuffer();
			gl.bindFramebuffer( gl.FRAMEBUFFER, viewFramebuffer[ viewIndex ] );
165 166
			gl.framebufferTextureLayer( gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, texture.color, 0, viewIndex );

F
Fernando Serrano 已提交
167 168
		}

169 170
		framebufferWidth = halfWidth;
		framebufferHeight = canvas.height;
F
Fernando Serrano 已提交
171

172 173 174 175 176
		this.renderTarget = new WebGLRenderTarget( framebufferWidth, framebufferHeight );

		// @hack This should be done in WebGLTextures?
		properties.get( this.renderTarget ).__webglFramebuffer = framebuffer;

F
Fernando Serrano 已提交
177
	};
178

179
	this.bindFramebuffer = function ( camera ) {
180

F
Fernando Serrano 已提交
181 182 183 184
		var width = canvas.width;
		var height = canvas.height;

		if ( camera.isArrayCamera ) {
185

F
Fernando Serrano 已提交
186 187
			// Every camera must have the same size, so we just get the size from the first one
			var bounds = camera.cameras[ 0 ].bounds;
188

F
Fernando Serrano 已提交
189 190 191 192 193 194 195 196
			width *= bounds.z;
			height *= bounds.w;

		}

		if ( framebufferWidth < width || framebufferHeight < height ) {

			console.log( 'WebGLMultiview: Updating multiview FBO with dimensions: ', width, height );
197
			gl.bindTexture( gl.TEXTURE_2D_ARRAY, texture.color );
F
Fernando Serrano 已提交
198
			gl.texImage3D( gl.TEXTURE_2D_ARRAY, 0, gl.RGBA8, width, height, numViews, 0, gl.RGBA, gl.UNSIGNED_BYTE, null );
199
			gl.bindTexture( gl.TEXTURE_2D_ARRAY, texture.depthStencil );
F
Fernando Serrano 已提交
200 201 202
			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;
203

204 205
			this.renderTarget.setSize( width, height );

F
Fernando Serrano 已提交
206
		}
207

208 209 210 211
		gl.bindFramebuffer( gl.DRAW_FRAMEBUFFER, framebuffer );

	};

212
	this.unbindFramebuffer = function ( camera ) {
213

F
Fernando Serrano 已提交
214
		gl.bindFramebuffer( gl.DRAW_FRAMEBUFFER, null );
215

F
Fernando Serrano 已提交
216
		if ( camera.isArrayCamera ) {
217

F
Fernando Serrano 已提交
218
			for ( var i = 0; i < camera.cameras.length; i ++ ) {
219

F
Fernando Serrano 已提交
220
				var bounds = camera.cameras[ i ].bounds;
221

F
Fernando Serrano 已提交
222 223 224 225
				var x = bounds.x * canvas.width;
				var y = bounds.y * canvas.height;
				var width = bounds.z * canvas.width;
				var height = bounds.w * canvas.height;
226

F
Fernando Serrano 已提交
227 228
				gl.bindFramebuffer( gl.READ_FRAMEBUFFER, viewFramebuffer[ i ] );
				gl.blitFramebuffer( 0, 0, width, height, x, y, x + width, y + height, gl.COLOR_BUFFER_BIT, gl.NEAREST );
229

F
Fernando Serrano 已提交
230
			}
231

F
Fernando Serrano 已提交
232
		} else {
233

F
Fernando Serrano 已提交
234 235
			gl.bindFramebuffer( gl.READ_FRAMEBUFFER, viewFramebuffer[ 0 ] );
			gl.blitFramebuffer( 0, 0, canvas.width, canvas.height, 0, 0, canvas.width, canvas.height, gl.COLOR_BUFFER_BIT, gl.NEAREST );
236

F
Fernando Serrano 已提交
237
		}
238 239 240

	};

241

F
Fernando Serrano 已提交
242
	if ( this.isEnabled() ) {
243

F
Fernando Serrano 已提交
244
		this.createMultiviewRenderTargetTexture();
245

F
Fernando Serrano 已提交
246
	}
247 248 249 250

}

export { WebGLMultiview };