Skip to content

Commit 1123347

Browse files
felixtrzdmarcos
authored andcommitted
WebXR: Implement antialiased multiview using OCULUS_multiview (#15)
Fix incorrect handling of depth buffer when stencil buffer was enabled WebXR: check for null render target (#15) (#17)
1 parent 52a6a2c commit 1123347

File tree

9 files changed

+481
-52
lines changed

9 files changed

+481
-52
lines changed

examples/webxr_xr_ballshooter.html

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,7 @@
6767

6868
//
6969

70-
renderer = new THREE.WebGLRenderer( { antialias: true } );
70+
renderer = new THREE.WebGLRenderer( { antialias: true, multiviewStereo: true } );
7171
renderer.setPixelRatio( window.devicePixelRatio );
7272
renderer.setSize( window.innerWidth, window.innerHeight );
7373
renderer.setAnimationLoop( animate );
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
/**
2+
* @author fernandojsg / http://fernandojsg.com
3+
* @author Takahiro https://github.com/takahirox
4+
*/
5+
6+
import { WebGLRenderTarget } from './WebGLRenderTarget.js';
7+
8+
class WebGLMultiviewRenderTarget extends WebGLRenderTarget {
9+
10+
constructor( width, height, numViews, options = {} ) {
11+
12+
super( width, height, options );
13+
14+
this.depthBuffer = false;
15+
this.stencilBuffer = false;
16+
17+
this.numViews = numViews;
18+
19+
}
20+
21+
copy( source ) {
22+
23+
super.copy( source );
24+
25+
this.numViews = source.numViews;
26+
27+
return this;
28+
29+
}
30+
31+
}
32+
33+
WebGLMultiviewRenderTarget.prototype.isWebGLMultiviewRenderTarget = true;
34+
35+
export { WebGLMultiviewRenderTarget };

src/renderers/WebGLRenderer.js

Lines changed: 55 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ import { WebGLGeometries } from './webgl/WebGLGeometries.js';
3838
import { WebGLIndexedBufferRenderer } from './webgl/WebGLIndexedBufferRenderer.js';
3939
import { WebGLInfo } from './webgl/WebGLInfo.js';
4040
import { WebGLMorphtargets } from './webgl/WebGLMorphtargets.js';
41+
import { WebGLMultiview } from './webgl/WebGLMultiview.js';
4142
import { WebGLObjects } from './webgl/WebGLObjects.js';
4243
import { WebGLPrograms } from './webgl/WebGLPrograms.js';
4344
import { WebGLProperties } from './webgl/WebGLProperties.js';
@@ -71,6 +72,7 @@ class WebGLRenderer {
7172
powerPreference = 'default',
7273
failIfMajorPerformanceCaveat = false,
7374
reverseDepthBuffer = false,
75+
multiviewStereo = false,
7476
} = parameters;
7577

7678
this.isWebGLRenderer = true;
@@ -278,6 +280,7 @@ class WebGLRenderer {
278280
let extensions, capabilities, state, info;
279281
let properties, textures, cubemaps, cubeuvmaps, attributes, geometries, objects;
280282
let programCache, materials, renderLists, renderStates, clipping, shadowMap;
283+
let multiview;
281284

282285
let background, morphtargets, bufferRenderer, indexedBufferRenderer;
283286

@@ -316,6 +319,7 @@ class WebGLRenderer {
316319
renderLists = new WebGLRenderLists();
317320
renderStates = new WebGLRenderStates( extensions );
318321
background = new WebGLBackground( _this, cubemaps, cubeuvmaps, state, objects, _alpha, premultipliedAlpha );
322+
multiview = new WebGLMultiview( _this, extensions, _gl );
319323
shadowMap = new WebGLShadowMap( _this, objects, capabilities );
320324
uniformsGroups = new WebGLUniformsGroups( _gl, info, capabilities, state );
321325

@@ -1252,11 +1256,21 @@ class WebGLRenderer {
12521256

12531257
if ( _renderBackground ) background.render( scene );
12541258

1255-
for ( let i = 0, l = cameras.length; i < l; i ++ ) {
1259+
if ( xr.enabled && xr.isMultiview ) {
12561260

1257-
const camera2 = cameras[ i ];
1261+
textures.setDeferTextureUploads( true );
12581262

1259-
renderScene( currentRenderList, scene, camera2, camera2.viewport );
1263+
renderScene( currentRenderList, scene, camera, camera.cameras[ 0 ].viewport );
1264+
1265+
} else {
1266+
1267+
for ( let i = 0, l = cameras.length; i < l; i ++ ) {
1268+
1269+
const camera2 = cameras[ i ];
1270+
1271+
renderScene( currentRenderList, scene, camera2, camera2.viewport );
1272+
1273+
}
12601274

12611275
}
12621276

@@ -1782,6 +1796,7 @@ class WebGLRenderer {
17821796
materialProperties.vertexAlphas = parameters.vertexAlphas;
17831797
materialProperties.vertexTangents = parameters.vertexTangents;
17841798
materialProperties.toneMapping = parameters.toneMapping;
1799+
materialProperties.numMultiviewViews = parameters.numMultiviewViews;
17851800

17861801
}
17871802

@@ -1813,6 +1828,8 @@ class WebGLRenderer {
18131828

18141829
}
18151830

1831+
const numMultiviewViews = _currentRenderTarget && _currentRenderTarget.isWebGLMultiviewRenderTarget ? _currentRenderTarget.numViews : 0;
1832+
18161833
const morphAttribute = geometry.morphAttributes.position || geometry.morphAttributes.normal || geometry.morphAttributes.color;
18171834
const morphTargetsCount = ( morphAttribute !== undefined ) ? morphAttribute.length : 0;
18181835

@@ -1940,6 +1957,10 @@ class WebGLRenderer {
19401957

19411958
needsProgramChange = true;
19421959

1960+
} else if ( materialProperties.numMultiviewViews !== numMultiviewViews ) {
1961+
1962+
needsProgramChange = true;
1963+
19431964
}
19441965

19451966
} else {
@@ -1986,24 +2007,33 @@ class WebGLRenderer {
19862007

19872008
// common camera uniforms
19882009

1989-
const reverseDepthBuffer = state.buffers.depth.getReversed();
2010+
if ( program.numMultiviewViews > 0 ) {
19902011

1991-
if ( reverseDepthBuffer ) {
2012+
multiview.updateCameraProjectionMatricesUniform( camera, p_uniforms );
2013+
multiview.updateCameraViewMatricesUniform( camera, p_uniforms );
19922014

1993-
_currentProjectionMatrix.copy( camera.projectionMatrix );
2015+
} else {
19942016

1995-
toNormalizedProjectionMatrix( _currentProjectionMatrix );
1996-
toReversedProjectionMatrix( _currentProjectionMatrix );
2017+
const reverseDepthBuffer = state.buffers.depth.getReversed();
19972018

1998-
p_uniforms.setValue( _gl, 'projectionMatrix', _currentProjectionMatrix );
2019+
if ( reverseDepthBuffer ) {
19992020

2000-
} else {
2021+
_currentProjectionMatrix.copy( camera.projectionMatrix );
20012022

2002-
p_uniforms.setValue( _gl, 'projectionMatrix', camera.projectionMatrix );
2023+
toNormalizedProjectionMatrix( _currentProjectionMatrix );
2024+
toReversedProjectionMatrix( _currentProjectionMatrix );
20032025

2004-
}
2026+
p_uniforms.setValue( _gl, 'projectionMatrix', _currentProjectionMatrix );
2027+
2028+
} else {
2029+
2030+
p_uniforms.setValue( _gl, 'projectionMatrix', camera.projectionMatrix );
20052031

2006-
p_uniforms.setValue( _gl, 'viewMatrix', camera.matrixWorldInverse );
2032+
}
2033+
2034+
p_uniforms.setValue( _gl, 'viewMatrix', camera.matrixWorldInverse );
2035+
2036+
}
20072037

20082038
const uCamPos = p_uniforms.map.cameraPosition;
20092039

@@ -2165,8 +2195,17 @@ class WebGLRenderer {
21652195

21662196
// common matrices
21672197

2168-
p_uniforms.setValue( _gl, 'modelViewMatrix', object.modelViewMatrix );
2169-
p_uniforms.setValue( _gl, 'normalMatrix', object.normalMatrix );
2198+
if ( program.numMultiviewViews > 0 ) {
2199+
2200+
multiview.updateObjectMatricesUniforms( object, camera, p_uniforms );
2201+
2202+
} else {
2203+
2204+
p_uniforms.setValue( _gl, 'modelViewMatrix', object.modelViewMatrix );
2205+
p_uniforms.setValue( _gl, 'normalMatrix', object.normalMatrix );
2206+
2207+
}
2208+
21702209
p_uniforms.setValue( _gl, 'modelMatrix', object.matrixWorld );
21712210

21722211
// UBOs
@@ -2270,7 +2309,7 @@ class WebGLRenderer {
22702309

22712310
renderTargetProperties.__autoAllocateDepthBuffer = depthTexture === undefined;
22722311

2273-
if ( ! renderTargetProperties.__autoAllocateDepthBuffer ) {
2312+
if ( ! renderTargetProperties.__autoAllocateDepthBuffer && ( ! _currentRenderTarget || ! _currentRenderTarget.isWebGLMultiviewRenderTarget ) ) {
22742313

22752314
// The multisample_render_to_texture extension doesn't work properly if there
22762315
// are midframe flushes and an external depth buffer. Disable use of the extension.

src/renderers/webgl/WebGLBackground.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -92,7 +92,7 @@ function WebGLBackground( renderer, cubemaps, cubeuvmaps, state, objects, alpha,
9292
if ( boxMesh === undefined ) {
9393

9494
boxMesh = new Mesh(
95-
new BoxGeometry( 1, 1, 1 ),
95+
new BoxGeometry( 10000, 10000, 10000 ),
9696
new ShaderMaterial( {
9797
name: 'BackgroundCubeMaterial',
9898
uniforms: cloneUniforms( ShaderLib.backgroundCube.uniforms ),
Lines changed: 100 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,100 @@
1+
/**
2+
* @author fernandojsg / http://fernandojsg.com
3+
* @author Takahiro https://github.com/takahirox
4+
*/
5+
import { Matrix3 } from '../../math/Matrix3.js';
6+
import { Matrix4 } from '../../math/Matrix4.js';
7+
8+
class WebGLMultiview {
9+
10+
constructor( renderer, extensions, gl ) {
11+
12+
this.renderer = renderer;
13+
14+
this.DEFAULT_NUMVIEWS = 2;
15+
this.maxNumViews = 0;
16+
this.gl = gl;
17+
18+
this.extensions = extensions;
19+
20+
this.available = this.extensions.has( 'OCULUS_multiview' );
21+
22+
if ( this.available ) {
23+
24+
const extension = this.extensions.get( 'OCULUS_multiview' );
25+
26+
this.maxNumViews = this.gl.getParameter( extension.MAX_VIEWS_OVR );
27+
28+
this.mat4 = [];
29+
this.mat3 = [];
30+
this.cameraArray = [];
31+
32+
for ( var i = 0; i < this.maxNumViews; i ++ ) {
33+
34+
this.mat4[ i ] = new Matrix4();
35+
this.mat3[ i ] = new Matrix3();
36+
37+
}
38+
39+
}
40+
41+
}
42+
43+
//
44+
getCameraArray( camera ) {
45+
46+
if ( camera.isArrayCamera ) return camera.cameras;
47+
48+
this.cameraArray[ 0 ] = camera;
49+
50+
return this.cameraArray;
51+
52+
}
53+
54+
updateCameraProjectionMatricesUniform( camera, uniforms ) {
55+
56+
var cameras = this.getCameraArray( camera );
57+
58+
for ( var i = 0; i < cameras.length; i ++ ) {
59+
60+
this.mat4[ i ].copy( cameras[ i ].projectionMatrix );
61+
62+
}
63+
64+
uniforms.setValue( this.gl, 'projectionMatrices', this.mat4 );
65+
66+
}
67+
68+
updateCameraViewMatricesUniform( camera, uniforms ) {
69+
70+
var cameras = this.getCameraArray( camera );
71+
72+
for ( var i = 0; i < cameras.length; i ++ ) {
73+
74+
this.mat4[ i ].copy( cameras[ i ].matrixWorldInverse );
75+
76+
}
77+
78+
uniforms.setValue( this.gl, 'viewMatrices', this.mat4 );
79+
80+
}
81+
82+
updateObjectMatricesUniforms( object, camera, uniforms ) {
83+
84+
var cameras = this.getCameraArray( camera );
85+
86+
for ( var i = 0; i < cameras.length; i ++ ) {
87+
88+
this.mat4[ i ].multiplyMatrices( cameras[ i ].matrixWorldInverse, object.matrixWorld );
89+
this.mat3[ i ].getNormalMatrix( this.mat4[ i ] );
90+
91+
}
92+
93+
uniforms.setValue( this.gl, 'modelViewMatrices', this.mat4 );
94+
uniforms.setValue( this.gl, 'normalMatrices', this.mat3 );
95+
96+
}
97+
98+
}
99+
100+
export { WebGLMultiview };

src/renderers/webgl/WebGLProgram.js

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -497,6 +497,8 @@ function WebGLProgram( renderer, cacheKey, parameters, bindingStates ) {
497497
let prefixVertex, prefixFragment;
498498
let versionString = parameters.glslVersion ? '#version ' + parameters.glslVersion + '\n' : '';
499499

500+
const numMultiviewViews = parameters.numMultiviewViews;
501+
500502
if ( parameters.isRawShaderMaterial ) {
501503

502504
prefixVertex = [
@@ -884,6 +886,53 @@ function WebGLProgram( renderer, cacheKey, parameters, bindingStates ) {
884886
'#define textureCubeGradEXT textureGrad'
885887
].join( '\n' ) + '\n' + prefixFragment;
886888

889+
// Multiview
890+
891+
if ( numMultiviewViews > 0 ) {
892+
893+
// TODO: fix light transforms here?
894+
895+
prefixVertex = [
896+
'#extension GL_OVR_multiview : require',
897+
'layout(num_views = ' + numMultiviewViews + ') in;',
898+
'#define VIEW_ID gl_ViewID_OVR'
899+
].join( '\n' ) + '\n' + prefixVertex;
900+
901+
prefixVertex = prefixVertex.replace(
902+
[
903+
'uniform mat4 modelViewMatrix;',
904+
'uniform mat4 projectionMatrix;',
905+
'uniform mat4 viewMatrix;',
906+
'uniform mat3 normalMatrix;'
907+
].join( '\n' ),
908+
[
909+
'uniform mat4 modelViewMatrices[' + numMultiviewViews + '];',
910+
'uniform mat4 projectionMatrices[' + numMultiviewViews + '];',
911+
'uniform mat4 viewMatrices[' + numMultiviewViews + '];',
912+
'uniform mat3 normalMatrices[' + numMultiviewViews + '];',
913+
914+
'#define modelViewMatrix modelViewMatrices[VIEW_ID]',
915+
'#define projectionMatrix projectionMatrices[VIEW_ID]',
916+
'#define viewMatrix viewMatrices[VIEW_ID]',
917+
'#define normalMatrix normalMatrices[VIEW_ID]'
918+
].join( '\n' )
919+
);
920+
921+
prefixFragment = [
922+
'#extension GL_OVR_multiview : require',
923+
'#define VIEW_ID gl_ViewID_OVR'
924+
].join( '\n' ) + '\n' + prefixFragment;
925+
926+
prefixFragment = prefixFragment.replace(
927+
'uniform mat4 viewMatrix;',
928+
[
929+
'uniform mat4 viewMatrices[' + numMultiviewViews + '];',
930+
'#define viewMatrix viewMatrices[VIEW_ID]'
931+
].join( '\n' )
932+
);
933+
934+
}
935+
887936
}
888937

889938
const vertexGlsl = versionString + prefixVertex + vertexShader;
@@ -1076,6 +1125,7 @@ function WebGLProgram( renderer, cacheKey, parameters, bindingStates ) {
10761125
this.program = program;
10771126
this.vertexShader = glVertexShader;
10781127
this.fragmentShader = glFragmentShader;
1128+
this.numMultiviewViews = numMultiviewViews;
10791129

10801130
return this;
10811131

0 commit comments

Comments
 (0)