update non-euclidian
This commit is contained in:
parent
ff05234606
commit
29744defef
10 changed files with 131 additions and 173 deletions
File diff suppressed because one or more lines are too long
|
|
@ -34,8 +34,13 @@ window.AFRAME.registerComponent('xrf', {
|
||||||
let blinkControls = document.querySelector('[blink-controls]')
|
let blinkControls = document.querySelector('[blink-controls]')
|
||||||
if( blinkControls ){
|
if( blinkControls ){
|
||||||
let els = xrf.getCollisionMeshes()
|
let els = xrf.getCollisionMeshes()
|
||||||
|
let invisible = false
|
||||||
els.map( (mesh) => {
|
els.map( (mesh) => {
|
||||||
mesh.material.visible = false
|
if( !invisible ){
|
||||||
|
invisible = mesh.material.clone()
|
||||||
|
invisible.visible = false
|
||||||
|
}
|
||||||
|
mesh.material = invisible
|
||||||
let el = document.createElement("a-entity")
|
let el = document.createElement("a-entity")
|
||||||
el.setAttribute("xrf-get", mesh.name )
|
el.setAttribute("xrf-get", mesh.name )
|
||||||
el.setAttribute("class","floor")
|
el.setAttribute("class","floor")
|
||||||
|
|
@ -124,21 +129,6 @@ window.AFRAME.registerComponent('xrf', {
|
||||||
els.map( (el) => document.querySelector('a-scene').removeChild(el) )
|
els.map( (el) => document.querySelector('a-scene').removeChild(el) )
|
||||||
})
|
})
|
||||||
|
|
||||||
// *TODO* workaround no longer needed?
|
|
||||||
//
|
|
||||||
// aScene.addEventListener('enter-vr', () => {
|
|
||||||
// // undo lookup-control shenanigans (which blocks updating camerarig position in VR)
|
|
||||||
// document.querySelector('[camera]').object3D.parent.matrixAutoUpdate = true
|
|
||||||
// document.querySelector('[camera]').components['look-controls'].pause() //removeAttribute("look-controls")
|
|
||||||
// document.querySelector('[camera]').components['wasd-controls'].pause() //removeAttribute("wasd-controls")
|
|
||||||
// })
|
|
||||||
// aScene.addEventListener('exit-vr', () => {
|
|
||||||
// // redo lookup-control shenanigans (which blocks updating camerarig position in VR)
|
|
||||||
// document.querySelector('[camera]').object3D.parent.matrixAutoUpdate = false
|
|
||||||
// document.querySelector('[camera]').components['look-controls'].play() //setAttribute("look-controls",'')
|
|
||||||
// document.querySelector('[camera]').components['wasd-controls'].play() //setAttribute("wasd-controls",'')
|
|
||||||
// })
|
|
||||||
|
|
||||||
AFRAME.XRF.navigator.to(this.data)
|
AFRAME.XRF.navigator.to(this.data)
|
||||||
.then( (model) => {
|
.then( (model) => {
|
||||||
let gets = [ ...document.querySelectorAll('[xrf-get]') ]
|
let gets = [ ...document.querySelectorAll('[xrf-get]') ]
|
||||||
|
|
|
||||||
|
|
@ -51,7 +51,6 @@ xrf.drawLineToMesh = (opts) => {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
xrf.addEventListener('navigateLoaded', (opts) => {
|
|
||||||
xrf.addEventListener('render', (opts) => {
|
xrf.addEventListener('render', (opts) => {
|
||||||
// update focusline
|
// update focusline
|
||||||
let {time,model} = opts
|
let {time,model} = opts
|
||||||
|
|
@ -63,4 +62,3 @@ xrf.addEventListener('navigateLoaded', (opts) => {
|
||||||
if( xrf.focusLine.opacity > 0.0 ) xrf.focusLine.opacity -= time*0.2
|
if( xrf.focusLine.opacity > 0.0 ) xrf.focusLine.opacity -= time*0.2
|
||||||
if( xrf.focusLine.opacity < 0.0 ) xrf.focusLine.opacity = 0
|
if( xrf.focusLine.opacity < 0.0 ) xrf.focusLine.opacity = 0
|
||||||
})
|
})
|
||||||
})
|
|
||||||
|
|
|
||||||
|
|
@ -24,7 +24,7 @@ xrf.filter = function(query, cb){
|
||||||
xrf.filter.scene = function(opts){
|
xrf.filter.scene = function(opts){
|
||||||
let {scene,frag} = opts
|
let {scene,frag} = opts
|
||||||
|
|
||||||
xrf.filter
|
scene = xrf.filter
|
||||||
.sort(frag) // get (sorted) filters from XR Fragments
|
.sort(frag) // get (sorted) filters from XR Fragments
|
||||||
.process(frag,scene,opts) // show/hide things
|
.process(frag,scene,opts) // show/hide things
|
||||||
|
|
||||||
|
|
@ -41,12 +41,14 @@ xrf.filter.sort = function(frag){
|
||||||
return xrf.filter
|
return xrf.filter
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// opts = {copyScene:true} in case you want a copy of the scene (not filter the current scene inplace)
|
||||||
xrf.filter.process = function(frag,scene,opts){
|
xrf.filter.process = function(frag,scene,opts){
|
||||||
const cleanupKey = (k) => k.replace(/[-\*\/]/g,'')
|
const cleanupKey = (k) => k.replace(/[-\*\/]/g,'')
|
||||||
let firstFilter = frag.filters.length ? frag.filters[0].filter.get() : false
|
let firstFilter = frag.filters.length ? frag.filters[0].filter.get() : false
|
||||||
const hasName = (m,name,filter) => m.name == name
|
const hasName = (m,name,filter) => m.name == name
|
||||||
const hasNameOrTag = (m,name_or_tag,filter) => hasName(m,name_or_tag) ||
|
const hasNameOrTag = (m,name_or_tag,filter) => hasName(m,name_or_tag) ||
|
||||||
String(m.userData['tag']).match( new RegExp("(^| )"+name_or_tag) )
|
String(m.userData['tag']).match( new RegExp("(^| )"+name_or_tag) )
|
||||||
|
|
||||||
// utility functions
|
// utility functions
|
||||||
const getOrCloneMaterial = (o) => {
|
const getOrCloneMaterial = (o) => {
|
||||||
if( o.material ){
|
if( o.material ){
|
||||||
|
|
@ -70,12 +72,20 @@ xrf.filter.process = function(frag,scene,opts){
|
||||||
let obj
|
let obj
|
||||||
frag.target = firstFilter
|
frag.target = firstFilter
|
||||||
scene.traverse( (n) => hasName(n, firstFilter.key,firstFilter) && (obj = n) )
|
scene.traverse( (n) => hasName(n, firstFilter.key,firstFilter) && (obj = n) )
|
||||||
|
console.log("reparent "+firstFilter.key+" "+((opts.copyScene)?"copy":"inplace"))
|
||||||
if(obj ){
|
if(obj ){
|
||||||
while( scene.children.length > 0 ) scene.children[0].removeFromParent()
|
|
||||||
obj.position.set(0,0,0)
|
obj.position.set(0,0,0)
|
||||||
|
if( opts.copyScene ){
|
||||||
|
opts.copyScene = new xrf.THREE.Scene()
|
||||||
|
opts.copyScene.children[0] = obj
|
||||||
|
scene = opts.copyScene
|
||||||
|
}else{
|
||||||
|
// empty current scene and add obj
|
||||||
|
while( scene.children.length > 0 ) scene.children[0].removeFromParent()
|
||||||
scene.add( obj )
|
scene.add( obj )
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// then show/hide things based on secondary selectors
|
// then show/hide things based on secondary selectors
|
||||||
// we don't use the XRWG (everything) because we process only the given (sub)scene
|
// we don't use the XRWG (everything) because we process only the given (sub)scene
|
||||||
|
|
@ -88,7 +98,7 @@ xrf.filter.process = function(frag,scene,opts){
|
||||||
// hide external objects temporarely
|
// hide external objects temporarely
|
||||||
scene.traverse( (m) => {
|
scene.traverse( (m) => {
|
||||||
if( m.isSRCExternal ){
|
if( m.isSRCExternal ){
|
||||||
m.traverse( (n) => (extembeds[ n.uuid ] = m) && (n.visible = false) )
|
m.traverse( (n) => (extembeds[ n.uuid ] = m) && (m.visible = false) )
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
@ -108,6 +118,6 @@ xrf.filter.process = function(frag,scene,opts){
|
||||||
for ( let i in extembeds ) extembeds[i].visible = true
|
for ( let i in extembeds ) extembeds[i].visible = true
|
||||||
})
|
})
|
||||||
|
|
||||||
return xrf.filter
|
return scene
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -39,6 +39,13 @@ xrf.frag.href = function(v, opts){
|
||||||
xrf
|
xrf
|
||||||
.emit('href',{click:true,mesh,xrf:v}) // let all listeners agree
|
.emit('href',{click:true,mesh,xrf:v}) // let all listeners agree
|
||||||
.then( () => {
|
.then( () => {
|
||||||
|
let {urlObj,dir,file,hash,ext} = xrf.parseUrl(v.string)
|
||||||
|
//if( !file.match(/\./) || file.match(/\.html/) ){
|
||||||
|
// debugger
|
||||||
|
// let inIframe
|
||||||
|
// try { inIframe = window.self !== window.top; } catch (e) { inIframe = true; }
|
||||||
|
// return inIframe ? window.parent.postMessage({ url: v.string }, '*') : window.open( v.string, '_blank')
|
||||||
|
//}
|
||||||
const flags = v.string[0] == '#' ? xrf.XRF.PV_OVERRIDE : undefined
|
const flags = v.string[0] == '#' ? xrf.XRF.PV_OVERRIDE : undefined
|
||||||
let toFrag = xrf.URI.parse( v.string, xrf.XRF.NAVIGATOR | xrf.XRF.PV_OVERRIDE | xrf.XRF.METADATA )
|
let toFrag = xrf.URI.parse( v.string, xrf.XRF.NAVIGATOR | xrf.XRF.PV_OVERRIDE | xrf.XRF.METADATA )
|
||||||
// always commit current location (keep a trail of last positions before we navigate)
|
// always commit current location (keep a trail of last positions before we navigate)
|
||||||
|
|
|
||||||
|
|
@ -7,6 +7,7 @@ xrf.frag.src = function(v, opts){
|
||||||
let url = v.string
|
let url = v.string
|
||||||
let srcFrag = opts.srcFrag = xrfragment.URI.parse(url)
|
let srcFrag = opts.srcFrag = xrfragment.URI.parse(url)
|
||||||
opts.isLocal = v.string[0] == '#'
|
opts.isLocal = v.string[0] == '#'
|
||||||
|
opts.isPortal = xrf.frag.src.renderAsPortal(mesh)
|
||||||
|
|
||||||
if( opts.isLocal ){
|
if( opts.isLocal ){
|
||||||
xrf.frag.src.localSRC(url,srcFrag,opts) // local
|
xrf.frag.src.localSRC(url,srcFrag,opts) // local
|
||||||
|
|
@ -16,22 +17,21 @@ xrf.frag.src = function(v, opts){
|
||||||
xrf.frag.src.addModel = (model,url,frag,opts) => {
|
xrf.frag.src.addModel = (model,url,frag,opts) => {
|
||||||
let {mesh} = opts
|
let {mesh} = opts
|
||||||
let scene = model.scene
|
let scene = model.scene
|
||||||
xrf.frag.src.filterScene(scene,{...opts,frag}) // filter scene
|
scene = xrf.frag.src.filterScene(scene,{...opts,frag}) // get filtered scene
|
||||||
if( mesh.material ) mesh.material.visible = false // hide placeholder object
|
if( mesh.material && !mesh.userData.src ) mesh.material.visible = false // hide placeholder object
|
||||||
//enableSourcePortation(scene)
|
//enableSourcePortation(scene)
|
||||||
if( xrf.frag.src.renderAsPortal(mesh) ){
|
if( xrf.frag.src.renderAsPortal(mesh) ){
|
||||||
// only add remote objects, because
|
// only add remote objects, because
|
||||||
// local scene-objects are already added to scene
|
// local scene-objects are already added to scene
|
||||||
xrf.portalNonEuclidian({...opts,model,scene:model.scene})
|
xrf.portalNonEuclidian({...opts,model,scene:model.scene})
|
||||||
if( !opts.isLocal && !mesh.portal.isLens ) xrf.scene.add(scene)
|
if( !opts.isLocal ) xrf.scene.add(scene)
|
||||||
return
|
|
||||||
}else{
|
}else{
|
||||||
xrf.frag.src.scale( scene, opts, url ) // scale scene
|
xrf.frag.src.scale( scene, opts, url ) // scale scene
|
||||||
mesh.add(scene)
|
mesh.add(scene)
|
||||||
|
xrf.emit('parseModel', {...opts, scene, model})
|
||||||
}
|
}
|
||||||
// flag everything isSRC & isXRF
|
// flag everything isSRC & isXRF
|
||||||
mesh.traverse( (n) => { n.isSRC = n.isXRF = n[ opts.isLocal ? 'isSRCLocal' : 'isSRCExternal' ] = true })
|
mesh.traverse( (n) => { n.isSRC = n.isXRF = n[ opts.isLocal ? 'isSRCLocal' : 'isSRCExternal' ] = true })
|
||||||
xrf.emit('parseModel', {...opts, scene, model})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
xrf.frag.src.renderAsPortal = (mesh) => {
|
xrf.frag.src.renderAsPortal = (mesh) => {
|
||||||
|
|
@ -77,13 +77,16 @@ xrf.frag.src.externalSRC = (url,frag,opts) => {
|
||||||
}
|
}
|
||||||
|
|
||||||
xrf.frag.src.localSRC = (url,frag,opts) => {
|
xrf.frag.src.localSRC = (url,frag,opts) => {
|
||||||
let {model,scene} = opts
|
let {model,mesh,scene} = opts
|
||||||
|
setTimeout( () => {
|
||||||
|
if( mesh.material ) mesh.material = mesh.material.clone() // clone, so we can individually highlight meshes
|
||||||
let _model = {
|
let _model = {
|
||||||
animations: model.animations,
|
animations: model.animations,
|
||||||
scene: scene.clone()
|
scene: scene.clone() // *TODO* opts.isPortal ? scene : scene.clone()
|
||||||
}
|
}
|
||||||
_model.scenes = [_model.scene]
|
_model.scenes = [_model.scene]
|
||||||
xrf.frag.src.addModel(_model,url,frag, opts) // current file
|
xrf.frag.src.addModel(_model,url,frag, opts) // current file
|
||||||
|
},500 )
|
||||||
}
|
}
|
||||||
|
|
||||||
// scale embedded XR fragments https://xrfragment.org/#scaling%20of%20instanced%20objects
|
// scale embedded XR fragments https://xrfragment.org/#scaling%20of%20instanced%20objects
|
||||||
|
|
@ -121,12 +124,14 @@ xrf.frag.src.scale = function(scene, opts, url){
|
||||||
xrf.frag.src.filterScene = (scene,opts) => {
|
xrf.frag.src.filterScene = (scene,opts) => {
|
||||||
let { mesh, model, camera, renderer, THREE, hashbus, frag} = opts
|
let { mesh, model, camera, renderer, THREE, hashbus, frag} = opts
|
||||||
|
|
||||||
xrf.filter.scene({scene,frag,reparent:true})
|
scene = xrf.filter.scene({scene,frag,reparent:true}) // *TODO* ,copyScene: opts.isPortal})
|
||||||
|
|
||||||
|
if( !opts.isLocal ){
|
||||||
scene.traverse( (m) => {
|
scene.traverse( (m) => {
|
||||||
if( m.userData && (m.userData.src || m.userData.href) ) return ; // prevent infinite recursion
|
if( m.userData && (m.userData.src || m.userData.href) ) return ; // prevent infinite recursion
|
||||||
hashbus.pub.mesh(m,{scene,recursive:true}) // cool idea: recursion-depth based distance between face & src
|
hashbus.pub.mesh(m,{scene,recursive:true}) // cool idea: recursion-depth based distance between face & src
|
||||||
})
|
})
|
||||||
|
}
|
||||||
return scene
|
return scene
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -11,8 +11,6 @@ let loadAudio = (mimetype) => function(url,opts){
|
||||||
let {urlObj,dir,file,hash,ext} = xrf.parseUrl(url)
|
let {urlObj,dir,file,hash,ext} = xrf.parseUrl(url)
|
||||||
let frag = xrf.URI.parse( url )
|
let frag = xrf.URI.parse( url )
|
||||||
|
|
||||||
return
|
|
||||||
|
|
||||||
/* WebAudio: setup context via THREEjs */
|
/* WebAudio: setup context via THREEjs */
|
||||||
if( !camera.listener ){
|
if( !camera.listener ){
|
||||||
camera.listener = new THREE.AudioListener();
|
camera.listener = new THREE.AudioListener();
|
||||||
|
|
@ -37,7 +35,8 @@ let loadAudio = (mimetype) => function(url,opts){
|
||||||
}
|
}
|
||||||
|
|
||||||
sound.playXRF = (t) => {
|
sound.playXRF = (t) => {
|
||||||
|
mesh.add(sound)
|
||||||
|
try{
|
||||||
if( sound.isPlaying && t.y != undefined ) sound.stop()
|
if( sound.isPlaying && t.y != undefined ) sound.stop()
|
||||||
if( sound.isPlaying && t.y == undefined ) sound.pause()
|
if( sound.isPlaying && t.y == undefined ) sound.pause()
|
||||||
|
|
||||||
|
|
@ -61,11 +60,10 @@ let loadAudio = (mimetype) => function(url,opts){
|
||||||
}
|
}
|
||||||
sound.play()
|
sound.play()
|
||||||
}
|
}
|
||||||
|
}catch(e){ console.warn(e) }
|
||||||
}
|
}
|
||||||
mesh.add(sound)
|
|
||||||
});
|
|
||||||
|
|
||||||
mesh.audio = sound
|
mesh.audio = sound
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
let audioMimeTypes = [
|
let audioMimeTypes = [
|
||||||
|
|
|
||||||
12
src/3rd/js/three/xrf/src/html.js
Normal file
12
src/3rd/js/three/xrf/src/html.js
Normal file
|
|
@ -0,0 +1,12 @@
|
||||||
|
|
||||||
|
let loadHTML = (mimetype) => function(url,opts){
|
||||||
|
let {mesh,src,camera} = opts
|
||||||
|
let {urlObj,dir,file,hash,ext} = xrf.parseUrl(url)
|
||||||
|
let frag = xrf.URI.parse( url )
|
||||||
|
console.warn("todo: html viewer for src not implemented")
|
||||||
|
}
|
||||||
|
|
||||||
|
let htmlMimeTypes = [
|
||||||
|
'text/html'
|
||||||
|
]
|
||||||
|
htmlMimeTypes.map( (mimetype) => xrf.frag.src.type[ mimetype ] = loadHTML(mimetype) )
|
||||||
|
|
@ -8,55 +8,13 @@ xrf.frag.src.type['image/png'] = function(url,opts){
|
||||||
let {mesh,THREE} = opts
|
let {mesh,THREE} = opts
|
||||||
let restrictTo3DBoundingBox = mesh.geometry
|
let restrictTo3DBoundingBox = mesh.geometry
|
||||||
|
|
||||||
let renderEquirect = (texture) => {
|
mesh.material = new xrf.THREE.MeshBasicMaterial({
|
||||||
texture.mapping = THREE.EquirectangularReflectionMapping
|
map: null,
|
||||||
texture.needsUpdate = true
|
transparent: url.match(/(png|gif)/) ? true : false,
|
||||||
texture.wrapS = THREE.RepeatWrapping;
|
|
||||||
texture.wrapT = THREE.RepeatWrapping;
|
|
||||||
texture.magFilter = THREE.NearestFilter
|
|
||||||
texture.minFilter = THREE.NearestFilter
|
|
||||||
|
|
||||||
// poor man's equi-portal
|
|
||||||
mesh.material = new THREE.ShaderMaterial( {
|
|
||||||
side: THREE.DoubleSide,
|
side: THREE.DoubleSide,
|
||||||
uniforms: {
|
color: 0xFFFFFF,
|
||||||
pano: { value: texture },
|
opacity:1
|
||||||
selected: { value: false },
|
|
||||||
},
|
|
||||||
vertexShader: `
|
|
||||||
vec3 portalPosition;
|
|
||||||
varying vec3 vWorldPosition;
|
|
||||||
varying float vDistanceToCenter;
|
|
||||||
varying float vDistance;
|
|
||||||
void main() {
|
|
||||||
vDistanceToCenter = clamp(length(position - vec3(0.0, 0.0, 0.0)), 0.0, 1.0);
|
|
||||||
portalPosition = (modelMatrix * vec4(0.0, 0.0, 0.0, 1.0)).xyz;
|
|
||||||
vDistance = length(portalPosition - cameraPosition);
|
|
||||||
vWorldPosition = (modelMatrix * vec4(position, 1.0)).xyz;
|
|
||||||
gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
|
|
||||||
}
|
|
||||||
`,
|
|
||||||
fragmentShader: `
|
|
||||||
#define RECIPROCAL_PI2 0.15915494
|
|
||||||
uniform sampler2D pano;
|
|
||||||
uniform bool selected;
|
|
||||||
varying float vDistanceToCenter;
|
|
||||||
varying float vDistance;
|
|
||||||
varying vec3 vWorldPosition;
|
|
||||||
void main() {
|
|
||||||
vec3 direction = normalize(vWorldPosition - cameraPosition );
|
|
||||||
vec2 sampleUV;
|
|
||||||
sampleUV.y = clamp(direction.y * 0.5 + 0.5, 0.0, 1.0);
|
|
||||||
sampleUV.x = atan(direction.z, -direction.x) * -RECIPROCAL_PI2;
|
|
||||||
sampleUV.x += 0.33; // adjust focus to AFRAME's a-scene.components.screenshot.capture()
|
|
||||||
vec4 color = texture2D(pano, sampleUV);
|
|
||||||
vec4 selected_color = selected ? color*vec4(1.5) : color;
|
|
||||||
gl_FragColor = selected_color;
|
|
||||||
}
|
|
||||||
`,
|
|
||||||
});
|
});
|
||||||
mesh.material.needsUpdate = true
|
|
||||||
}
|
|
||||||
|
|
||||||
let renderImage = (texture) => {
|
let renderImage = (texture) => {
|
||||||
let img = {w: texture.source.data.width, h: texture.source.data.height}
|
let img = {w: texture.source.data.width, h: texture.source.data.height}
|
||||||
|
|
@ -72,27 +30,16 @@ xrf.frag.src.type['image/png'] = function(url,opts){
|
||||||
//}
|
//}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
//const geometry = new THREE.BoxGeometry();
|
mesh.material.map = texture
|
||||||
mesh.material = new xrf.THREE.MeshBasicMaterial({
|
mesh.needsUpdate = true
|
||||||
map: texture,
|
|
||||||
transparent: url.match(/(png|gif)/) ? true : false,
|
|
||||||
side: THREE.DoubleSide,
|
|
||||||
color: 0xFFFFFF,
|
|
||||||
opacity:1
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
let onLoad = (texture) => {
|
let onLoad = (texture) => {
|
||||||
texture.colorSpace = THREE.SRGBColorSpace;
|
texture.colorSpace = THREE.SRGBColorSpace;
|
||||||
texture.wrapS = THREE.RepeatWrapping;
|
texture.wrapS = THREE.RepeatWrapping;
|
||||||
texture.wrapT = THREE.RepeatWrapping;
|
texture.wrapT = THREE.RepeatWrapping;
|
||||||
// detect equirectangular image
|
|
||||||
if( texture && texture.source.data.height == texture.source.data.width/2 ){
|
|
||||||
renderEquirect(texture)
|
|
||||||
}else{
|
|
||||||
renderImage(texture)
|
renderImage(texture)
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
new THREE.TextureLoader().load( url, onLoad, null, console.error );
|
new THREE.TextureLoader().load( url, onLoad, null, console.error );
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,7 @@
|
||||||
xrf.portalNonEuclidian = function(opts){
|
xrf.portalNonEuclidian = function(opts){
|
||||||
let { frag, mesh, model, camera, scene, renderer} = opts
|
let { frag, mesh, model, camera, scene, renderer} = opts
|
||||||
|
|
||||||
|
|
||||||
mesh.portal = {
|
mesh.portal = {
|
||||||
pos: mesh.position.clone(),
|
pos: mesh.position.clone(),
|
||||||
posWorld: new xrf.THREE.Vector3(),
|
posWorld: new xrf.THREE.Vector3(),
|
||||||
|
|
@ -55,12 +56,6 @@ xrf.portalNonEuclidian = function(opts){
|
||||||
.filter( (n) => !n.portal ) // filter out (self)references to portals (prevent recursion)
|
.filter( (n) => !n.portal ) // filter out (self)references to portals (prevent recursion)
|
||||||
.map(addStencilFeature)
|
.map(addStencilFeature)
|
||||||
|
|
||||||
//// add missing lights to make sure things get lit properly
|
|
||||||
xrf.scene.traverse( (n) => n.isLight &&
|
|
||||||
!stencilObjects.find( (o) => o.uuid == n.uuid ) &&
|
|
||||||
stencilObjects.push(n)
|
|
||||||
)
|
|
||||||
|
|
||||||
// put it into a scene (without .add() because it reparents objects) so we can render it separately
|
// put it into a scene (without .add() because it reparents objects) so we can render it separately
|
||||||
mesh.portal.stencilObjects = new xrf.THREE.Scene()
|
mesh.portal.stencilObjects = new xrf.THREE.Scene()
|
||||||
mesh.portal.stencilObjects.children = stencilObjects
|
mesh.portal.stencilObjects.children = stencilObjects
|
||||||
|
|
@ -68,11 +63,6 @@ xrf.portalNonEuclidian = function(opts){
|
||||||
xrf.portalNonEuclidian.stencilRef += 1 // each portal has unique stencil id
|
xrf.portalNonEuclidian.stencilRef += 1 // each portal has unique stencil id
|
||||||
console.log(`enabling portal for object '${mesh.name}' (stencilRef:${mesh.portal.stencilRef})`)
|
console.log(`enabling portal for object '${mesh.name}' (stencilRef:${mesh.portal.stencilRef})`)
|
||||||
|
|
||||||
// clone so it won't be affected by other fragments
|
|
||||||
setTimeout( (mesh) => {
|
|
||||||
if( mesh.material ) mesh.material = mesh.material.clone() // clone, so we can individually highlight meshes
|
|
||||||
}, 0, mesh )
|
|
||||||
|
|
||||||
return this
|
return this
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -154,7 +144,7 @@ xrf.portalNonEuclidian = function(opts){
|
||||||
.setupStencilObjects(scene,opts)
|
.setupStencilObjects(scene,opts)
|
||||||
|
|
||||||
// move portal objects to portalposition
|
// move portal objects to portalposition
|
||||||
mesh.portal.positionObjectsIfNeeded(mesh.portal.posWorld, mesh.scale)
|
if( mesh.portal.stencilObjects ) mesh.portal.positionObjectsIfNeeded(mesh.portal.posWorld, mesh.scale)
|
||||||
}
|
}
|
||||||
|
|
||||||
xrf.portalNonEuclidian.selectStencil = (n, stencilRef, nested) => {
|
xrf.portalNonEuclidian.selectStencil = (n, stencilRef, nested) => {
|
||||||
|
|
@ -183,24 +173,25 @@ xrf.portalNonEuclidian.setMaterial = function(mesh){
|
||||||
|
|
||||||
xrf.addEventListener('parseModel',(opts) => {
|
xrf.addEventListener('parseModel',(opts) => {
|
||||||
const scene = opts.model.scene
|
const scene = opts.model.scene
|
||||||
// scene.traverse( (n) => n.renderOrder = 10 ) // rendering everything *after* the stencil buffers
|
//for( let i in scene.children ) scene.children[i].renderOrder = 10 // render outer layers last (worldspheres e.g.)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
||||||
// (re)set portalObject when entering/leaving a portal
|
// (re)set portalObjects when entering/leaving a portal
|
||||||
xrf.addEventListener('href', (opts) => {
|
let updatePortals = (opts) => {
|
||||||
let {mesh,v} = opts
|
|
||||||
if( opts.click && mesh.portal ){
|
|
||||||
if( !opts.click ) return
|
|
||||||
xrf.scene.traverse( (n) => {
|
xrf.scene.traverse( (n) => {
|
||||||
if( !n.portal ) return
|
if( !n.portal ) return
|
||||||
// since we're leaving this portal destination, lets move objects back to the portal
|
// move objects back to the portal
|
||||||
if( n.portal.isInside ) n.portal.positionObjectsIfNeeded( n.portal.posWorld, n.scale )
|
if( n.portal.isInside ) n.portal.positionObjectsIfNeeded( n.portal.posWorld, n.scale )
|
||||||
n.portal.isInside = false
|
n.portal.isInside = false
|
||||||
})
|
})
|
||||||
mesh.portal.isInside = true
|
if( opts.mesh && opts.mesh.portal && opts.click ){
|
||||||
mesh.portal.positionObjectsIfNeeded() // move objects back to original pos (since we are going there)
|
opts.mesh.portal.isInside = true
|
||||||
|
opts.mesh.portal.positionObjectsIfNeeded() // move objects back to original pos (since we are teleporting there)
|
||||||
}
|
}
|
||||||
})
|
}
|
||||||
|
|
||||||
|
xrf.addEventListener('href', (opts) => opts.click && updatePortals(opts) )
|
||||||
|
xrf.addEventListener('navigate', updatePortals )
|
||||||
|
|
||||||
xrf.portalNonEuclidian.stencilRef = 1
|
xrf.portalNonEuclidian.stencilRef = 1
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue