Skip to content

Commit 9bee41b

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) Fix multiview for WebXRManager, some changes were lost in a previous rebase (#25)
1 parent 1dbe703 commit 9bee41b

9 files changed

Lines changed: 481 additions & 51 deletions

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 & 14 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';
@@ -82,6 +83,7 @@ class WebGLRenderer {
8283
powerPreference = 'default',
8384
failIfMajorPerformanceCaveat = false,
8485
reversedDepthBuffer = false,
86+
multiviewStereo = false,
8587
} = parameters;
8688

8789
/**
@@ -408,6 +410,7 @@ class WebGLRenderer {
408410
let extensions, capabilities, state, info;
409411
let properties, textures, cubemaps, cubeuvmaps, attributes, geometries, objects;
410412
let programCache, materials, renderLists, renderStates, clipping, shadowMap;
413+
let multiview;
411414

412415
let background, morphtargets, bufferRenderer, indexedBufferRenderer;
413416

@@ -446,6 +449,7 @@ class WebGLRenderer {
446449
renderLists = new WebGLRenderLists();
447450
renderStates = new WebGLRenderStates( extensions );
448451
background = new WebGLBackground( _this, cubemaps, cubeuvmaps, state, objects, _alpha, premultipliedAlpha );
452+
multiview = new WebGLMultiview( _this, extensions, _gl );
449453
shadowMap = new WebGLShadowMap( _this, objects, capabilities );
450454
uniformsGroups = new WebGLUniformsGroups( _gl, info, capabilities, state );
451455

@@ -535,7 +539,7 @@ class WebGLRenderer {
535539

536540
// xr
537541

538-
const xr = new WebXRManager( _this, _gl );
542+
const xr = new WebXRManager( _this, _gl, extensions, multiviewStereo );
539543

540544
/**
541545
* A reference to the XR manager.
@@ -1652,11 +1656,21 @@ class WebGLRenderer {
16521656

16531657
if ( _renderBackground ) background.render( scene );
16541658

1655-
for ( let i = 0, l = cameras.length; i < l; i ++ ) {
1659+
if ( xr.enabled && xr.isMultiview ) {
16561660

1657-
const camera2 = cameras[ i ];
1661+
textures.setDeferTextureUploads( true );
16581662

1659-
renderScene( currentRenderList, scene, camera2, camera2.viewport );
1663+
renderScene( currentRenderList, scene, camera, camera.cameras[ 0 ].viewport );
1664+
1665+
} else {
1666+
1667+
for ( let i = 0, l = cameras.length; i < l; i ++ ) {
1668+
1669+
const camera2 = cameras[ i ];
1670+
1671+
renderScene( currentRenderList, scene, camera2, camera2.viewport );
1672+
1673+
}
16601674

16611675
}
16621676

@@ -1688,6 +1702,8 @@ class WebGLRenderer {
16881702

16891703
if ( scene.isScene === true ) scene.onAfterRender( _this, scene, camera );
16901704

1705+
textures.runDeferredUploads();
1706+
16911707
// _gl.finish();
16921708

16931709
bindingStates.resetDefaultState();
@@ -2184,6 +2200,7 @@ class WebGLRenderer {
21842200
materialProperties.vertexAlphas = parameters.vertexAlphas;
21852201
materialProperties.vertexTangents = parameters.vertexTangents;
21862202
materialProperties.toneMapping = parameters.toneMapping;
2203+
materialProperties.numMultiviewViews = parameters.numMultiviewViews;
21872204

21882205
}
21892206

@@ -2215,6 +2232,8 @@ class WebGLRenderer {
22152232

22162233
}
22172234

2235+
const numMultiviewViews = _currentRenderTarget && _currentRenderTarget.isWebGLMultiviewRenderTarget ? _currentRenderTarget.numViews : 0;
2236+
22182237
const morphAttribute = geometry.morphAttributes.position || geometry.morphAttributes.normal || geometry.morphAttributes.color;
22192238
const morphTargetsCount = ( morphAttribute !== undefined ) ? morphAttribute.length : 0;
22202239

@@ -2342,6 +2361,10 @@ class WebGLRenderer {
23422361

23432362
needsProgramChange = true;
23442363

2364+
} else if ( materialProperties.numMultiviewViews !== numMultiviewViews ) {
2365+
2366+
needsProgramChange = true;
2367+
23452368
}
23462369

23472370
} else {
@@ -2388,18 +2411,27 @@ class WebGLRenderer {
23882411

23892412
// common camera uniforms
23902413

2391-
const reversedDepthBuffer = state.buffers.depth.getReversed();
2414+
if ( program.numMultiviewViews > 0 ) {
23922415

2393-
if ( reversedDepthBuffer && camera.reversedDepth !== true ) {
2416+
multiview.updateCameraProjectionMatricesUniform( camera, p_uniforms );
2417+
multiview.updateCameraViewMatricesUniform( camera, p_uniforms );
23942418

2395-
camera._reversedDepth = true;
2396-
camera.updateProjectionMatrix();
2419+
} else {
23972420

2398-
}
2421+
const reversedDepthBuffer = state.buffers.depth.getReversed();
2422+
2423+
if ( reversedDepthBuffer && camera.reversedDepth !== true ) {
23992424

2400-
p_uniforms.setValue( _gl, 'projectionMatrix', camera.projectionMatrix );
2425+
camera._reversedDepth = true;
2426+
camera.updateProjectionMatrix();
2427+
2428+
}
24012429

2402-
p_uniforms.setValue( _gl, 'viewMatrix', camera.matrixWorldInverse );
2430+
p_uniforms.setValue( _gl, 'projectionMatrix', camera.projectionMatrix );
2431+
2432+
p_uniforms.setValue( _gl, 'viewMatrix', camera.matrixWorldInverse );
2433+
2434+
}
24032435

24042436
const uCamPos = p_uniforms.map.cameraPosition;
24052437

@@ -2568,8 +2600,17 @@ class WebGLRenderer {
25682600

25692601
// common matrices
25702602

2571-
p_uniforms.setValue( _gl, 'modelViewMatrix', object.modelViewMatrix );
2572-
p_uniforms.setValue( _gl, 'normalMatrix', object.normalMatrix );
2603+
if ( program.numMultiviewViews > 0 ) {
2604+
2605+
multiview.updateObjectMatricesUniforms( object, camera, p_uniforms );
2606+
2607+
} else {
2608+
2609+
p_uniforms.setValue( _gl, 'modelViewMatrix', object.modelViewMatrix );
2610+
p_uniforms.setValue( _gl, 'normalMatrix', object.normalMatrix );
2611+
2612+
}
2613+
25732614
p_uniforms.setValue( _gl, 'modelMatrix', object.matrixWorld );
25742615

25752616
// UBOs
@@ -2684,7 +2725,7 @@ class WebGLRenderer {
26842725
const renderTargetProperties = properties.get( renderTarget );
26852726

26862727
renderTargetProperties.__autoAllocateDepthBuffer = renderTarget.resolveDepthBuffer === false;
2687-
if ( renderTargetProperties.__autoAllocateDepthBuffer === false ) {
2728+
if ( ! renderTargetProperties.__autoAllocateDepthBuffer ) {
26882729

26892730
// The multisample_render_to_texture extension doesn't work properly if there
26902731
// 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
@@ -500,6 +500,8 @@ function WebGLProgram( renderer, cacheKey, parameters, bindingStates ) {
500500
let prefixVertex, prefixFragment;
501501
let versionString = parameters.glslVersion ? '#version ' + parameters.glslVersion + '\n' : '';
502502

503+
const numMultiviewViews = parameters.numMultiviewViews;
504+
503505
if ( parameters.isRawShaderMaterial ) {
504506

505507
prefixVertex = [
@@ -887,6 +889,53 @@ function WebGLProgram( renderer, cacheKey, parameters, bindingStates ) {
887889
'#define textureCubeGradEXT textureGrad'
888890
].join( '\n' ) + '\n' + prefixFragment;
889891

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

892941
const vertexGlsl = versionString + prefixVertex + vertexShader;
@@ -1083,6 +1132,7 @@ function WebGLProgram( renderer, cacheKey, parameters, bindingStates ) {
10831132
this.program = program;
10841133
this.vertexShader = glVertexShader;
10851134
this.fragmentShader = glFragmentShader;
1135+
this.numMultiviewViews = numMultiviewViews;
10861136

10871137
return this;
10881138

0 commit comments

Comments
 (0)