|
/* global THREE, setup, animate */ |
|
let container, |
|
renderer, |
|
scene, |
|
camera, |
|
display, |
|
appScene, |
|
terrain = []; |
|
|
|
function init() { |
|
container = document.createElement("div"); |
|
document.body.appendChild(container); |
|
|
|
scene = new THREE.Scene(); |
|
|
|
appScene = new THREE.Object3D(); |
|
scene.add(appScene); |
|
|
|
camera = new THREE.PerspectiveCamera(60, window.innerWidth / window.innerHeight, 0.1, 1000); |
|
camera.lookAt(new THREE.Vector3()); |
|
|
|
const ambientLight = new THREE.AmbientLight(0x808080); |
|
scene.add(ambientLight); |
|
|
|
const directionalLight = new THREE.DirectionalLight(0xffffff, 1); |
|
directionalLight.position.set(1, 1, 1); |
|
scene.add(directionalLight); |
|
|
|
initTerrain(); |
|
|
|
renderer = new THREE.WebGLRenderer({ |
|
antialias: true, |
|
alpha: true |
|
}); |
|
renderer.setPixelRatio(window.devicePixelRatio); |
|
renderer.setSize(window.innerWidth, window.innerHeight); |
|
container.appendChild(renderer.domElement); |
|
} |
|
|
|
function initTerrain() { |
|
const terrainMaterial = new THREE.MeshBasicMaterial({ |
|
color: 0x000000, |
|
wireframe: false |
|
}); |
|
const terrainMeshes = {}; |
|
const _getTerrainMesh = id => { |
|
let terrainMesh = terrainMeshes[id]; |
|
if (!terrainMesh) { |
|
terrainMesh = _makeTerrainMesh(); |
|
terrainMeshes[id] = terrainMesh; |
|
terrain.push(terrainMesh); |
|
scene.add(terrainMesh); |
|
} |
|
return terrainMesh; |
|
}; |
|
const _makeTerrainMesh = () => { |
|
const geometry = new THREE.BufferGeometry(); |
|
const positions = Float32Array.from([0, 0, 0, 0, 1, 0, 1, 1, 0]); |
|
geometry.addAttribute("position", new THREE.BufferAttribute(positions, 3)); |
|
const normals = Float32Array.from([0, 0, 1, 0, 0, 1, 0, 0, 1]); |
|
geometry.addAttribute("normal", new THREE.BufferAttribute(normals, 3)); |
|
const indices = Uint32Array.from([0, 1, 2]); |
|
geometry.setIndex(new THREE.BufferAttribute(indices, 1)); |
|
const material = terrainMaterial; |
|
const mesh = new THREE.Mesh(geometry, material); |
|
mesh.frustumCulled = false; |
|
return mesh; |
|
}; |
|
const _loadTerrainMesh = (terrainMesh, { positions, normals, indices }) => { |
|
const newPositions = new Float32Array(positions.length); |
|
newPositions.set(positions); |
|
terrainMesh.geometry.addAttribute("position", new THREE.BufferAttribute(newPositions, 3)); |
|
const newNormals = new Float32Array(normals.length); |
|
newNormals.set(normals); |
|
terrainMesh.geometry.addAttribute("normal", new THREE.BufferAttribute(newNormals, 3)); |
|
const newIndices = new Uint16Array(indices.length); |
|
newIndices.set(indices); |
|
terrainMesh.geometry.setIndex(new THREE.BufferAttribute(newIndices, 1)); |
|
}; |
|
const _onMesh = updates => { |
|
for (let i = 0; i < updates.length; i++) { |
|
const update = updates[i]; |
|
const terrainMesh = _getTerrainMesh(update.id); |
|
_loadTerrainMesh(terrainMesh, update); |
|
} |
|
}; |
|
window.browser.nativeMl.RequestMesh(_onMesh); |
|
} |
|
|
|
let reloading = false; |
|
|
|
function _animate(time, frame) { |
|
const inputSources = display.session.getInputSources(); |
|
|
|
if (!reloading) { |
|
try { |
|
animate(frame, inputSources); |
|
} catch (e) { |
|
console.log(e); |
|
} |
|
} |
|
|
|
renderer.render(scene, renderer.vr.enabled ? renderer.vr.getCamera(camera) : camera); |
|
} |
|
|
|
init(); |
|
|
|
(async () => { |
|
display = await navigator.xr.requestDevice(); |
|
const session = await display.requestSession({ |
|
exclusive: true |
|
}); |
|
display.session = session; |
|
|
|
const gamepads = navigator.getGamepads(); |
|
let lastSelect = performance.now(); |
|
|
|
session.onselect = () => { |
|
if (performance.now() - lastSelect < 500) { |
|
console.log("reloading"); |
|
appScene.children.slice(0).forEach(child => appScene.remove(child)); |
|
document.getElementById("app").remove(); |
|
const app = document.createElement("script"); |
|
app.id = "app"; |
|
reloading = true; |
|
app.addEventListener( |
|
"load", |
|
() => { |
|
console.log("reloaded"); |
|
try { |
|
setup(appScene, terrain, gamepads); |
|
reloading = false; |
|
} catch (e) { |
|
console.log(e); |
|
} |
|
}, |
|
{ once: true } |
|
); |
|
document.body.appendChild(app); |
|
app.src = `app.js?${Date.now()}`; |
|
} |
|
lastSelect = performance.now(); |
|
}; |
|
|
|
session.requestAnimationFrame((timestamp, frame) => { |
|
renderer.vr.setSession(session, { |
|
frameOfReferenceType: "stage" |
|
}); |
|
|
|
const viewport = session.baseLayer.getViewport(frame.views[0]); |
|
const width = viewport.width; |
|
const height = viewport.height; |
|
|
|
renderer.setSize(width * 2, height); |
|
|
|
renderer.setAnimationLoop(null); |
|
|
|
renderer.vr.enabled = true; |
|
renderer.vr.setDevice(display); |
|
setup(appScene, terrain, gamepads); |
|
renderer.vr.setAnimationLoop(_animate); |
|
}); |
|
})(); |