xrfragment/example/threejs/sandbox/index.html

259 lines
8.8 KiB
HTML
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<!DOCTYPE html>
<html lang="en">
<head>
<title>THREE.js - xrfragment sandbox</title>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no">
<link rel="stylesheet" href="./../../assets/css/axist.min.css" />
<link type="text/css" rel="stylesheet" href="./../../assets/css/style.css"/>
</head>
<body>
<div id="overlay" x-data="{ urls: ['#pos=0,1.6,15','#pos=0,1.6,15&rot=0,360,0'] }">
<img src="./../../assets/logo.png" class="logo"/>
<input type="submit" value="load 3D asset"></input>
<input type="text" id="uri" value="" onchange="XRF.navigator.to( $('#uri').value )"/>
</div>
<a class="btn-foot" id="source" target="_blank" href="https://github.com/coderofsalvation/xrfragment-helloworld"> clone project</a>
<a class="btn-foot" id="embed" target="_blank" onclick="embed()">📺 embed</a>
<a class="btn-foot" id="model" target="_blank" href="index.gltf">⬇️ model</a>
<textarea style="display:none"></textarea>
<script async src="./../../assets/js/alpine.min.js"></script>
<!-- Import maps polyfill -->
<!-- Remove this when import maps will be widely supported -->
<script async src="https://unpkg.com/es-module-shims@1.6.3/dist/es-module-shims.js"></script>
<script type="importmap">
{
"imports": {
"three": "https://unpkg.com/three@0.151.3/build/three.module.js",
"three/addons/": "https://unpkg.com/three@0.151.3/examples/jsm/"
}
}
</script>
<script type="module">
import * as THREE from 'three';
import xrf from './../../../dist/xrfragment.three.module.js';
import { loadFile, setupConsole, setupUrlBar, notify } from './../../assets/js/utils.js';
import { RGBELoader } from 'three/addons/loaders/RGBELoader.js';
import { Lensflare, LensflareElement } from 'three/addons/objects/Lensflare.js';
import { BoxLineGeometry } from 'three/addons/geometries/BoxLineGeometry.js';
import { Reflector } from 'three/addons/objects/Reflector.js';
import { VRButton } from 'three/addons/webxr/VRButton.js';
import { GLTFLoader } from 'three/addons/loaders/GLTFLoader.js';
import { FBXLoader } from 'three/addons/loaders/FBXLoader.js';
import { HTMLMesh } from 'three/addons/interactive/HTMLMesh.js';
import { InteractiveGroup } from 'three/addons/interactive/InteractiveGroup.js';
import { XRControllerModelFactory } from 'three/addons/webxr/XRControllerModelFactory.js';
import { OrbitControls } from 'three/addons/controls/OrbitControls.js';
import { GUI } from 'three/addons/libs/lil-gui.module.min.js';
import Stats from 'three/addons/libs/stats.module.js';
window.$ = (s) => document.querySelector(s)
let camera, scene, renderer, controls;
let reflector;
let stats, statsMesh;
let vrbutton;
const parameters = {
env: 1.0,
};
init();
notify("NOTE: only AFRAME demo has immersive back-button (for now)")
function init() {
scene = new THREE.Scene();
scene.background = new THREE.Color( 0xcccccc );
camera = new THREE.PerspectiveCamera( 70, window.innerWidth / window.innerHeight, 0.1, 2000 );
renderer = new THREE.WebGLRenderer( { antialias: true } );
renderer.autoClear = false;
renderer.setPixelRatio( window.devicePixelRatio );
renderer.setSize( window.innerWidth, window.innerHeight );
renderer.outputEncoding = THREE.sRGBEncoding;
renderer.xr.enabled = true;
renderer.domElement.className = "render"
document.body.appendChild( renderer.domElement );
document.body.appendChild( vrbutton = VRButton.createButton( renderer ) );
window.addEventListener( 'resize', onWindowResize );
let cameraRig = new THREE.Group()
cameraRig.position.set( 0, 0, 0 );
camera.position.set(0,1.6,0)
cameraRig.add(camera)
scene.add(cameraRig)
// enable XR fragments
let XRF = xrf.init({
THREE,
camera:cameraRig,
scene,
renderer,
debug: true,
loaders: { gltf: GLTFLoader, fbx: FBXLoader }, // which 3D assets (extensions) to check for XR fragments?
})
// optional: react/extend/hook into XR fragment
XRF.env = (xrf,v,opts) => {
let { mesh, model, camera, scene, renderer, THREE} = opts
xrf(v,opts)
}
// *TODO* lowhanging fruit: during XR fragments-query milestone, target objects using XR fragment queries
// to provide jquery-ish interface for three.js)
//
// XRF('example1.gltf#q=.foo', (objs) => {
//
// })
window.XRF = XRF // expose to form
let file = document.location.search.length > 2 ? document.location.search.substr(1) + document.location.hash : 'index.gltf#pos=0,1,20'
// optional decoration of href event
XRF.addEventListener('href',(e) => {
if( e.click ){
const { mesh, model, camera, scene, renderer, THREE} = e.XRF
const url = e.xrf.string
const isExtern = url[0] != '#'
const promise = e.promise() // promisify event
document.querySelector('#model').setAttribute('href',url.replace(/.*\?/,'') )
promise.resolve()
}
})
XRF.navigator.to( file )
// setup mouse controls
//controls = new OrbitControls( camera, renderer.domElement );
//controls.listenToKeyEvents( window ); // optional
//controls.enableDamping = true; // an animation loop is required when either damping or auto-rotation are enabled
//controls.dampingFactor = 0.1;
//controls.screenSpacePanning = false;
//controls.minDistance = 0.1;
//controls.maxDistance = 5000;
//controls.maxPolarAngle = Math.PI / 2;
//controls.target = new THREE.Vector3(0,1.6,0)
//controls.update()
const geometry = new THREE.BufferGeometry();
geometry.setFromPoints( [ new THREE.Vector3( 0, 0, 0 ), new THREE.Vector3( 0, 0, - 5 ) ] );
const controller1 = renderer.xr.getController( 0 );
controller1.add( new THREE.Line( geometry ) );
cameraRig.add( controller1 );
const controller2 = renderer.xr.getController( 1 );
controller2.add( new THREE.Line( geometry ) );
cameraRig.add( controller2 );
const controllerModelFactory = new XRControllerModelFactory();
const controllerGrip1 = renderer.xr.getControllerGrip( 0 );
controllerGrip1.add( controllerModelFactory.createControllerModel( controllerGrip1 ) );
cameraRig.add( controllerGrip1 );
const controllerGrip2 = renderer.xr.getControllerGrip( 1 );
controllerGrip2.add( controllerModelFactory.createControllerModel( controllerGrip2 ) );
cameraRig.add( controllerGrip2 );
setupConsole()
setupUrlBar( $('input#uri'), XRF )
// GUI
function onChange() {
renderer.toneMappingExposure = parameters.env;
}
const gui = new GUI( { width: 300 } );
gui.add( parameters, 'env', 0.2, 3.0, 0.1 ).onChange( onChange );
const mesh = new HTMLMesh( gui.domElement );
mesh.position.x = - 0.75;
mesh.position.y = 1.5;
mesh.position.z = 0.3;
mesh.rotation.y = Math.PI / 4;
mesh.scale.setScalar( 2 );
// Add stats.js
stats = new Stats();
stats.dom.style.width = '80px';
stats.dom.style.height = '48px';
document.body.appendChild( stats.dom );
statsMesh = new HTMLMesh( stats.dom );
statsMesh.position.x = - 0.75;
statsMesh.position.y = 2;
statsMesh.position.z = 0.3;
statsMesh.rotation.y = Math.PI / 4;
statsMesh.scale.setScalar( 2.5 );
vrbutton.addEventListener('click', () => {
// show gui inside VR scene
gui.domElement.style.visibility = 'hidden';
XRF.interactive.add( mesh );
XRF.interactive.add( statsMesh );
})
let fileLoaders = loadFile({
".gltf": (file) => file.arrayBuffer().then( (data) => xrf.navigator.to(file.name,null,xrf.loaders.gltf,data) ),
".glb": (file) => file.arrayBuffer().then( (data) => xrf.navigator.to(file.name,null,xrf.loaders.gltf,data) )
})
$("#overlay > input[type=submit]").addEventListener("click", fileLoaders )
}
function onWindowResize() {
camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();
renderer.setSize( window.innerWidth, window.innerHeight );
}
function animate() {
renderer.setAnimationLoop( render );
}
function render() {
const time = performance.now() * 0.0002;
//const torus = scene.getObjectByName( 'torus' );
//torus.rotation.x = time * 0.4;
//torus.rotation.y = time;
//controls.update()
renderer.render( scene, camera );
stats.update();
// Canvas elements doesn't trigger DOM updates, so we have to update the texture
statsMesh.material.map.update();
}
animate();
</script>
</body>
</html>