Skip to content

Instantly share code, notes, and snippets.

@nickjanssen
Last active November 22, 2016 07:49
Show Gist options
  • Save nickjanssen/21b46c8c7002eb2d60caadc0f785536d to your computer and use it in GitHub Desktop.
Save nickjanssen/21b46c8c7002eb2d60caadc0f785536d to your computer and use it in GitHub Desktop.
Example code showing how to create a Google Cardboard web demo. Link: http://cardboard.nickjanssen.com/
import React, { Component } from 'react'
const sceneConfig = {
url: 'Classroom/scene.json',
clearColor: 0xdbfff8,
startPosition: new THREE.Vector3(3, 2, 3),
lookAt: new THREE.Vector3(0, 2, 0)
}
const isMobile = typeof window.orientation !== 'undefined'
export default class App extends Component {
constructor(props) {
super(props)
this.state = {
loaded: false,
started: false,
enabledVR: isMobile
}
}
componentDidMount() {
const clock = new THREE.Clock()
const renderer = new THREE.WebGLRenderer()
renderer.setPixelRatio( window.devicePixelRatio )
renderer.setSize( window.innerWidth, window.innerHeight )
this._container.appendChild(renderer.domElement)
const effect = new THREE.StereoEffect( renderer )
effect.setSize( window.innerWidth, window.innerHeight )
const loader = new THREE.ObjectLoader()
const scene = new THREE.Scene()
const camera = new THREE.PerspectiveCamera( 70, window.innerWidth / window.innerHeight, 0.01, 1000 )
const deviceOrientationControls = new THREE.DeviceOrientationControls( camera )
const mouseControls = new THREE.MouseControls( camera )
let touchMoveForward = false
window.position = camera.position
window.addEventListener('resize', () => {
camera.aspect = window.innerWidth / window.innerHeight
camera.updateProjectionMatrix()
renderer.setSize( window.innerWidth, window.innerHeight )
}, false)
const init = () => {
loader.load(`scenes/${sceneConfig.url}?v1_1`, (mesh) => {
renderer.setClearColor(sceneConfig.clearColor)
scene.add(mesh)
this.setState({
loaded: true
})
camera.position.copy(sceneConfig.startPosition)
camera.lookAt(sceneConfig.lookAt)
})
// Add a cubemap/skybox
const imagePrefix = 'images/skybox/saitama_park_2048x1024_'
const directions = ['left', 'right', 'up', 'down', 'front', 'back']
const imageSuffix = '.png'
const skyGeometry = new THREE.CubeGeometry( 50, 50, 50 )
const materialArray = []
const textureLoader = new THREE.TextureLoader()
for (let i = 0; i < 6; i++) {
materialArray.push( new THREE.MeshBasicMaterial({
map: textureLoader.load( imagePrefix + directions[i] + imageSuffix ),
side: THREE.BackSide
}))
}
const skyMaterial = new THREE.MeshFaceMaterial( materialArray )
const skyBox = new THREE.Mesh( skyGeometry, skyMaterial )
scene.add( skyBox )
// end cubemap/skybox code
renderer.domElement.addEventListener( 'touchstart', () => {
touchMoveForward = true
})
document.addEventListener( 'touchmove', (e) => {
e.preventDefault()
})
renderer.domElement.addEventListener( 'touchend', () => {
touchMoveForward = false
})
}
const tick = (dt) => {
if (isMobile) {
deviceOrientationControls.update(dt)
}
if (!isMobile) {
mouseControls.update(dt)
}
if (touchMoveForward) {
camera.translateZ(-dt * 2)
}
camera.position.clamp(new THREE.Vector3(-4.6, 1.4, -3.2), new THREE.Vector3(4.6, 1.4, 3.2))
}
const animate = () => {
const delta = clock.getDelta()
requestAnimationFrame(animate)
tick(delta)
if (this.state.enabledVR) {
effect.render(scene, camera)
}
else {
renderer.render(scene, camera)
}
}
this.renderer = renderer
init()
animate()
}
render() {
return (
<div ref={(c) => this._container = c} className="render-view">
<div className={`blocker ${this.state.started && 'loaded'}`}>
<div className="instructions">
<div className="section">
<h1>Google Cardboard Web Demo</h1>
</div>
<div className="section">
{this.state.loaded ?
<button onClick={() => {
this.setState({
started: true
})
}} className={'button'}>Start</button>
:
<div className="spinner">
<div className="double-bounce1"></div>
<div className="double-bounce2"></div>
</div>
}
</div>
<div className="section">
{isMobile ?
<img className="cb-icon" src="images/rotate-instructions.svg" />
:
<div>
<p className="warning">Mobile device not detected.</p>
<p>Arrow keys to move.<br />Mouse to look around.</p>
</div>
}
</div>
<div className="section">
{isMobile ?
<div>
<p>Rotate device to look around.<br />Touch screen to move forward.</p>
</div>
:
<img src="images/drag.png" />
}
</div>
</div>
</div>
{this.state.started &&
<div className={`vr-enable-button ${this.state.enabledVR ? 'on' : ''}`}>
<img
src={'images/google-cardboard.svg'}
/>
<label className="switch">
<input type="checkbox" checked={this.state.enabledVR}
onClick={() => {
this.setState({
enabledVR: !this.state.enabledVR
})
this.renderer.setSize( window.innerWidth, window.innerHeight )
}} />
<div className="slider round"></div>
</label>
</div>}
</div>
)
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment