infamous
Version:
A CSS3D/WebGL UI library.
165 lines (128 loc) • 5.5 kB
JavaScript
import WEBVR from './WebVR.js'
import {
//PerspectiveCamera,
WebGLRenderer,
BasicShadowMap,
PCFSoftShadowMap,
PCFShadowMap,
} from 'three'
import Class from 'lowclass'
const sceneStates = new WeakMap
// A singleton responsible for setting up and drawing a WebGL scene for a given
// infamous/core/Scene using Three.js
const WebGLRendererThree = Class('WebGLRendererThree', {
initGl(scene) {
let sceneState = sceneStates.has(scene)
if (sceneState) sceneState = sceneStates.get(scene)
else sceneStates.set(scene, sceneState = {
// TODO: get the active camera from the scene
//camera: new PerspectiveCamera( 75, 16/9, 0.1, 1000 ),
// TODO: options controlled by HTML attributes on scene elements.
renderer: new WebGLRenderer( {
// TODO: how do we change alpha:true to alpha:false after the
// fact?
alpha: true,
antialias: true,
} ),
})
const { renderer } = sceneState
// TODO: make configurable by property/attribute
renderer.setPixelRatio(window.devicePixelRatio)
renderer.shadowMap.enabled = true
renderer.shadowMap.type = PCFSoftShadowMap; // default PCFShadowMap
this.updateResolution(scene)
scene.on('sizechange', () => this.updateResolution(scene))
// TODO? Maybe the html/scene.js element should be responsible for
// making this, so that DOM logic is encapsulated there?
scene._canvasContainer.appendChild( renderer.domElement )
},
drawScene(scene) {
const {renderer /* , scene: threeScene, camera */} = sceneStates.get(scene)
renderer.render(scene.threeObject3d, scene.threeCamera)
},
// TODO FIXME This is tied to the `sizechange` event of Scene, which means
// camera and renderer resize happens outside of the animation loop, but as
// with _calcSize, we want to see if we can put this in the nimation loop
// as well. Putting this logic in the loop depends on putting _calcSize in
// the loop. #66
updateResolution(scene) {
const state = sceneStates.get(scene)
scene._updateCameraAspect()
scene._updateCameraPerspective()
scene._updateCameraProjection()
state.renderer.setSize( scene._calculatedSize.x, scene._calculatedSize.y )
// Indirectly causes Motor to call this.drawScene(). It's important to
// call this rather than just this.drawScene() directly because Motor
// will make sure it runs in an animation frame.
scene._needsToBeRendered()
},
setClearColor( scene, color, opacity ) {
sceneStates.get( scene ).renderer.setClearColor( color, opacity )
},
setClearAlpha( scene, opacity ) {
sceneStates.get( scene ).renderer.setClearAlpha( opacity )
},
setShadowMapType(scene, type) {
type = type.toLowerCase()
if ( type == 'pcf' ) {
sceneStates.get( scene ).renderer.shadowMap.type = PCFShadowMap
}
else if ( type == 'pcfsoft' ) {
sceneStates.get( scene ).renderer.shadowMap.type = PCFSoftShadowMap
}
else if ( type == 'basic' ) {
sceneStates.get( scene ).renderer.shadowMap.type = BasicShadowMap
}
else { // default
sceneStates.get( scene ).renderer.shadowMap.type = PCFShadowMap
}
},
requestFrame( scene, fn ) {
const renderer = sceneStates.get( scene ).renderer
if ( renderer.animate ) // < r94
renderer.animate( fn )
else if ( renderer.setAnimationLoop ) // >= r94
renderer.setAnimationLoop( fn )
},
// This needs work: at the moment it has only been tested toggling it on
// once and nothing more.
enableVR( scene, enable ) {
const renderer = sceneStates.get( scene ).renderer
renderer.vr.enabled = enable
},
createDefaultWebVREntryUI( scene ) {
const renderer = sceneStates.get( scene ).renderer
window.addEventListener( 'vrdisplaypointerrestricted', onPointerRestricted, false );
window.addEventListener( 'vrdisplaypointerunrestricted', onPointerUnrestricted, false );
function onPointerRestricted() {
var pointerLockElement = renderer.domElement;
if ( pointerLockElement && typeof(pointerLockElement.requestPointerLock) === 'function' ) {
pointerLockElement.requestPointerLock();
}
}
function onPointerUnrestricted() {
var currentPointerLockElement = document.pointerLockElement;
var expectedPointerLockElement = renderer.domElement;
if ( currentPointerLockElement && currentPointerLockElement === expectedPointerLockElement && typeof(document.exitPointerLock) === 'function' ) {
document.exitPointerLock();
}
}
const button = WEBVR.createButton( renderer )
button.setAttribute( 'id', 'vrButton' )
button.style.color = 'black'
button.style['border-color'] = 'black'
button.setAttribute( 'slot', 'misc' )
scene.appendChild( button )
return button
},
})
let instance = null
export
function getWebGLRendererThree(scene) {
if (instance) return instance
else return instance = new WebGLRendererThree
}
export
function destroyWebGLRendererThree() {
instance = null
}