Skip to content

Commit

Permalink
Updated implementation of multiview on clean branch (#2)
Browse files Browse the repository at this point in the history
* Updated implementation of multiview on clean branch

* Lint fix
  • Loading branch information
snagy authored May 3, 2023
1 parent 1d91a4a commit 57e16fe
Show file tree
Hide file tree
Showing 10 changed files with 489 additions and 62 deletions.
2 changes: 1 addition & 1 deletion examples/webxr_xr_ballshooter.html
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,7 @@

//

renderer = new THREE.WebGLRenderer( { antialias: true } );
renderer = new THREE.WebGLRenderer( { antialias: true, multiviewStereo: true } );
renderer.setPixelRatio( window.devicePixelRatio );
renderer.setSize( window.innerWidth, window.innerHeight );
renderer.xr.enabled = true;
Expand Down
35 changes: 35 additions & 0 deletions src/renderers/WebGLMultiviewRenderTarget.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
/**
* @author fernandojsg / http://fernandojsg.com
* @author Takahiro https://github.com/takahirox
*/

import { WebGLRenderTarget } from './WebGLRenderTarget.js';

class WebGLMultiviewRenderTarget extends WebGLRenderTarget {

constructor( width, height, numViews, options = {} ) {

super( width, height, options );

this.depthBuffer = false;
this.stencilBuffer = false;

this.numViews = numViews;

}

copy( source ) {

super.copy( source );

this.numViews = source.numViews;

return this;

}

}

WebGLMultiviewRenderTarget.prototype.isWebGLMultiviewRenderTarget = true;

export { WebGLMultiviewRenderTarget };
84 changes: 63 additions & 21 deletions src/renderers/WebGLRenderer.js
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ import { WebGLState } from './webgl/WebGLState.js';
import { WebGLTextures } from './webgl/WebGLTextures.js';
import { WebGLUniforms } from './webgl/WebGLUniforms.js';
import { WebGLUtils } from './webgl/WebGLUtils.js';
import { WebGLMultiview } from './webgl/WebGLMultiview.js';
import { WebXRManager } from './webxr/WebXRManager.js';
import { WebGLMaterials } from './webgl/WebGLMaterials.js';
import { WebGLUniformsGroups } from './webgl/WebGLUniformsGroups.js';
Expand Down Expand Up @@ -79,6 +80,7 @@ class WebGLRenderer {
preserveDrawingBuffer = false,
powerPreference = 'default',
failIfMajorPerformanceCaveat = false,
multiviewStereo = false,
} = parameters;

this.isWebGLRenderer = true;
Expand Down Expand Up @@ -303,6 +305,7 @@ class WebGLRenderer {
let extensions, capabilities, state, info;
let properties, textures, cubemaps, cubeuvmaps, attributes, geometries, objects;
let programCache, materials, renderLists, renderStates, clipping, shadowMap;
let multiview;

let background, morphtargets, bufferRenderer, indexedBufferRenderer;

Expand Down Expand Up @@ -336,6 +339,7 @@ class WebGLRenderer {
renderLists = new WebGLRenderLists();
renderStates = new WebGLRenderStates( extensions, capabilities );
background = new WebGLBackground( _this, cubemaps, cubeuvmaps, state, objects, _alpha, premultipliedAlpha );
multiview = new WebGLMultiview( _this, extensions, _gl );
shadowMap = new WebGLShadowMap( _this, objects, capabilities );
uniformsGroups = new WebGLUniformsGroups( _gl, info, capabilities, state );

Expand All @@ -358,7 +362,7 @@ class WebGLRenderer {

// xr

const xr = new WebXRManager( _this, _gl );
const xr = new WebXRManager( _this, _gl, extensions, multiviewStereo );

this.xr = xr;

Expand Down Expand Up @@ -1101,13 +1105,23 @@ class WebGLRenderer {

if ( camera.isArrayCamera ) {

const cameras = camera.cameras;
if ( xr.enabled && xr.isMultiview ) {

for ( let i = 0, l = cameras.length; i < l; i ++ ) {
textures.deferTextureUploads = true;

const camera2 = cameras[ i ];
renderScene( currentRenderList, scene, camera, camera.cameras[ 0 ].viewport );

renderScene( currentRenderList, scene, camera2, camera2.viewport );
} else {

const cameras = camera.cameras;

for ( let i = 0, l = cameras.length; i < l; i ++ ) {

const camera2 = cameras[ i ];

renderScene( currentRenderList, scene, camera2, camera2.viewport );

}

}

Expand Down Expand Up @@ -1135,6 +1149,8 @@ class WebGLRenderer {

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

textures.runDeferredUploads();

// _gl.finish();

bindingStates.resetDefaultState();
Expand Down Expand Up @@ -1590,6 +1606,7 @@ class WebGLRenderer {
materialProperties.vertexAlphas = parameters.vertexAlphas;
materialProperties.vertexTangents = parameters.vertexTangents;
materialProperties.toneMapping = parameters.toneMapping;
materialProperties.numMultiviewViews = parameters.numMultiviewViews;

}

Expand All @@ -1609,7 +1626,7 @@ class WebGLRenderer {
const morphNormals = !! geometry.morphAttributes.normal;
const morphColors = !! geometry.morphAttributes.color;
const toneMapping = material.toneMapped ? _this.toneMapping : NoToneMapping;

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

Expand Down Expand Up @@ -1705,6 +1722,10 @@ class WebGLRenderer {

needsProgramChange = true;

} else if ( materialProperties.numMultiviewViews !== numMultiviewViews ) {

needsProgramChange = true;

}

} else {
Expand Down Expand Up @@ -1749,7 +1770,15 @@ class WebGLRenderer {

if ( refreshProgram || _currentCamera !== camera ) {

p_uniforms.setValue( _gl, 'projectionMatrix', camera.projectionMatrix );
if ( program.numMultiviewViews > 0 ) {

multiview.updateCameraProjectionMatricesUniform( camera, p_uniforms );

} else {

p_uniforms.setValue( _gl, 'projectionMatrix', camera.projectionMatrix );

}

if ( capabilities.logarithmicDepthBuffer ) {

Expand Down Expand Up @@ -1811,7 +1840,15 @@ class WebGLRenderer {
material.isShadowMaterial ||
object.isSkinnedMesh ) {

p_uniforms.setValue( _gl, 'viewMatrix', camera.matrixWorldInverse );
if ( program.numMultiviewViews > 0 ) {

multiview.updateCameraViewMatricesUniform( camera, p_uniforms );

} else {

p_uniforms.setValue( _gl, 'viewMatrix', camera.matrixWorldInverse );

}

}

Expand Down Expand Up @@ -1920,8 +1957,17 @@ class WebGLRenderer {

// common matrices

p_uniforms.setValue( _gl, 'modelViewMatrix', object.modelViewMatrix );
p_uniforms.setValue( _gl, 'normalMatrix', object.normalMatrix );
if ( program.numMultiviewViews > 0 ) {

multiview.updateObjectMatricesUniforms( object, camera, p_uniforms );

} else {

p_uniforms.setValue( _gl, 'modelViewMatrix', object.modelViewMatrix );
p_uniforms.setValue( _gl, 'normalMatrix', object.normalMatrix );

}

p_uniforms.setValue( _gl, 'modelMatrix', object.matrixWorld );

// UBOs
Expand Down Expand Up @@ -2005,20 +2051,16 @@ class WebGLRenderer {
const renderTargetProperties = properties.get( renderTarget );
renderTargetProperties.__hasExternalTextures = true;

if ( renderTargetProperties.__hasExternalTextures ) {

renderTargetProperties.__autoAllocateDepthBuffer = depthTexture === undefined;
renderTargetProperties.__autoAllocateDepthBuffer = depthTexture === undefined;

if ( ! renderTargetProperties.__autoAllocateDepthBuffer ) {
if ( ! renderTargetProperties.__autoAllocateDepthBuffer && ! _currentRenderTarget.isWebGLMultiviewRenderTarget ) {

// The multisample_render_to_texture extension doesn't work properly if there
// are midframe flushes and an external depth buffer. Disable use of the extension.
if ( extensions.has( 'WEBGL_multisampled_render_to_texture' ) === true ) {
// The multisample_render_to_texture extension doesn't work properly if there
// are midframe flushes and an external depth buffer. Disable use of the extension.
if ( extensions.has( 'WEBGL_multisampled_render_to_texture' ) === true ) {

console.warn( 'THREE.WebGLRenderer: Render-to-texture extension was disabled because an external texture was provided' );
renderTargetProperties.__useRenderToTexture = false;

}
console.warn( 'THREE.WebGLRenderer: Render-to-texture extension was disabled because an external texture was provided' );
renderTargetProperties.__useRenderToTexture = false;

}

Expand Down
2 changes: 1 addition & 1 deletion src/renderers/webgl/WebGLBackground.js
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ function WebGLBackground( renderer, cubemaps, cubeuvmaps, state, objects, alpha,
if ( boxMesh === undefined ) {

boxMesh = new Mesh(
new BoxGeometry( 1, 1, 1 ),
new BoxGeometry( 10000, 10000, 10000 ),
new ShaderMaterial( {
name: 'BackgroundCubeMaterial',
uniforms: cloneUniforms( ShaderLib.backgroundCube.uniforms ),
Expand Down
2 changes: 2 additions & 0 deletions src/renderers/webgl/WebGLLights.js
Original file line number Diff line number Diff line change
Expand Up @@ -484,6 +484,8 @@ function WebGLLights( extensions, capabilities ) {

const viewMatrix = camera.matrixWorldInverse;

// TODO here's where i need to fix the lights.

for ( let i = 0, l = lights.length; i < l; i ++ ) {

const light = lights[ i ];
Expand Down
101 changes: 101 additions & 0 deletions src/renderers/webgl/WebGLMultiview.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
/**
* @author fernandojsg / http://fernandojsg.com
* @author Takahiro https://github.com/takahirox
*/
import { Matrix3 } from '../../math/Matrix3.js';
import { Matrix4 } from '../../math/Matrix4.js';


class WebGLMultiview {

constructor( renderer, extensions, gl ) {

this.renderer = renderer;

this.DEFAULT_NUMVIEWS = 2;
this.maxNumViews = 0;
this.gl = gl;

this.extensions = extensions;

this.available = this.extensions.has( 'OCULUS_multiview' );

if ( this.available ) {

const extension = this.extensions.get( 'OCULUS_multiview' );

this.maxNumViews = this.gl.getParameter( extension.MAX_VIEWS_OVR );

this.mat4 = [];
this.mat3 = [];
this.cameraArray = [];

for ( var i = 0; i < this.maxNumViews; i ++ ) {

this.mat4[ i ] = new Matrix4();
this.mat3[ i ] = new Matrix3();

}

}

}

//
getCameraArray( camera ) {

if ( camera.isArrayCamera ) return camera.cameras;

this.cameraArray[ 0 ] = camera;

return this.cameraArray;

}

updateCameraProjectionMatricesUniform( camera, uniforms ) {

var cameras = this.getCameraArray( camera );

for ( var i = 0; i < cameras.length; i ++ ) {

this.mat4[ i ].copy( cameras[ i ].projectionMatrix );

}

uniforms.setValue( this.gl, 'projectionMatrices', this.mat4 );

}

updateCameraViewMatricesUniform( camera, uniforms ) {

var cameras = this.getCameraArray( camera );

for ( var i = 0; i < cameras.length; i ++ ) {

this.mat4[ i ].copy( cameras[ i ].matrixWorldInverse );

}

uniforms.setValue( this.gl, 'viewMatrices', this.mat4 );

}

updateObjectMatricesUniforms( object, camera, uniforms ) {

var cameras = this.getCameraArray( camera );

for ( var i = 0; i < cameras.length; i ++ ) {

this.mat4[ i ].multiplyMatrices( cameras[ i ].matrixWorldInverse, object.matrixWorld );
this.mat3[ i ].getNormalMatrix( this.mat4[ i ] );

}

uniforms.setValue( this.gl, 'modelViewMatrices', this.mat4 );
uniforms.setValue( this.gl, 'normalMatrices', this.mat3 );

}

}

export { WebGLMultiview };
Loading

0 comments on commit 57e16fe

Please sign in to comment.