cleanup and minor tweaks
This commit is contained in:
parent
f08c0acfd4
commit
7f57e0907f
|
@ -788,6 +788,7 @@ pub.mesh = (mesh,model) => { // evaluate embedded fragments (metadata) insid
|
|||
|
||||
pub.fragment = (k, opts ) => { // evaluate one fragment
|
||||
let frag = opts.frag[k];
|
||||
|
||||
// call native function (xrf/env.js e.g.), or pass it to user decorator
|
||||
xrf.emit(k,opts)
|
||||
.then( () => {
|
||||
|
@ -852,6 +853,7 @@ xrf.parseModel = function(model,url){
|
|||
model.mixer = new xrf.THREE.AnimationMixer(model.scene)
|
||||
model.animations.map( (anim) => {
|
||||
anim.action = model.mixer.clipAction( anim )
|
||||
//anim.action.setLoop(0)
|
||||
anim.action.play()
|
||||
})
|
||||
|
||||
|
@ -865,9 +867,10 @@ xrf.parseModel = function(model,url){
|
|||
xrf.focusLine.material.dashSize = 0.2 + 0.02*Math.sin( model.clock.getElapsedTime() )
|
||||
xrf.focusLine.material.gapSize = 0.1 + 0.02*Math.sin( model.clock.getElapsedTime() *3 )
|
||||
xrf.focusLine.material.opacity = (0.25 + 0.15*Math.sin( model.clock.getElapsedTime() * 3 )) * xrf.focusLine.opacity;
|
||||
if( xrf.focusLine.opacity > 0.0 ) xrf.focusLine.opacity -= time*0.3
|
||||
if( xrf.focusLine.opacity > 0.0 ) xrf.focusLine.opacity -= time*0.2
|
||||
if( xrf.focusLine.opacity < 0.0 ) xrf.focusLine.opacity = 0
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
xrf.getLastModel = () => xrf.model.last
|
||||
|
@ -940,7 +943,7 @@ xrf.InteractiveGroup = function(THREE,renderer,camera){
|
|||
function nocollide(){
|
||||
if( nocollide.tid ) return // ratelimit
|
||||
_event.type = "nocollide"
|
||||
scope.children.map( (c) => c.dispatchEvent(_event) )
|
||||
scope.objects.map( (c) => c.dispatchEvent(_event) )
|
||||
nocollide.tid = setTimeout( () => nocollide.tid = null, 100 )
|
||||
}
|
||||
|
||||
|
@ -1082,8 +1085,12 @@ xrf.navigator.to = (url,flags,loader,data) => {
|
|||
xrf.XRWG.generate({model,scene:model.scene})
|
||||
// spec: 1. execute the default predefined view '#' (if exist) (https://xrfragment.org/#predefined_view)
|
||||
xrf.frag.defaultPredefinedView({model,scene:model.scene})
|
||||
// spec: 2. execute predefined view(s) from URL (https://xrfragment.org/#predefined_view)
|
||||
hashbus.pub( url, model ) // and eval URI XR fragments
|
||||
// spec: 2. init metadata
|
||||
let frag = hashbus.pub( url, model ) // and eval URI XR fragments
|
||||
// spec: predefined view(s) from URL (https://xrfragment.org/#predefined_view)
|
||||
setTimeout( () => { // give external objects some slack
|
||||
xrf.frag.updatePredefinedView({model,scene:model.scene,frag})
|
||||
},2000)
|
||||
xrf.add( model.scene )
|
||||
xrf.navigator.updateHash(hash)
|
||||
resolve(model)
|
||||
|
@ -1096,9 +1103,14 @@ xrf.navigator.to = (url,flags,loader,data) => {
|
|||
|
||||
xrf.navigator.init = () => {
|
||||
if( xrf.navigator.init.inited ) return
|
||||
|
||||
window.addEventListener('popstate', function (event){
|
||||
xrf.navigator.to( document.location.search.substr(1) + document.location.hash )
|
||||
})
|
||||
|
||||
window.addEventListener('hashchange', function (e){
|
||||
xrf.emit('hash', {hash: document.location.hash })
|
||||
})
|
||||
|
||||
// this allows selectionlines to be updated according to the camera (renderloop)
|
||||
xrf.focusLine = new xrf.THREE.Group()
|
||||
|
@ -1398,7 +1410,7 @@ xrf.frag.href = function(v, opts){
|
|||
vec4 color = texture2D(pano, sampleUV);
|
||||
// Convert color to grayscale (lazy lite approach to not having to match tonemapping/shaderstacking of THREE.js)
|
||||
float luminance = 0.2126 * color.r + 0.7152 * color.g + 0.0722 * color.b;
|
||||
vec4 grayscale_color = color; //selected ? color : vec4(vec3(luminance) + vec3(0.33), color.a);
|
||||
vec4 grayscale_color = selected ? color : vec4(vec3(luminance) + vec3(0.33), color.a);
|
||||
gl_FragColor = grayscale_color;
|
||||
}
|
||||
`,
|
||||
|
@ -1426,14 +1438,18 @@ xrf.frag.href = function(v, opts){
|
|||
|
||||
let selected = (state) => () => {
|
||||
if( mesh.selected == state ) return // nothing changed
|
||||
if( mesh.material ){
|
||||
if( mesh.material.uniforms ) mesh.material.uniforms.selected.value = state
|
||||
else mesh.material.color.r = mesh.material.color.g = mesh.material.color.b = state ? 2.0 : 1.0
|
||||
}
|
||||
xrf.interactive.objects.map( (o) => {
|
||||
let newState = o.name == mesh.name ? state : false
|
||||
if( o.material ){
|
||||
if( o.material.uniforms ) o.material.uniforms.selected.value = newState
|
||||
if( o.material.emissive ) o.material.emissive.r = o.material.emissive.g = o.material.emissive.b = newState ? 2.0 : 1.0
|
||||
}
|
||||
})
|
||||
// update mouse cursor
|
||||
if( !renderer.domElement.lastCursor )
|
||||
renderer.domElement.lastCursor = renderer.domElement.style.cursor
|
||||
renderer.domElement.style.cursor = state ? 'pointer' : renderer.domElement.lastCursor
|
||||
|
||||
xrf
|
||||
.emit('href',{selected:state,mesh,xrf:v}) // let all listeners agree
|
||||
.then( () => mesh.selected = state )
|
||||
|
@ -1481,7 +1497,7 @@ xrf.frag.defaultPredefinedView = (opts) => {
|
|||
}
|
||||
|
||||
xrf.frag.updatePredefinedView = (opts) => {
|
||||
let {frag,scene,model} = opts
|
||||
let {frag,scene,model,renderer} = opts
|
||||
|
||||
// spec: https://xrfragment.org/#Selection%20of%20interest
|
||||
const selectionOfInterest = (frag,scene,mesh) => {
|
||||
|
@ -1489,7 +1505,7 @@ xrf.frag.updatePredefinedView = (opts) => {
|
|||
let oldSelection
|
||||
if(!id) return id // important: ignore empty strings
|
||||
// Selection of Interest if predefined_view matches object name
|
||||
if( mesh.visible ){
|
||||
if( mesh.visible && mesh.material){
|
||||
xrf.emit('focus',{...opts,frag})
|
||||
.then( () => {
|
||||
const color = new THREE.Color();
|
||||
|
@ -1557,14 +1573,13 @@ xrf.frag.updatePredefinedView = (opts) => {
|
|||
remove.map( (n) => scene.remove(n.selection) )
|
||||
// create new selections
|
||||
match.map( (w) => {
|
||||
if( w.key == `#${id}` && w.value && w.value[0] == '#' ){
|
||||
// if value is alias, execute fragment value
|
||||
xrf.hashbus.pub( w.value, xrf.model, xrf.XRF.METADATA | xrf.XRF.PV_OVERRIDE | xrf.XRF.NAVIGATOR )
|
||||
if( w.key == `#${id}` ){
|
||||
if( w.value && w.value[0] == '#' ){
|
||||
// if value is alias, execute fragment value
|
||||
xrf.hashbus.pub( w.value, xrf.model, xrf.XRF.METADATA | xrf.XRF.PV_OVERRIDE | xrf.XRF.NAVIGATOR )
|
||||
}
|
||||
}
|
||||
w.nodes.map( (mesh) => {
|
||||
if( mesh.material )
|
||||
selectionOfInterest( v, scene, mesh )
|
||||
})
|
||||
w.nodes.map( (mesh) => selectionOfInterest( v, scene, mesh ) )
|
||||
})
|
||||
}
|
||||
|
||||
|
@ -1574,6 +1589,8 @@ xrf.frag.updatePredefinedView = (opts) => {
|
|||
console.log("filtering predefined view of src")
|
||||
console.dir(frag)
|
||||
}else{
|
||||
console.log("updatePredefinedView")
|
||||
console.dir(frag)
|
||||
for ( let i in frag ) {
|
||||
let v = frag[i]
|
||||
if( v.is( xrf.XRF.PV_EXECUTE ) ){
|
||||
|
@ -1588,7 +1605,6 @@ xrf.frag.updatePredefinedView = (opts) => {
|
|||
// react to enduser typing url
|
||||
xrf.addEventListener('hash', (opts) => {
|
||||
let frag = xrf.URI.parse( opts.hash, xrf.XRF.NAVIGATOR | xrf.XRF.PV_OVERRIDE | xrf.XRF.METADATA )
|
||||
console.dir({opts,frag})
|
||||
xrf.frag.updatePredefinedView({frag,scene:xrf.scene})
|
||||
})
|
||||
|
||||
|
@ -1627,10 +1643,8 @@ xrf.frag.q = function(v, opts){
|
|||
xrf.frag.q.filter = function(scene,frag){
|
||||
// spec: https://xrfragment.org/#queries
|
||||
let q = frag.q.query
|
||||
console.dir(q)
|
||||
scene.traverse( (mesh) => {
|
||||
for ( let i in q ) {
|
||||
if( i == '' ) continue
|
||||
let isMeshId = q[i].id != undefined
|
||||
let isMeshProperty = q[i].rules != undefined && q[i].rules.length && !isMeshId
|
||||
if( q[i].root && mesh.isSRC ) continue; // ignore nested object for root-items (queryseletor '/foo' e.g.)
|
||||
|
@ -1655,23 +1669,41 @@ xrf.frag.rot = function(v, opts){
|
|||
xrf.frag.src = function(v, opts){
|
||||
|
||||
opts.embedded = v // indicate embedded XR fragment
|
||||
let { mesh, model, camera, scene, renderer, THREE, hashbus} = opts
|
||||
let { mesh, model, camera, scene, renderer, THREE, hashbus, frag} = opts
|
||||
|
||||
console.log(" └ instancing src")
|
||||
let src;
|
||||
let url = v.string
|
||||
let frag = xrfragment.URI.parse(url)
|
||||
let vfrag = xrfragment.URI.parse(url)
|
||||
opts.isPlane = mesh.geometry && mesh.geometry.attributes.uv && mesh.geometry.attributes.uv.count == 4
|
||||
|
||||
const addScene = (scene,url,frag) => {
|
||||
src = xrf.frag.src.filterScene(scene,{...opts,frag})
|
||||
xrf.frag.src.scale( src, opts, url )
|
||||
xrf.frag.src.eval( src, opts, url )
|
||||
enableSourcePortation(src)
|
||||
mesh.add(src)
|
||||
mesh.traverse( (n) => n.isSRC = n.isXRF = true )
|
||||
if( mesh.material ) mesh.material.visible = false
|
||||
}
|
||||
|
||||
const enableSourcePortation = (src) => {
|
||||
if( vfrag.href || v.string[0] == '#' ) return
|
||||
let scale = new THREE.Vector3()
|
||||
let size = new THREE.Vector3()
|
||||
mesh.getWorldScale(scale)
|
||||
new THREE.Box3().setFromObject(src).getSize(size)
|
||||
const geo = new THREE.SphereGeometry( Math.max(size.x, size.y, size.z) / scale.x, 10, 10 )
|
||||
const mat = new THREE.MeshBasicMaterial()
|
||||
mat.transparent = true
|
||||
mat.roughness = 0.05
|
||||
mat.metalness = 1
|
||||
mat.opacity = 0
|
||||
const cube = new THREE.Mesh( geo, mat )
|
||||
console.log("todo: sourceportate")
|
||||
//mesh.add(cube)
|
||||
}
|
||||
|
||||
const externalSRC = (url,frag,src) => {
|
||||
fetch(url, { method: 'HEAD' })
|
||||
.then( (res) => {
|
||||
|
@ -1690,8 +1722,8 @@ xrf.frag.src = function(v, opts){
|
|||
.catch( console.error )
|
||||
}
|
||||
|
||||
if( url[0] == "#" ) addScene(scene,url,frag) // current file
|
||||
else externalSRC(url,frag) // external file
|
||||
if( url[0] == "#" ) addScene(scene,url,vfrag) // current file
|
||||
else externalSRC(url,vfrag) // external file
|
||||
}
|
||||
|
||||
xrf.frag.src.eval = function(scene, opts, url){
|
||||
|
@ -1916,9 +1948,9 @@ window.AFRAME.registerComponent('xrf', {
|
|||
let aScene = document.querySelector('a-scene')
|
||||
let XRF = AFRAME.XRF = xrf.init({
|
||||
THREE,
|
||||
camera: aScene.camera,
|
||||
scene: aScene.object3D,
|
||||
renderer: aScene.renderer,
|
||||
camera: aScene.camera,
|
||||
scene: aScene.object3D,
|
||||
renderer: aScene.renderer,
|
||||
debug: true,
|
||||
loaders: {
|
||||
gltf: THREE.GLTFLoader, // which 3D assets (exts) to check for XR fragments?
|
||||
|
|
|
@ -788,6 +788,7 @@ pub.mesh = (mesh,model) => { // evaluate embedded fragments (metadata) insid
|
|||
|
||||
pub.fragment = (k, opts ) => { // evaluate one fragment
|
||||
let frag = opts.frag[k];
|
||||
|
||||
// call native function (xrf/env.js e.g.), or pass it to user decorator
|
||||
xrf.emit(k,opts)
|
||||
.then( () => {
|
||||
|
@ -852,6 +853,7 @@ xrf.parseModel = function(model,url){
|
|||
model.mixer = new xrf.THREE.AnimationMixer(model.scene)
|
||||
model.animations.map( (anim) => {
|
||||
anim.action = model.mixer.clipAction( anim )
|
||||
//anim.action.setLoop(0)
|
||||
anim.action.play()
|
||||
})
|
||||
|
||||
|
@ -865,9 +867,10 @@ xrf.parseModel = function(model,url){
|
|||
xrf.focusLine.material.dashSize = 0.2 + 0.02*Math.sin( model.clock.getElapsedTime() )
|
||||
xrf.focusLine.material.gapSize = 0.1 + 0.02*Math.sin( model.clock.getElapsedTime() *3 )
|
||||
xrf.focusLine.material.opacity = (0.25 + 0.15*Math.sin( model.clock.getElapsedTime() * 3 )) * xrf.focusLine.opacity;
|
||||
if( xrf.focusLine.opacity > 0.0 ) xrf.focusLine.opacity -= time*0.3
|
||||
if( xrf.focusLine.opacity > 0.0 ) xrf.focusLine.opacity -= time*0.2
|
||||
if( xrf.focusLine.opacity < 0.0 ) xrf.focusLine.opacity = 0
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
xrf.getLastModel = () => xrf.model.last
|
||||
|
@ -940,7 +943,7 @@ xrf.InteractiveGroup = function(THREE,renderer,camera){
|
|||
function nocollide(){
|
||||
if( nocollide.tid ) return // ratelimit
|
||||
_event.type = "nocollide"
|
||||
scope.children.map( (c) => c.dispatchEvent(_event) )
|
||||
scope.objects.map( (c) => c.dispatchEvent(_event) )
|
||||
nocollide.tid = setTimeout( () => nocollide.tid = null, 100 )
|
||||
}
|
||||
|
||||
|
@ -1082,8 +1085,12 @@ xrf.navigator.to = (url,flags,loader,data) => {
|
|||
xrf.XRWG.generate({model,scene:model.scene})
|
||||
// spec: 1. execute the default predefined view '#' (if exist) (https://xrfragment.org/#predefined_view)
|
||||
xrf.frag.defaultPredefinedView({model,scene:model.scene})
|
||||
// spec: 2. execute predefined view(s) from URL (https://xrfragment.org/#predefined_view)
|
||||
hashbus.pub( url, model ) // and eval URI XR fragments
|
||||
// spec: 2. init metadata
|
||||
let frag = hashbus.pub( url, model ) // and eval URI XR fragments
|
||||
// spec: predefined view(s) from URL (https://xrfragment.org/#predefined_view)
|
||||
setTimeout( () => { // give external objects some slack
|
||||
xrf.frag.updatePredefinedView({model,scene:model.scene,frag})
|
||||
},2000)
|
||||
xrf.add( model.scene )
|
||||
xrf.navigator.updateHash(hash)
|
||||
resolve(model)
|
||||
|
@ -1096,9 +1103,14 @@ xrf.navigator.to = (url,flags,loader,data) => {
|
|||
|
||||
xrf.navigator.init = () => {
|
||||
if( xrf.navigator.init.inited ) return
|
||||
|
||||
window.addEventListener('popstate', function (event){
|
||||
xrf.navigator.to( document.location.search.substr(1) + document.location.hash )
|
||||
})
|
||||
|
||||
window.addEventListener('hashchange', function (e){
|
||||
xrf.emit('hash', {hash: document.location.hash })
|
||||
})
|
||||
|
||||
// this allows selectionlines to be updated according to the camera (renderloop)
|
||||
xrf.focusLine = new xrf.THREE.Group()
|
||||
|
@ -1398,7 +1410,7 @@ xrf.frag.href = function(v, opts){
|
|||
vec4 color = texture2D(pano, sampleUV);
|
||||
// Convert color to grayscale (lazy lite approach to not having to match tonemapping/shaderstacking of THREE.js)
|
||||
float luminance = 0.2126 * color.r + 0.7152 * color.g + 0.0722 * color.b;
|
||||
vec4 grayscale_color = color; //selected ? color : vec4(vec3(luminance) + vec3(0.33), color.a);
|
||||
vec4 grayscale_color = selected ? color : vec4(vec3(luminance) + vec3(0.33), color.a);
|
||||
gl_FragColor = grayscale_color;
|
||||
}
|
||||
`,
|
||||
|
@ -1426,14 +1438,18 @@ xrf.frag.href = function(v, opts){
|
|||
|
||||
let selected = (state) => () => {
|
||||
if( mesh.selected == state ) return // nothing changed
|
||||
if( mesh.material ){
|
||||
if( mesh.material.uniforms ) mesh.material.uniforms.selected.value = state
|
||||
else mesh.material.color.r = mesh.material.color.g = mesh.material.color.b = state ? 2.0 : 1.0
|
||||
}
|
||||
xrf.interactive.objects.map( (o) => {
|
||||
let newState = o.name == mesh.name ? state : false
|
||||
if( o.material ){
|
||||
if( o.material.uniforms ) o.material.uniforms.selected.value = newState
|
||||
if( o.material.emissive ) o.material.emissive.r = o.material.emissive.g = o.material.emissive.b = newState ? 2.0 : 1.0
|
||||
}
|
||||
})
|
||||
// update mouse cursor
|
||||
if( !renderer.domElement.lastCursor )
|
||||
renderer.domElement.lastCursor = renderer.domElement.style.cursor
|
||||
renderer.domElement.style.cursor = state ? 'pointer' : renderer.domElement.lastCursor
|
||||
|
||||
xrf
|
||||
.emit('href',{selected:state,mesh,xrf:v}) // let all listeners agree
|
||||
.then( () => mesh.selected = state )
|
||||
|
@ -1481,7 +1497,7 @@ xrf.frag.defaultPredefinedView = (opts) => {
|
|||
}
|
||||
|
||||
xrf.frag.updatePredefinedView = (opts) => {
|
||||
let {frag,scene,model} = opts
|
||||
let {frag,scene,model,renderer} = opts
|
||||
|
||||
// spec: https://xrfragment.org/#Selection%20of%20interest
|
||||
const selectionOfInterest = (frag,scene,mesh) => {
|
||||
|
@ -1489,7 +1505,7 @@ xrf.frag.updatePredefinedView = (opts) => {
|
|||
let oldSelection
|
||||
if(!id) return id // important: ignore empty strings
|
||||
// Selection of Interest if predefined_view matches object name
|
||||
if( mesh.visible ){
|
||||
if( mesh.visible && mesh.material){
|
||||
xrf.emit('focus',{...opts,frag})
|
||||
.then( () => {
|
||||
const color = new THREE.Color();
|
||||
|
@ -1557,14 +1573,13 @@ xrf.frag.updatePredefinedView = (opts) => {
|
|||
remove.map( (n) => scene.remove(n.selection) )
|
||||
// create new selections
|
||||
match.map( (w) => {
|
||||
if( w.key == `#${id}` && w.value && w.value[0] == '#' ){
|
||||
// if value is alias, execute fragment value
|
||||
xrf.hashbus.pub( w.value, xrf.model, xrf.XRF.METADATA | xrf.XRF.PV_OVERRIDE | xrf.XRF.NAVIGATOR )
|
||||
if( w.key == `#${id}` ){
|
||||
if( w.value && w.value[0] == '#' ){
|
||||
// if value is alias, execute fragment value
|
||||
xrf.hashbus.pub( w.value, xrf.model, xrf.XRF.METADATA | xrf.XRF.PV_OVERRIDE | xrf.XRF.NAVIGATOR )
|
||||
}
|
||||
}
|
||||
w.nodes.map( (mesh) => {
|
||||
if( mesh.material )
|
||||
selectionOfInterest( v, scene, mesh )
|
||||
})
|
||||
w.nodes.map( (mesh) => selectionOfInterest( v, scene, mesh ) )
|
||||
})
|
||||
}
|
||||
|
||||
|
@ -1574,6 +1589,8 @@ xrf.frag.updatePredefinedView = (opts) => {
|
|||
console.log("filtering predefined view of src")
|
||||
console.dir(frag)
|
||||
}else{
|
||||
console.log("updatePredefinedView")
|
||||
console.dir(frag)
|
||||
for ( let i in frag ) {
|
||||
let v = frag[i]
|
||||
if( v.is( xrf.XRF.PV_EXECUTE ) ){
|
||||
|
@ -1588,7 +1605,6 @@ xrf.frag.updatePredefinedView = (opts) => {
|
|||
// react to enduser typing url
|
||||
xrf.addEventListener('hash', (opts) => {
|
||||
let frag = xrf.URI.parse( opts.hash, xrf.XRF.NAVIGATOR | xrf.XRF.PV_OVERRIDE | xrf.XRF.METADATA )
|
||||
console.dir({opts,frag})
|
||||
xrf.frag.updatePredefinedView({frag,scene:xrf.scene})
|
||||
})
|
||||
|
||||
|
@ -1627,10 +1643,8 @@ xrf.frag.q = function(v, opts){
|
|||
xrf.frag.q.filter = function(scene,frag){
|
||||
// spec: https://xrfragment.org/#queries
|
||||
let q = frag.q.query
|
||||
console.dir(q)
|
||||
scene.traverse( (mesh) => {
|
||||
for ( let i in q ) {
|
||||
if( i == '' ) continue
|
||||
let isMeshId = q[i].id != undefined
|
||||
let isMeshProperty = q[i].rules != undefined && q[i].rules.length && !isMeshId
|
||||
if( q[i].root && mesh.isSRC ) continue; // ignore nested object for root-items (queryseletor '/foo' e.g.)
|
||||
|
@ -1655,23 +1669,41 @@ xrf.frag.rot = function(v, opts){
|
|||
xrf.frag.src = function(v, opts){
|
||||
|
||||
opts.embedded = v // indicate embedded XR fragment
|
||||
let { mesh, model, camera, scene, renderer, THREE, hashbus} = opts
|
||||
let { mesh, model, camera, scene, renderer, THREE, hashbus, frag} = opts
|
||||
|
||||
console.log(" └ instancing src")
|
||||
let src;
|
||||
let url = v.string
|
||||
let frag = xrfragment.URI.parse(url)
|
||||
let vfrag = xrfragment.URI.parse(url)
|
||||
opts.isPlane = mesh.geometry && mesh.geometry.attributes.uv && mesh.geometry.attributes.uv.count == 4
|
||||
|
||||
const addScene = (scene,url,frag) => {
|
||||
src = xrf.frag.src.filterScene(scene,{...opts,frag})
|
||||
xrf.frag.src.scale( src, opts, url )
|
||||
xrf.frag.src.eval( src, opts, url )
|
||||
enableSourcePortation(src)
|
||||
mesh.add(src)
|
||||
mesh.traverse( (n) => n.isSRC = n.isXRF = true )
|
||||
if( mesh.material ) mesh.material.visible = false
|
||||
}
|
||||
|
||||
const enableSourcePortation = (src) => {
|
||||
if( vfrag.href || v.string[0] == '#' ) return
|
||||
let scale = new THREE.Vector3()
|
||||
let size = new THREE.Vector3()
|
||||
mesh.getWorldScale(scale)
|
||||
new THREE.Box3().setFromObject(src).getSize(size)
|
||||
const geo = new THREE.SphereGeometry( Math.max(size.x, size.y, size.z) / scale.x, 10, 10 )
|
||||
const mat = new THREE.MeshBasicMaterial()
|
||||
mat.transparent = true
|
||||
mat.roughness = 0.05
|
||||
mat.metalness = 1
|
||||
mat.opacity = 0
|
||||
const cube = new THREE.Mesh( geo, mat )
|
||||
console.log("todo: sourceportate")
|
||||
//mesh.add(cube)
|
||||
}
|
||||
|
||||
const externalSRC = (url,frag,src) => {
|
||||
fetch(url, { method: 'HEAD' })
|
||||
.then( (res) => {
|
||||
|
@ -1690,8 +1722,8 @@ xrf.frag.src = function(v, opts){
|
|||
.catch( console.error )
|
||||
}
|
||||
|
||||
if( url[0] == "#" ) addScene(scene,url,frag) // current file
|
||||
else externalSRC(url,frag) // external file
|
||||
if( url[0] == "#" ) addScene(scene,url,vfrag) // current file
|
||||
else externalSRC(url,vfrag) // external file
|
||||
}
|
||||
|
||||
xrf.frag.src.eval = function(scene, opts, url){
|
||||
|
|
|
@ -788,6 +788,7 @@ pub.mesh = (mesh,model) => { // evaluate embedded fragments (metadata) insid
|
|||
|
||||
pub.fragment = (k, opts ) => { // evaluate one fragment
|
||||
let frag = opts.frag[k];
|
||||
|
||||
// call native function (xrf/env.js e.g.), or pass it to user decorator
|
||||
xrf.emit(k,opts)
|
||||
.then( () => {
|
||||
|
@ -852,6 +853,7 @@ xrf.parseModel = function(model,url){
|
|||
model.mixer = new xrf.THREE.AnimationMixer(model.scene)
|
||||
model.animations.map( (anim) => {
|
||||
anim.action = model.mixer.clipAction( anim )
|
||||
//anim.action.setLoop(0)
|
||||
anim.action.play()
|
||||
})
|
||||
|
||||
|
@ -865,9 +867,10 @@ xrf.parseModel = function(model,url){
|
|||
xrf.focusLine.material.dashSize = 0.2 + 0.02*Math.sin( model.clock.getElapsedTime() )
|
||||
xrf.focusLine.material.gapSize = 0.1 + 0.02*Math.sin( model.clock.getElapsedTime() *3 )
|
||||
xrf.focusLine.material.opacity = (0.25 + 0.15*Math.sin( model.clock.getElapsedTime() * 3 )) * xrf.focusLine.opacity;
|
||||
if( xrf.focusLine.opacity > 0.0 ) xrf.focusLine.opacity -= time*0.3
|
||||
if( xrf.focusLine.opacity > 0.0 ) xrf.focusLine.opacity -= time*0.2
|
||||
if( xrf.focusLine.opacity < 0.0 ) xrf.focusLine.opacity = 0
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
xrf.getLastModel = () => xrf.model.last
|
||||
|
@ -940,7 +943,7 @@ xrf.InteractiveGroup = function(THREE,renderer,camera){
|
|||
function nocollide(){
|
||||
if( nocollide.tid ) return // ratelimit
|
||||
_event.type = "nocollide"
|
||||
scope.children.map( (c) => c.dispatchEvent(_event) )
|
||||
scope.objects.map( (c) => c.dispatchEvent(_event) )
|
||||
nocollide.tid = setTimeout( () => nocollide.tid = null, 100 )
|
||||
}
|
||||
|
||||
|
@ -1082,8 +1085,12 @@ xrf.navigator.to = (url,flags,loader,data) => {
|
|||
xrf.XRWG.generate({model,scene:model.scene})
|
||||
// spec: 1. execute the default predefined view '#' (if exist) (https://xrfragment.org/#predefined_view)
|
||||
xrf.frag.defaultPredefinedView({model,scene:model.scene})
|
||||
// spec: 2. execute predefined view(s) from URL (https://xrfragment.org/#predefined_view)
|
||||
hashbus.pub( url, model ) // and eval URI XR fragments
|
||||
// spec: 2. init metadata
|
||||
let frag = hashbus.pub( url, model ) // and eval URI XR fragments
|
||||
// spec: predefined view(s) from URL (https://xrfragment.org/#predefined_view)
|
||||
setTimeout( () => { // give external objects some slack
|
||||
xrf.frag.updatePredefinedView({model,scene:model.scene,frag})
|
||||
},2000)
|
||||
xrf.add( model.scene )
|
||||
xrf.navigator.updateHash(hash)
|
||||
resolve(model)
|
||||
|
@ -1096,9 +1103,14 @@ xrf.navigator.to = (url,flags,loader,data) => {
|
|||
|
||||
xrf.navigator.init = () => {
|
||||
if( xrf.navigator.init.inited ) return
|
||||
|
||||
window.addEventListener('popstate', function (event){
|
||||
xrf.navigator.to( document.location.search.substr(1) + document.location.hash )
|
||||
})
|
||||
|
||||
window.addEventListener('hashchange', function (e){
|
||||
xrf.emit('hash', {hash: document.location.hash })
|
||||
})
|
||||
|
||||
// this allows selectionlines to be updated according to the camera (renderloop)
|
||||
xrf.focusLine = new xrf.THREE.Group()
|
||||
|
@ -1398,7 +1410,7 @@ xrf.frag.href = function(v, opts){
|
|||
vec4 color = texture2D(pano, sampleUV);
|
||||
// Convert color to grayscale (lazy lite approach to not having to match tonemapping/shaderstacking of THREE.js)
|
||||
float luminance = 0.2126 * color.r + 0.7152 * color.g + 0.0722 * color.b;
|
||||
vec4 grayscale_color = color; //selected ? color : vec4(vec3(luminance) + vec3(0.33), color.a);
|
||||
vec4 grayscale_color = selected ? color : vec4(vec3(luminance) + vec3(0.33), color.a);
|
||||
gl_FragColor = grayscale_color;
|
||||
}
|
||||
`,
|
||||
|
@ -1426,14 +1438,18 @@ xrf.frag.href = function(v, opts){
|
|||
|
||||
let selected = (state) => () => {
|
||||
if( mesh.selected == state ) return // nothing changed
|
||||
if( mesh.material ){
|
||||
if( mesh.material.uniforms ) mesh.material.uniforms.selected.value = state
|
||||
else mesh.material.color.r = mesh.material.color.g = mesh.material.color.b = state ? 2.0 : 1.0
|
||||
}
|
||||
xrf.interactive.objects.map( (o) => {
|
||||
let newState = o.name == mesh.name ? state : false
|
||||
if( o.material ){
|
||||
if( o.material.uniforms ) o.material.uniforms.selected.value = newState
|
||||
if( o.material.emissive ) o.material.emissive.r = o.material.emissive.g = o.material.emissive.b = newState ? 2.0 : 1.0
|
||||
}
|
||||
})
|
||||
// update mouse cursor
|
||||
if( !renderer.domElement.lastCursor )
|
||||
renderer.domElement.lastCursor = renderer.domElement.style.cursor
|
||||
renderer.domElement.style.cursor = state ? 'pointer' : renderer.domElement.lastCursor
|
||||
|
||||
xrf
|
||||
.emit('href',{selected:state,mesh,xrf:v}) // let all listeners agree
|
||||
.then( () => mesh.selected = state )
|
||||
|
@ -1481,7 +1497,7 @@ xrf.frag.defaultPredefinedView = (opts) => {
|
|||
}
|
||||
|
||||
xrf.frag.updatePredefinedView = (opts) => {
|
||||
let {frag,scene,model} = opts
|
||||
let {frag,scene,model,renderer} = opts
|
||||
|
||||
// spec: https://xrfragment.org/#Selection%20of%20interest
|
||||
const selectionOfInterest = (frag,scene,mesh) => {
|
||||
|
@ -1489,7 +1505,7 @@ xrf.frag.updatePredefinedView = (opts) => {
|
|||
let oldSelection
|
||||
if(!id) return id // important: ignore empty strings
|
||||
// Selection of Interest if predefined_view matches object name
|
||||
if( mesh.visible ){
|
||||
if( mesh.visible && mesh.material){
|
||||
xrf.emit('focus',{...opts,frag})
|
||||
.then( () => {
|
||||
const color = new THREE.Color();
|
||||
|
@ -1557,14 +1573,13 @@ xrf.frag.updatePredefinedView = (opts) => {
|
|||
remove.map( (n) => scene.remove(n.selection) )
|
||||
// create new selections
|
||||
match.map( (w) => {
|
||||
if( w.key == `#${id}` && w.value && w.value[0] == '#' ){
|
||||
// if value is alias, execute fragment value
|
||||
xrf.hashbus.pub( w.value, xrf.model, xrf.XRF.METADATA | xrf.XRF.PV_OVERRIDE | xrf.XRF.NAVIGATOR )
|
||||
if( w.key == `#${id}` ){
|
||||
if( w.value && w.value[0] == '#' ){
|
||||
// if value is alias, execute fragment value
|
||||
xrf.hashbus.pub( w.value, xrf.model, xrf.XRF.METADATA | xrf.XRF.PV_OVERRIDE | xrf.XRF.NAVIGATOR )
|
||||
}
|
||||
}
|
||||
w.nodes.map( (mesh) => {
|
||||
if( mesh.material )
|
||||
selectionOfInterest( v, scene, mesh )
|
||||
})
|
||||
w.nodes.map( (mesh) => selectionOfInterest( v, scene, mesh ) )
|
||||
})
|
||||
}
|
||||
|
||||
|
@ -1574,6 +1589,8 @@ xrf.frag.updatePredefinedView = (opts) => {
|
|||
console.log("filtering predefined view of src")
|
||||
console.dir(frag)
|
||||
}else{
|
||||
console.log("updatePredefinedView")
|
||||
console.dir(frag)
|
||||
for ( let i in frag ) {
|
||||
let v = frag[i]
|
||||
if( v.is( xrf.XRF.PV_EXECUTE ) ){
|
||||
|
@ -1588,7 +1605,6 @@ xrf.frag.updatePredefinedView = (opts) => {
|
|||
// react to enduser typing url
|
||||
xrf.addEventListener('hash', (opts) => {
|
||||
let frag = xrf.URI.parse( opts.hash, xrf.XRF.NAVIGATOR | xrf.XRF.PV_OVERRIDE | xrf.XRF.METADATA )
|
||||
console.dir({opts,frag})
|
||||
xrf.frag.updatePredefinedView({frag,scene:xrf.scene})
|
||||
})
|
||||
|
||||
|
@ -1627,10 +1643,8 @@ xrf.frag.q = function(v, opts){
|
|||
xrf.frag.q.filter = function(scene,frag){
|
||||
// spec: https://xrfragment.org/#queries
|
||||
let q = frag.q.query
|
||||
console.dir(q)
|
||||
scene.traverse( (mesh) => {
|
||||
for ( let i in q ) {
|
||||
if( i == '' ) continue
|
||||
let isMeshId = q[i].id != undefined
|
||||
let isMeshProperty = q[i].rules != undefined && q[i].rules.length && !isMeshId
|
||||
if( q[i].root && mesh.isSRC ) continue; // ignore nested object for root-items (queryseletor '/foo' e.g.)
|
||||
|
@ -1655,23 +1669,41 @@ xrf.frag.rot = function(v, opts){
|
|||
xrf.frag.src = function(v, opts){
|
||||
|
||||
opts.embedded = v // indicate embedded XR fragment
|
||||
let { mesh, model, camera, scene, renderer, THREE, hashbus} = opts
|
||||
let { mesh, model, camera, scene, renderer, THREE, hashbus, frag} = opts
|
||||
|
||||
console.log(" └ instancing src")
|
||||
let src;
|
||||
let url = v.string
|
||||
let frag = xrfragment.URI.parse(url)
|
||||
let vfrag = xrfragment.URI.parse(url)
|
||||
opts.isPlane = mesh.geometry && mesh.geometry.attributes.uv && mesh.geometry.attributes.uv.count == 4
|
||||
|
||||
const addScene = (scene,url,frag) => {
|
||||
src = xrf.frag.src.filterScene(scene,{...opts,frag})
|
||||
xrf.frag.src.scale( src, opts, url )
|
||||
xrf.frag.src.eval( src, opts, url )
|
||||
enableSourcePortation(src)
|
||||
mesh.add(src)
|
||||
mesh.traverse( (n) => n.isSRC = n.isXRF = true )
|
||||
if( mesh.material ) mesh.material.visible = false
|
||||
}
|
||||
|
||||
const enableSourcePortation = (src) => {
|
||||
if( vfrag.href || v.string[0] == '#' ) return
|
||||
let scale = new THREE.Vector3()
|
||||
let size = new THREE.Vector3()
|
||||
mesh.getWorldScale(scale)
|
||||
new THREE.Box3().setFromObject(src).getSize(size)
|
||||
const geo = new THREE.SphereGeometry( Math.max(size.x, size.y, size.z) / scale.x, 10, 10 )
|
||||
const mat = new THREE.MeshBasicMaterial()
|
||||
mat.transparent = true
|
||||
mat.roughness = 0.05
|
||||
mat.metalness = 1
|
||||
mat.opacity = 0
|
||||
const cube = new THREE.Mesh( geo, mat )
|
||||
console.log("todo: sourceportate")
|
||||
//mesh.add(cube)
|
||||
}
|
||||
|
||||
const externalSRC = (url,frag,src) => {
|
||||
fetch(url, { method: 'HEAD' })
|
||||
.then( (res) => {
|
||||
|
@ -1690,8 +1722,8 @@ xrf.frag.src = function(v, opts){
|
|||
.catch( console.error )
|
||||
}
|
||||
|
||||
if( url[0] == "#" ) addScene(scene,url,frag) // current file
|
||||
else externalSRC(url,frag) // external file
|
||||
if( url[0] == "#" ) addScene(scene,url,vfrag) // current file
|
||||
else externalSRC(url,vfrag) // external file
|
||||
}
|
||||
|
||||
xrf.frag.src.eval = function(scene, opts, url){
|
||||
|
|
|
@ -80,7 +80,7 @@ value: draft-XRFRAGMENTS-leonvankammen-00
|
|||
|
||||
<h1 class="special" id="abstract">Abstract</h1>
|
||||
|
||||
<p>This draft is a specification for 4D URLs & navigation, which links together space, time & text together, for hypermedia browsers with- or without a network-connection.<br>
|
||||
<p>This draft is a specification for 4D URLs & <a href="https://github.com/coderofsalvation/hypermediatic">hypermediatic</a> navigation, which links together space, time & text together, for hypermedia browsers with- or without a network-connection.<br>
|
||||
The specification promotes spatial addressibility, sharing, navigation, query-ing and annotating interactive (text)objects across for (XR) Browsers.<br>
|
||||
XR Fragments allows us to enrich existing dataformats, by recursive use of existing proven technologies like <a href="https://en.wikipedia.org/wiki/URI_fragment">URI Fragments</a> and BibTags notation.<br></p>
|
||||
|
||||
|
@ -92,11 +92,11 @@ XR Fragments allows us to enrich existing dataformats, by recursive use of exist
|
|||
|
||||
<p>How can we add more features to existing text & 3D scenes, without introducing new dataformats?<br>
|
||||
Historically, there’s many attempts to create the ultimate markuplanguage or 3D fileformat.<br>
|
||||
Their lowest common denominator is: (co)authoring using plain text.<br>
|
||||
The lowest common denominator is: describing/tagging/naming nodes using <strong>plain text</strong>.<br>
|
||||
XR Fragments allows us to enrich/connect existing dataformats, by introducing existing technologies/ideas:<br></p>
|
||||
|
||||
<ol>
|
||||
<li>addressibility and navigation of 3D scenes/objects: <a href="https://en.wikipedia.org/wiki/URI_fragment">URI Fragments</a> + src/href spatial metadata</li>
|
||||
<li>addressibility and <a href="https://github.com/coderofsalvation/hypermediatic">hypermediatic</a> navigation of 3D scenes/objects: <a href="https://en.wikipedia.org/wiki/URI_fragment">URI Fragments</a> + src/href spatial metadata</li>
|
||||
<li>Interlinking text/& 3D by collapsing space into a Word Graph (XRWG) to show <a href="#visible-links">visible links</a> (and augmenting text with <a href="https://github.com/coderofsalvation/tagbibs">bibs</a> / <a href="https://en.wikipedia.org/wiki/BibTeX">BibTags</a> appendices (see <a href="https://visual-meta.info">visual-meta</a> e.g.)</li>
|
||||
<li>unlocking spatial potential of the (originally 2D) hashtag (which jumps to a chapter) for navigating XR documents</li>
|
||||
</ol>
|
||||
|
@ -199,12 +199,12 @@ Instead of combining them (in a game-editor e.g.), XR Fragments is opting for a
|
|||
<p>Traditional webbrowsers can become 4D document-ready by:</p>
|
||||
|
||||
<ul>
|
||||
<li>loading 3D assets (gltf/fbx e.g.) natively (with or without using HTML).</li>
|
||||
<li><a href="https://github.com/coderofsalvation/hypermediatic">hypermediatic</a> loading 3D assets (gltf/fbx e.g.) natively (with or without using HTML).</li>
|
||||
<li>allowing assets to publish hashtags to themselves (the scene) using the hashbus (like hashtags controlling the scrollbar).</li>
|
||||
<li>collapsing the 3D scene to an wordgraph (for essential navigation purposes) controllable thru a hash(tag)bus</li>
|
||||
</ul>
|
||||
|
||||
<p>XR Fragments itself are HTML-agnostic, though pseudo-XR Fragment browsers <strong>can</strong> be implemented on top of HTML/Javascript.</p>
|
||||
<p>XR Fragments itself are <a href="https://github.com/coderofsalvation/hypermediatic">hypermediatic</a> and HTML-agnostic, though pseudo-XR Fragment browsers <strong>can</strong> be implemented on top of HTML/Javascript.</p>
|
||||
|
||||
<h1 id="conventions-and-definitions">Conventions and Definitions</h1>
|
||||
|
||||
|
@ -275,9 +275,9 @@ sub-delims = "," / "="
|
|||
|
||||
<tr>
|
||||
<td><code>#t</code></td>
|
||||
<td>vector2</td>
|
||||
<td><code>#t=500,1000</code></td>
|
||||
<td>sets animation-loop range between frame 500 and 1000</td>
|
||||
<td>vector3</td>
|
||||
<td><code>#t=1,500,1000</code></td>
|
||||
<td>play animation-loop range between frame 500 and 1000, at normal speed</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
|
@ -307,22 +307,6 @@ sub-delims = "," / "="
|
|||
</thead>
|
||||
|
||||
<tbody>
|
||||
<tr>
|
||||
<td><code>name</code></td>
|
||||
<td>string</td>
|
||||
<td><code>"name": "cube"</code></td>
|
||||
<td>identify/tag</td>
|
||||
<td>object supported in all 3D fileformats & scenes</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td><code>tag</code></td>
|
||||
<td>string</td>
|
||||
<td><code>"tag": "cubes geo"</code></td>
|
||||
<td>tag object</td>
|
||||
<td>custom property in 3D fileformats</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td><code>href</code></td>
|
||||
<td>string</td>
|
||||
|
@ -338,16 +322,26 @@ sub-delims = "," / "="
|
|||
<td>XR embed / teleport</td>
|
||||
<td>custom property in 3D fileformats</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td><code>tag</code></td>
|
||||
<td>string</td>
|
||||
<td><code>"tag": "cubes geo"</code></td>
|
||||
<td>tag object (for query-use / XRWG highlighting)</td>
|
||||
<td>custom property in 3D fileformats</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<p>Supported popular compatible 3D fileformats: <code>.gltf</code>, <code>.obj</code>, <code>.fbx</code>, <code>.usdz</code>, <code>.json</code> (THREE.js), <code>.dae</code> and so on.</p>
|
||||
|
||||
<blockquote>
|
||||
<p>NOTE: XR Fragments are file-agnostic, which means that the metadata exist in programmatic 3D scene(nodes) too.</p>
|
||||
<p>NOTE: XR Fragments are optional but also file- and protocol-agnostic, which means that programmatic 3D scene(nodes) can also use the mechanism/metadata.</p>
|
||||
</blockquote>
|
||||
|
||||
<h1 id="spatial-referencing-3d">Spatial Referencing 3D</h1>
|
||||
|
||||
<p>XR Fragments assume the following objectname-to-URIFragment mapping:</p>
|
||||
|
||||
<pre><code>
|
||||
my.io/scene.fbx
|
||||
+─────────────────────────────+
|
||||
|
@ -366,6 +360,10 @@ sub-delims = "," / "="
|
|||
|
||||
</code></pre>
|
||||
|
||||
<blockquote>
|
||||
<p>Every 3D fileformat supports named 3D object, and this name allows URLs (fragments) to reference them (and their children objects).</p>
|
||||
</blockquote>
|
||||
|
||||
<p>Clever nested design of 3D scenes allow great ways for re-using content, and/or previewing scenes.<br>
|
||||
For example, to render a portal with a preview-version of the scene, create an 3D object with:</p>
|
||||
|
||||
|
@ -375,7 +373,7 @@ For example, to render a portal with a preview-version of the scene, create an 3
|
|||
</ul>
|
||||
|
||||
<blockquote>
|
||||
<p>It also allows <strong>sourceportation</strong>, which basically means the enduser can teleport to the original XR Document of an <code>src</code> embedded object, and see a visible connection to the particular embedded object.</p>
|
||||
<p>It also allows <strong>sourceportation</strong>, which basically means the enduser can teleport to the original XR Document of an <code>src</code> embedded object, and see a visible connection to the particular embedded object. Basically an embedded link becoming an outbound link by activating it.</p>
|
||||
</blockquote>
|
||||
|
||||
<h1 id="navigating-3d">Navigating 3D</h1>
|
||||
|
@ -398,8 +396,8 @@ For example, to render a portal with a preview-version of the scene, create an 3
|
|||
|
||||
<tr>
|
||||
<td><b>#t</b>=0,100</td>
|
||||
<td>vector2</td>
|
||||
<td>(re)position looprange of scene-animation or <code>src</code>-mediacontent</td>
|
||||
<td>vector3</td>
|
||||
<td>set playback speed, and (re)position looprange of scene-animation or <code>src</code>-mediacontent</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
|
@ -416,7 +414,7 @@ For example, to render a portal with a preview-version of the scene, create an 3
|
|||
<li>the Y-coordinate of <code>pos</code> identifies the floorposition. This means that desktop-projections usually need to add 1.5m (average person height) on top (which is done automatically by VR/AR headsets).</li>
|
||||
<li>set the position of the camera accordingly to the vector3 values of <code>#pos</code></li>
|
||||
<li><code>rot</code> sets the rotation of the camera (only for non-VR/AR headsets)</li>
|
||||
<li><code>t</code> sets the animation-range of the current scene animation(s) or <code>src</code>-mediacontent (video/audioframes e.g., use <code>t=7,7</code> to ‘STOP’ at certain frame)</li>
|
||||
<li><code>t</code> sets the playbackspeed and animation-range of the current scene animation(s) or <code>src</code>-mediacontent (video/audioframes e.g., use <code>t=0,7,7</code> to ‘STOP’ at frame 7 e.g.)</li>
|
||||
<li>in case an <code>href</code> does not mention any <code>pos</code>-coordinate, <code>pos=0,0,0</code> will be assumed</li>
|
||||
</ol>
|
||||
|
||||
|
@ -533,7 +531,7 @@ Resizing will be happen accordingly to its placeholder object <code>aquariumcube
|
|||
<a href="https://github.com/coderofsalvation/xrfragment/blob/main/example/assets/src.gltf#L192">» example 3D asset</a><br>
|
||||
<a href="https://github.com/coderofsalvation/xrfragment/issues/4">» discussion</a><br></p>
|
||||
|
||||
<h1 id="navigating-content-href-portals">Navigating content (href portals)</h1>
|
||||
<h1 id="navigating-content-internal-outbound-href-portals">Navigating content (internal/outbound href portals)</h1>
|
||||
|
||||
<p>navigation, portals & mutations</p>
|
||||
|
||||
|
@ -556,7 +554,7 @@ Resizing will be happen accordingly to its placeholder object <code>aquariumcube
|
|||
</table>
|
||||
|
||||
<ol>
|
||||
<li><p>clicking an “external”- or “file URI” fully replaces the current scene and assumes <code>pos=0,0,0&rot=0,0,0</code> by default (unless specified)</p></li>
|
||||
<li><p>clicking an outbound “external”- or “file URI” fully replaces the current scene and assumes <code>pos=0,0,0&rot=0,0,0</code> by default (unless specified)</p></li>
|
||||
|
||||
<li><p>relocation/reorientation should happen locally for local URI’s (<code>#pos=....</code>)</p></li>
|
||||
|
||||
|
@ -1085,16 +1083,20 @@ here are some hashtagbibs followed by bibtex:
|
|||
<p>when an XR browser updates the human text, a quick scan for nonmatching tags (<code>@book{nonmatchingbook</code> e.g.) should be performed and prompt the enduser for deleting them.</p>
|
||||
</blockquote>
|
||||
|
||||
<h1 id="broken-links">Broken links</h1>
|
||||
<h1 id="transclusion-broken-link-resolution">Transclusion (broken link) resolution</h1>
|
||||
|
||||
<p>There’s a soft-mechanism to harden links & prevent broken links in various ways:</p>
|
||||
<p>In spirit of Ted Nelson’s ‘transclusion resolution’, there’s a soft-mechanism to harden links & minimize broken links in various ways:</p>
|
||||
|
||||
<ol>
|
||||
<li>defining a different transport protocol (https vs ipfs or DAT) in <code>src</code> or <code>href</code> values can make a difference</li>
|
||||
<li>mirroring files on another protocol using errorcodes in <code>src</code> or <code>href</code> properties</li>
|
||||
<li>mirroring files on another protocol using (HTTP) errorcode tags in <code>src</code> or <code>href</code> properties</li>
|
||||
<li>in case of <code>src</code>: nesting a copy of the embedded object in the placeholder object (<code>embeddedObject</code>) will not be replaced when the request fails</li>
|
||||
</ol>
|
||||
|
||||
<blockquote>
|
||||
<p>due to the popularity, maturity and extensiveness of HTTP codes for client/server communication, non-HTTP protocols easily map to HTTP codes (ipfs ERR_NOT_FOUND maps to 404 e.g.)</p>
|
||||
</blockquote>
|
||||
|
||||
<p>For example:</p>
|
||||
|
||||
<pre><code> +────────────────────────────────────────────────────────+
|
||||
|
@ -1105,19 +1107,45 @@ here are some hashtagbibs followed by bibtex:
|
|||
│ │ │
|
||||
│ ├── ◻ buttonA │
|
||||
│ │ └ href: http://foo.io/campagne.fbx │
|
||||
│ │ └ href!404: ipfs://foo.io/campagne.fbx │
|
||||
│ │ └ href!400: #q=clienterrortext │
|
||||
│ │ └ href@404: ipfs://foo.io/campagne.fbx │
|
||||
│ │ └ href@400: #q=clienterrortext │
|
||||
│ │ └ ◻ offlinetext │
|
||||
│ │ │
|
||||
│ └── ◻ embeddedObject <--------- the meshdata inside embeddedObject will (not)
|
||||
│ └ src: https://foo.io/bar.gltf │ be flushed when the request (does not) succeed.
|
||||
│ └ src!404: http://foo.io/bar.gltf │ So worstcase the 3D data (of the time of publishing index.gltf)
|
||||
│ └ src!400: https://archive.org/l2kj43.gltf │ will be displayed.
|
||||
│ └ src@404: http://foo.io/bar.gltf │ So worstcase the 3D data (of the time of publishing index.gltf)
|
||||
│ └ src@400: https://archive.org/l2kj43.gltf │ will be displayed.
|
||||
│ │
|
||||
+────────────────────────────────────────────────────────+
|
||||
|
||||
</code></pre>
|
||||
|
||||
<h1 id="topic-based-index-less-webrings">Topic-based index-less Webrings</h1>
|
||||
|
||||
<p>As hashtags in URLs map to the XWRG, <code>href</code>-values can be used to promote topic-based index-less webrings.<br>
|
||||
Consider 3D scenes linking to eachother using these <code>href</code> values:</p>
|
||||
|
||||
<ul>
|
||||
<li><code>href: schoolA.edu/projects.gltf#math</code></li>
|
||||
<li><code>href: schoolB.edu/projects.gltf#math</code></li>
|
||||
<li><code>href: university.edu/projects.gltf#math</code></li>
|
||||
</ul>
|
||||
|
||||
<p>These links would all show visible links to math-tagged objects in the scene.<br>
|
||||
To filter out non-related objects one could take it a step further using queries:</p>
|
||||
|
||||
<ul>
|
||||
<li><code>href: schoolA.edu/projects.gltf#math&q=-topics math</code></li>
|
||||
<li><code>href: schoolB.edu/projects.gltf#math&q=-courses math</code></li>
|
||||
<li><code>href: university.edu/projects.gltf#math&q=-theme math</code></li>
|
||||
</ul>
|
||||
|
||||
<blockquote>
|
||||
<p>This would hide all object tagged with <code>topic</code>, <code>courses</code> or <code>theme</code> (including math) so that later only objects tagged with <code>math</code> will be visible</p>
|
||||
</blockquote>
|
||||
|
||||
<p>This makes spatial content multi-purpose, without the need to separate content into separate files, or show/hide things using a complex logiclayer like javascript.</p>
|
||||
|
||||
<h1 id="security-considerations">Security Considerations</h1>
|
||||
|
||||
<p>Since XR Text contains metadata too, the user should be able to set up tagging-rules, so the copy-paste feature can :</p>
|
||||
|
@ -1133,8 +1161,11 @@ here are some hashtagbibs followed by bibtex:
|
|||
|
||||
<hr>
|
||||
|
||||
<p><strong>Q:</strong> Why isn’t there support for scripting
|
||||
<strong>A:</strong> This is out of scope, and up to the XR hypermedia browser. Javascript seems to been able to turn webpages from hypermedia documents into its opposite (hyperscripted nonhypermedia documents). In order to prevent this backward-movement (hypermedia tends to liberate people from finnicky scripting) XR Fragments should never unhyperify itself by hardcoupling to a particular markup or scripting language. <a href="https://xrfragment.org/doc/RFC_XR_Macros.html">XR Macro’s</a> are an example of something which is probably smarter and safer for hypermedia browsers to implement, instead of going full-in with a turing-complete scripting language (and suffer the security consequences later).</p>
|
||||
<p><strong>Q:</strong> Why isn’t there support for scripting, while we have things like WASM
|
||||
<strong>A:</strong> This is out of scope as it unhyperifies hypermedia, and this is up to XR hypermedia browser-extensions.<br> Historically scripting/Javascript seems to been able to turn webpages from hypermedia documents into its opposite (hyperscripted nonhypermedia documents).<br>In order to prevent this backward-movement (hypermedia tends to liberate people from finnicky scripting) XR Fragments should never unhyperify itself by hardcoupling to a particular markup or scripting language. <a href="https://xrfragment.org/doc/RFC_XR_Macros.html">XR Macro’s</a> are an example of something which is probably smarter and safer for hypermedia browsers to implement, instead of going full-in with a turing-complete scripting language (and suffer the security consequences later).<br>
|
||||
XR Fragments supports filtering objects in a scene only, because in the history of the javascript-powered web, showing/hiding document-entities seems to be one of the most popular basic usecases.<br>
|
||||
Doing advanced scripting & networkrequests under the hood are obviously interesting endavours, but this is something which should not be hardcoupled with hypermedia.<br>This belongs to browser extensions.<br>
|
||||
Non-HTML Hypermedia browsers should make browser extensions the right place, to ‘extend’ experiences, in contrast to code/javascript inside hypermedia documents (this turned out as a hypermedia antipattern).</p>
|
||||
|
||||
<h1 id="iana-considerations">IANA Considerations</h1>
|
||||
|
||||
|
|
|
@ -199,17 +199,19 @@ sub-delims = "," / "="
|
|||
|
||||
| key | type | example (JSON) | function | existing compatibility |
|
||||
|--------------|----------|------------------------|---------------------|----------------------------------------|
|
||||
| `name` | string | `"name": "cube"` | identify/tag | object supported in all 3D fileformats & scenes |
|
||||
| `tag` | string | `"tag": "cubes geo"` | tag object | custom property in 3D fileformats |
|
||||
| `href` | string | `"href": "b.gltf"` | XR teleport | custom property in 3D fileformats |
|
||||
| `src` | string | `"src": "#cube"` | XR embed / teleport |custom property in 3D fileformats |
|
||||
| `src` | string | `"src": "#cube"` | XR embed / teleport | custom property in 3D fileformats |
|
||||
| `tag` | string | `"tag": "cubes geo"` | tag object (for query-use / XRWG highlighting) | custom property in 3D fileformats |
|
||||
|
||||
Supported popular compatible 3D fileformats: `.gltf`, `.obj`, `.fbx`, `.usdz`, `.json` (THREE.js), `.dae` and so on.
|
||||
|
||||
> NOTE: XR Fragments are file-agnostic, which means that the metadata exist in programmatic 3D scene(nodes) too.
|
||||
> NOTE: XR Fragments are optional but also file- and protocol-agnostic, which means that programmatic 3D scene(nodes) can also use the mechanism/metadata.
|
||||
|
||||
# Spatial Referencing 3D
|
||||
|
||||
|
||||
XR Fragments assume the following objectname-to-URIFragment mapping:
|
||||
|
||||
```
|
||||
|
||||
my.io/scene.fbx
|
||||
|
@ -229,6 +231,8 @@ Supported popular compatible 3D fileformats: `.gltf`, `.obj`, `.fbx`, `.usdz`, `
|
|||
|
||||
```
|
||||
|
||||
> Every 3D fileformat supports named 3D object, and this name allows URLs (fragments) to reference them (and their children objects).
|
||||
|
||||
Clever nested design of 3D scenes allow great ways for re-using content, and/or previewing scenes.<br>
|
||||
For example, to render a portal with a preview-version of the scene, create an 3D object with:
|
||||
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
|
||||
|
||||
Internet Engineering Task Force L.R. van Kammen
|
||||
Internet-Draft 22 September 2023
|
||||
Internet-Draft 12 October 2023
|
||||
Intended status: Informational
|
||||
|
||||
|
||||
|
@ -13,9 +13,10 @@ Intended status: Informational
|
|||
|
||||
Abstract
|
||||
|
||||
This draft is a specification for 4D URLs & navigation, which links
|
||||
together space, time & text together, for hypermedia browsers with-
|
||||
or without a network-connection.
|
||||
This draft is a specification for 4D URLs & hypermediatic
|
||||
(https://github.com/coderofsalvation/hypermediatic) navigation, which
|
||||
links together space, time & text together, for hypermedia browsers
|
||||
with- or without a network-connection.
|
||||
The specification promotes spatial addressibility, sharing,
|
||||
navigation, query-ing and annotating interactive (text)objects across
|
||||
for (XR) Browsers.
|
||||
|
@ -41,7 +42,7 @@ Status of This Memo
|
|||
time. It is inappropriate to use Internet-Drafts as reference
|
||||
material or to cite them other than as "work in progress."
|
||||
|
||||
This Internet-Draft will expire on 25 March 2024.
|
||||
This Internet-Draft will expire on 14 April 2024.
|
||||
|
||||
Copyright Notice
|
||||
|
||||
|
@ -52,10 +53,9 @@ Copyright Notice
|
|||
|
||||
|
||||
|
||||
|
||||
van Kammen Expires 25 March 2024 [Page 1]
|
||||
van Kammen Expires 14 April 2024 [Page 1]
|
||||
|
||||
Internet-Draft XR Fragments September 2023
|
||||
Internet-Draft XR Fragments October 2023
|
||||
|
||||
|
||||
This document is subject to BCP 78 and the IETF Trust's Legal
|
||||
|
@ -79,7 +79,7 @@ Table of Contents
|
|||
7. Navigating 3D . . . . . . . . . . . . . . . . . . . . . . . . 8
|
||||
8. Top-level URL processing . . . . . . . . . . . . . . . . . . 9
|
||||
9. Embedding XR content (src-instancing) . . . . . . . . . . . . 9
|
||||
10. Navigating content (href portals) . . . . . . . . . . . . . . 12
|
||||
10. Navigating content (internal/outbound href portals) . . . . . 12
|
||||
10.1. UX spec . . . . . . . . . . . . . . . . . . . . . . . . 13
|
||||
10.2. Scaling instanced content . . . . . . . . . . . . . . . 13
|
||||
11. XR Fragment queries . . . . . . . . . . . . . . . . . . . . . 14
|
||||
|
@ -90,12 +90,13 @@ Table of Contents
|
|||
13.1. Default Data URI mimetype . . . . . . . . . . . . . . . 20
|
||||
13.2. URL and Data URI . . . . . . . . . . . . . . . . . . . . 21
|
||||
13.3. XR Text example parser . . . . . . . . . . . . . . . . . 22
|
||||
14. Broken links . . . . . . . . . . . . . . . . . . . . . . . . 24
|
||||
15. Security Considerations . . . . . . . . . . . . . . . . . . . 25
|
||||
16. FAQ . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 25
|
||||
17. IANA Considerations . . . . . . . . . . . . . . . . . . . . . 26
|
||||
18. Acknowledgments . . . . . . . . . . . . . . . . . . . . . . . 26
|
||||
19. Appendix: Definitions . . . . . . . . . . . . . . . . . . . . 26
|
||||
14. Transclusion (broken link) resolution . . . . . . . . . . . . 24
|
||||
15. Topic-based index-less Webrings . . . . . . . . . . . . . . . 25
|
||||
16. Security Considerations . . . . . . . . . . . . . . . . . . . 26
|
||||
17. FAQ . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 26
|
||||
18. IANA Considerations . . . . . . . . . . . . . . . . . . . . . 27
|
||||
19. Acknowledgments . . . . . . . . . . . . . . . . . . . . . . . 27
|
||||
20. Appendix: Definitions . . . . . . . . . . . . . . . . . . . . 27
|
||||
|
||||
1. Introduction
|
||||
|
||||
|
@ -103,20 +104,23 @@ Table of Contents
|
|||
introducing new dataformats?
|
||||
Historically, there's many attempts to create the ultimate
|
||||
markuplanguage or 3D fileformat.
|
||||
Their lowest common denominator is: (co)authoring using plain text.
|
||||
The lowest common denominator is: describing/tagging/naming nodes
|
||||
using *plain text*.
|
||||
|
||||
|
||||
|
||||
van Kammen Expires 14 April 2024 [Page 2]
|
||||
|
||||
Internet-Draft XR Fragments October 2023
|
||||
|
||||
|
||||
XR Fragments allows us to enrich/connect existing dataformats, by
|
||||
introducing existing technologies/ideas:
|
||||
|
||||
|
||||
|
||||
van Kammen Expires 25 March 2024 [Page 2]
|
||||
|
||||
Internet-Draft XR Fragments September 2023
|
||||
|
||||
|
||||
1. addressibility and navigation of 3D scenes/objects: URI Fragments
|
||||
(https://en.wikipedia.org/wiki/URI_fragment) + src/href spatial
|
||||
metadata
|
||||
1. addressibility and hypermediatic
|
||||
(https://github.com/coderofsalvation/hypermediatic) navigation of
|
||||
3D scenes/objects: URI Fragments (https://en.wikipedia.org/wiki/
|
||||
URI_fragment) + src/href spatial metadata
|
||||
2. Interlinking text/& 3D by collapsing space into a Word Graph
|
||||
(XRWG) to show visible links (#visible-links) (and augmenting
|
||||
text with bibs (https://github.com/coderofsalvation/tagbibs) /
|
||||
|
@ -161,13 +165,9 @@ Internet-Draft XR Fragments September 2023
|
|||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
van Kammen Expires 25 March 2024 [Page 3]
|
||||
van Kammen Expires 14 April 2024 [Page 3]
|
||||
|
||||
Internet-Draft XR Fragments September 2023
|
||||
Internet-Draft XR Fragments October 2023
|
||||
|
||||
|
||||
+===========+=============================+====================+
|
||||
|
@ -221,9 +221,9 @@ Internet-Draft XR Fragments September 2023
|
|||
|
||||
|
||||
|
||||
van Kammen Expires 25 March 2024 [Page 4]
|
||||
van Kammen Expires 14 April 2024 [Page 4]
|
||||
|
||||
Internet-Draft XR Fragments September 2023
|
||||
Internet-Draft XR Fragments October 2023
|
||||
|
||||
|
||||
+──────────────────────────────────────────────────────────────────────────────────────────────+
|
||||
|
@ -246,15 +246,18 @@ Internet-Draft XR Fragments September 2023
|
|||
|
||||
Traditional webbrowsers can become 4D document-ready by:
|
||||
|
||||
* loading 3D assets (gltf/fbx e.g.) natively (with or without using
|
||||
* hypermediatic (https://github.com/coderofsalvation/hypermediatic)
|
||||
loading 3D assets (gltf/fbx e.g.) natively (with or without using
|
||||
HTML).
|
||||
* allowing assets to publish hashtags to themselves (the scene)
|
||||
using the hashbus (like hashtags controlling the scrollbar).
|
||||
* collapsing the 3D scene to an wordgraph (for essential navigation
|
||||
purposes) controllable thru a hash(tag)bus
|
||||
|
||||
XR Fragments itself are HTML-agnostic, though pseudo-XR Fragment
|
||||
browsers *can* be implemented on top of HTML/Javascript.
|
||||
XR Fragments itself are hypermediatic
|
||||
(https://github.com/coderofsalvation/hypermediatic) and HTML-
|
||||
agnostic, though pseudo-XR Fragment browsers *can* be implemented on
|
||||
top of HTML/Javascript.
|
||||
|
||||
3. Conventions and Definitions
|
||||
|
||||
|
@ -274,12 +277,9 @@ Internet-Draft XR Fragments September 2023
|
|||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
van Kammen Expires 25 March 2024 [Page 5]
|
||||
van Kammen Expires 14 April 2024 [Page 5]
|
||||
|
||||
Internet-Draft XR Fragments September 2023
|
||||
Internet-Draft XR Fragments October 2023
|
||||
|
||||
|
||||
+=============================+=================================+
|
||||
|
@ -296,65 +296,67 @@ Internet-Draft XR Fragments September 2023
|
|||
|
||||
4. List of URI Fragments
|
||||
|
||||
+==========+=========+==============+==============================+
|
||||
| fragment | type | example | info |
|
||||
+==========+=========+==============+==============================+
|
||||
| #pos | vector3 | #pos=0.5,0,0 | positions camera (or XR |
|
||||
| | | | floor) to xyz-coord 0.5,0,0, |
|
||||
+----------+---------+--------------+------------------------------+
|
||||
| #rot | vector3 | #rot=0,90,0 | rotates camera to xyz-coord |
|
||||
| | | | 0.5,0,0 |
|
||||
+----------+---------+--------------+------------------------------+
|
||||
| #t | vector2 | #t=500,1000 | sets animation-loop range |
|
||||
| | | | between frame 500 and 1000 |
|
||||
+----------+---------+--------------+------------------------------+
|
||||
| #...... | string | #.cubes | predefined views, XRWG |
|
||||
| | | #cube | fragments and ID fragments |
|
||||
+----------+---------+--------------+------------------------------+
|
||||
+==========+=========+===============+==============================+
|
||||
| fragment | type | example | info |
|
||||
+==========+=========+===============+==============================+
|
||||
| #pos | vector3 | #pos=0.5,0,0 | positions camera (or XR |
|
||||
| | | | floor) to xyz-coord |
|
||||
| | | | 0.5,0,0, |
|
||||
+----------+---------+---------------+------------------------------+
|
||||
| #rot | vector3 | #rot=0,90,0 | rotates camera to xyz- |
|
||||
| | | | coord 0.5,0,0 |
|
||||
+----------+---------+---------------+------------------------------+
|
||||
| #t | vector3 | #t=1,500,1000 | play animation-loop range |
|
||||
| | | | between frame 500 and |
|
||||
| | | | 1000, at normal speed |
|
||||
+----------+---------+---------------+------------------------------+
|
||||
| #...... | string | #.cubes #cube | predefined views, XRWG |
|
||||
| | | | fragments and ID |
|
||||
| | | | fragments |
|
||||
+----------+---------+---------------+------------------------------+
|
||||
|
||||
Table 3
|
||||
Table 3
|
||||
|
||||
| xyz coordinates are similar to ones found in SVG Media Fragments
|
||||
|
||||
5. List of metadata for 3D nodes
|
||||
|
||||
+======+========+=============+===========+=========================+
|
||||
| key | type | example | function | existing compatibility |
|
||||
| | | (JSON) | | |
|
||||
+======+========+=============+===========+=========================+
|
||||
| name | string | "name": | identify/ | object supported in all |
|
||||
| | | "cube" | tag | 3D fileformats & scenes |
|
||||
+------+--------+-------------+-----------+-------------------------+
|
||||
| tag | string | "tag": | tag | custom property in 3D |
|
||||
| | | "cubes | object | fileformats |
|
||||
| | | geo" | | |
|
||||
+------+--------+-------------+-----------+-------------------------+
|
||||
| href | string | "href": | XR | custom property in 3D |
|
||||
+======+========+==========+==================+===================+
|
||||
| key | type | example | function | existing |
|
||||
| | | (JSON) | | compatibility |
|
||||
+======+========+==========+==================+===================+
|
||||
| href | string | "href": | XR teleport | custom property |
|
||||
| | | "b.gltf" | | in 3D fileformats |
|
||||
+------+--------+----------+------------------+-------------------+
|
||||
| src | string | "src": | XR embed / | custom property |
|
||||
| | | "#cube" | teleport | in 3D fileformats |
|
||||
|
||||
|
||||
|
||||
van Kammen Expires 25 March 2024 [Page 6]
|
||||
van Kammen Expires 14 April 2024 [Page 6]
|
||||
|
||||
Internet-Draft XR Fragments September 2023
|
||||
Internet-Draft XR Fragments October 2023
|
||||
|
||||
|
||||
| | | "b.gltf" | teleport | fileformats |
|
||||
+------+--------+-------------+-----------+-------------------------+
|
||||
| src | string | "src": | XR embed | custom property in 3D |
|
||||
| | | "#cube" | / | fileformats |
|
||||
| | | | teleport | |
|
||||
+------+--------+-------------+-----------+-------------------------+
|
||||
+------+--------+----------+------------------+-------------------+
|
||||
| tag | string | "tag": | tag object (for | custom property |
|
||||
| | | "cubes | query-use / XRWG | in 3D fileformats |
|
||||
| | | geo" | highlighting) | |
|
||||
+------+--------+----------+------------------+-------------------+
|
||||
|
||||
Table 4
|
||||
|
||||
Supported popular compatible 3D fileformats: .gltf, .obj, .fbx,
|
||||
.usdz, .json (THREE.js), .dae and so on.
|
||||
|
||||
| NOTE: XR Fragments are file-agnostic, which means that the
|
||||
| metadata exist in programmatic 3D scene(nodes) too.
|
||||
| NOTE: XR Fragments are optional but also file- and protocol-
|
||||
| agnostic, which means that programmatic 3D scene(nodes) can also
|
||||
| use the mechanism/metadata.
|
||||
|
||||
6. Spatial Referencing 3D
|
||||
|
||||
XR Fragments assume the following objectname-to-URIFragment mapping:
|
||||
|
||||
my.io/scene.fbx
|
||||
+─────────────────────────────+
|
||||
│ sky │ src: http://my.io/scene.fbx#sky (includes building,mainobject,floor)
|
||||
|
@ -370,6 +372,9 @@ Internet-Draft XR Fragments September 2023
|
|||
│ +─────────────────────────+ │
|
||||
+─────────────────────────────+
|
||||
|
||||
| Every 3D fileformat supports named 3D object, and this name allows
|
||||
| URLs (fragments) to reference them (and their children objects).
|
||||
|
||||
Clever nested design of 3D scenes allow great ways for re-using
|
||||
content, and/or previewing scenes.
|
||||
For example, to render a portal with a preview-version of the scene,
|
||||
|
@ -378,21 +383,22 @@ Internet-Draft XR Fragments September 2023
|
|||
* href: https://scene.fbx
|
||||
* src: https://otherworld.gltf#mainobject
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
van Kammen Expires 14 April 2024 [Page 7]
|
||||
|
||||
Internet-Draft XR Fragments October 2023
|
||||
|
||||
|
||||
| It also allows *sourceportation*, which basically means the
|
||||
| enduser can teleport to the original XR Document of an src
|
||||
| embedded object, and see a visible connection to the particular
|
||||
| embedded object.
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
van Kammen Expires 25 March 2024 [Page 7]
|
||||
|
||||
Internet-Draft XR Fragments September 2023
|
||||
|
||||
| embedded object. Basically an embedded link becoming an outbound
|
||||
| link by activating it.
|
||||
|
||||
7. Navigating 3D
|
||||
|
||||
|
@ -401,7 +407,8 @@ Internet-Draft XR Fragments September 2023
|
|||
+====================+=========+==================================+
|
||||
| <b>#pos</b>=0,0,0 | vector3 | (re)position camera |
|
||||
+--------------------+---------+----------------------------------+
|
||||
| <b>#t</b>=0,100 | vector2 | (re)position looprange of scene- |
|
||||
| <b>#t</b>=0,100 | vector3 | set playback speed, and |
|
||||
| | | (re)position looprange of scene- |
|
||||
| | | animation or src-mediacontent |
|
||||
+--------------------+---------+----------------------------------+
|
||||
| <b>#rot</b>=0,90,0 | vector3 | rotate camera |
|
||||
|
@ -421,15 +428,28 @@ Internet-Draft XR Fragments September 2023
|
|||
2. set the position of the camera accordingly to the vector3 values
|
||||
of #pos
|
||||
3. rot sets the rotation of the camera (only for non-VR/AR headsets)
|
||||
4. t sets the animation-range of the current scene animation(s) or
|
||||
src-mediacontent (video/audioframes e.g., use t=7,7 to 'STOP' at
|
||||
certain frame)
|
||||
4. t sets the playbackspeed and animation-range of the current scene
|
||||
animation(s) or src-mediacontent (video/audioframes e.g., use
|
||||
t=0,7,7 to 'STOP' at frame 7 e.g.)
|
||||
5. in case an href does not mention any pos-coordinate, pos=0,0,0
|
||||
will be assumed
|
||||
|
||||
Here's an ascii representation of a 3D scene-graph which contains 3D
|
||||
objects ◻ and their metadata:
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
van Kammen Expires 14 April 2024 [Page 8]
|
||||
|
||||
Internet-Draft XR Fragments October 2023
|
||||
|
||||
|
||||
+────────────────────────────────────────────────────────+
|
||||
│ │
|
||||
│ index.gltf │
|
||||
|
@ -442,14 +462,6 @@ Internet-Draft XR Fragments September 2023
|
|||
│ │
|
||||
+────────────────────────────────────────────────────────+
|
||||
|
||||
|
||||
|
||||
|
||||
van Kammen Expires 25 March 2024 [Page 8]
|
||||
|
||||
Internet-Draft XR Fragments September 2023
|
||||
|
||||
|
||||
An XR Fragment-compatible browser viewing this scene, allows the end-
|
||||
user to interact with the buttonA and buttonB.
|
||||
In case of buttonA the end-user will be teleported to another
|
||||
|
@ -489,21 +501,9 @@ Internet-Draft XR Fragments September 2023
|
|||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
van Kammen Expires 25 March 2024 [Page 9]
|
||||
van Kammen Expires 14 April 2024 [Page 9]
|
||||
|
||||
Internet-Draft XR Fragments September 2023
|
||||
Internet-Draft XR Fragments October 2023
|
||||
|
||||
|
||||
+========+==========+==============================================+
|
||||
|
@ -557,9 +557,9 @@ Internet-Draft XR Fragments September 2023
|
|||
|
||||
|
||||
|
||||
van Kammen Expires 25 March 2024 [Page 10]
|
||||
van Kammen Expires 14 April 2024 [Page 10]
|
||||
|
||||
Internet-Draft XR Fragments September 2023
|
||||
Internet-Draft XR Fragments October 2023
|
||||
|
||||
|
||||
| Instead of cherrypicking objects with #bass&tuna thru src, queries
|
||||
|
@ -613,9 +613,9 @@ Internet-Draft XR Fragments September 2023
|
|||
|
||||
|
||||
|
||||
van Kammen Expires 25 March 2024 [Page 11]
|
||||
van Kammen Expires 14 April 2024 [Page 11]
|
||||
|
||||
Internet-Draft XR Fragments September 2023
|
||||
Internet-Draft XR Fragments October 2023
|
||||
|
||||
|
||||
» example implementation
|
||||
|
@ -627,7 +627,7 @@ Internet-Draft XR Fragments September 2023
|
|||
» discussion (https://github.com/coderofsalvation/xrfragment/
|
||||
issues/4)
|
||||
|
||||
10. Navigating content (href portals)
|
||||
10. Navigating content (internal/outbound href portals)
|
||||
|
||||
navigation, portals & mutations
|
||||
|
||||
|
@ -641,9 +641,9 @@ Internet-Draft XR Fragments September 2023
|
|||
|
||||
Table 7
|
||||
|
||||
1. clicking an ''external''- or ''file URI'' fully replaces the
|
||||
current scene and assumes pos=0,0,0&rot=0,0,0 by default (unless
|
||||
specified)
|
||||
1. clicking an outbound ''external''- or ''file URI'' fully replaces
|
||||
the current scene and assumes pos=0,0,0&rot=0,0,0 by default
|
||||
(unless specified)
|
||||
|
||||
2. relocation/reorientation should happen locally for local URI's
|
||||
(#pos=....)
|
||||
|
@ -669,9 +669,9 @@ Internet-Draft XR Fragments September 2023
|
|||
|
||||
|
||||
|
||||
van Kammen Expires 25 March 2024 [Page 12]
|
||||
van Kammen Expires 14 April 2024 [Page 12]
|
||||
|
||||
Internet-Draft XR Fragments September 2023
|
||||
Internet-Draft XR Fragments October 2023
|
||||
|
||||
|
||||
6. in case of navigating to a new [[pos)ition, ''first'' navigate to
|
||||
|
@ -725,9 +725,9 @@ Internet-Draft XR Fragments September 2023
|
|||
|
||||
|
||||
|
||||
van Kammen Expires 25 March 2024 [Page 13]
|
||||
van Kammen Expires 14 April 2024 [Page 13]
|
||||
|
||||
Internet-Draft XR Fragments September 2023
|
||||
Internet-Draft XR Fragments October 2023
|
||||
|
||||
|
||||
| REASON: non-empty placeholder object can act as a protective
|
||||
|
@ -781,9 +781,9 @@ Internet-Draft XR Fragments September 2023
|
|||
|
||||
|
||||
|
||||
van Kammen Expires 25 March 2024 [Page 14]
|
||||
van Kammen Expires 14 April 2024 [Page 14]
|
||||
|
||||
Internet-Draft XR Fragments September 2023
|
||||
Internet-Draft XR Fragments October 2023
|
||||
|
||||
|
||||
11.1. including/excluding
|
||||
|
@ -837,9 +837,9 @@ Internet-Draft XR Fragments September 2023
|
|||
|
||||
|
||||
|
||||
van Kammen Expires 25 March 2024 [Page 15]
|
||||
van Kammen Expires 14 April 2024 [Page 15]
|
||||
|
||||
Internet-Draft XR Fragments September 2023
|
||||
Internet-Draft XR Fragments October 2023
|
||||
|
||||
|
||||
11. and we set root to true or false (true=/ root selector is
|
||||
|
@ -893,9 +893,9 @@ Internet-Draft XR Fragments September 2023
|
|||
|
||||
|
||||
|
||||
van Kammen Expires 25 March 2024 [Page 16]
|
||||
van Kammen Expires 14 April 2024 [Page 16]
|
||||
|
||||
Internet-Draft XR Fragments September 2023
|
||||
Internet-Draft XR Fragments October 2023
|
||||
|
||||
|
||||
in games outside the browser? Through the lens of constructive lazy
|
||||
|
@ -949,9 +949,9 @@ Internet-Draft XR Fragments September 2023
|
|||
|
||||
|
||||
|
||||
van Kammen Expires 25 March 2024 [Page 17]
|
||||
van Kammen Expires 14 April 2024 [Page 17]
|
||||
|
||||
Internet-Draft XR Fragments September 2023
|
||||
Internet-Draft XR Fragments October 2023
|
||||
|
||||
|
||||
http://y.io/z.fbx | Derived XRWG (expressed as BibTex)
|
||||
|
@ -1005,9 +1005,9 @@ Internet-Draft XR Fragments September 2023
|
|||
|
||||
|
||||
|
||||
van Kammen Expires 25 March 2024 [Page 18]
|
||||
van Kammen Expires 14 April 2024 [Page 18]
|
||||
|
||||
Internet-Draft XR Fragments September 2023
|
||||
Internet-Draft XR Fragments October 2023
|
||||
|
||||
|
||||
As seen above, the XRWG can expand bibs
|
||||
|
@ -1061,9 +1061,9 @@ Internet-Draft XR Fragments September 2023
|
|||
|
||||
|
||||
|
||||
van Kammen Expires 25 March 2024 [Page 19]
|
||||
van Kammen Expires 14 April 2024 [Page 19]
|
||||
|
||||
Internet-Draft XR Fragments September 2023
|
||||
Internet-Draft XR Fragments October 2023
|
||||
|
||||
|
||||
12. Default font (unless specified otherwise) is a modern monospace
|
||||
|
@ -1117,9 +1117,9 @@ Internet-Draft XR Fragments September 2023
|
|||
|
||||
|
||||
|
||||
van Kammen Expires 25 March 2024 [Page 20]
|
||||
van Kammen Expires 14 April 2024 [Page 20]
|
||||
|
||||
Internet-Draft XR Fragments September 2023
|
||||
Internet-Draft XR Fragments October 2023
|
||||
|
||||
|
||||
* lines beginning with @ will not be rendered verbatim by default
|
||||
|
@ -1173,9 +1173,9 @@ Internet-Draft XR Fragments September 2023
|
|||
|
||||
|
||||
|
||||
van Kammen Expires 25 March 2024 [Page 21]
|
||||
van Kammen Expires 14 April 2024 [Page 21]
|
||||
|
||||
Internet-Draft XR Fragments September 2023
|
||||
Internet-Draft XR Fragments October 2023
|
||||
|
||||
|
||||
+--------------------------------------------------------------+ +------------------------+
|
||||
|
@ -1229,9 +1229,9 @@ xrtext = {
|
|||
|
||||
|
||||
|
||||
van Kammen Expires 25 March 2024 [Page 22]
|
||||
van Kammen Expires 14 April 2024 [Page 22]
|
||||
|
||||
Internet-Draft XR Fragments September 2023
|
||||
Internet-Draft XR Fragments October 2023
|
||||
|
||||
|
||||
// bibtex: ↓@ ↓<tag|tag{phrase,|{ruler}> ↓property ↓end
|
||||
|
@ -1285,9 +1285,9 @@ Internet-Draft XR Fragments September 2023
|
|||
|
||||
|
||||
|
||||
van Kammen Expires 25 March 2024 [Page 23]
|
||||
van Kammen Expires 14 April 2024 [Page 23]
|
||||
|
||||
Internet-Draft XR Fragments September 2023
|
||||
Internet-Draft XR Fragments October 2023
|
||||
|
||||
|
||||
str = `
|
||||
|
@ -1330,10 +1330,10 @@ console.log( xrtext.encode(text,tags) ) // multiplex text & bibtex back to
|
|||
| nonmatching tags (@book{nonmatchingbook e.g.) should be performed
|
||||
| and prompt the enduser for deleting them.
|
||||
|
||||
14. Broken links
|
||||
14. Transclusion (broken link) resolution
|
||||
|
||||
There's a soft-mechanism to harden links & prevent broken links in
|
||||
various ways:
|
||||
In spirit of Ted Nelson's 'transclusion resolution', there's a soft-
|
||||
mechanism to harden links & minimize broken links in various ways:
|
||||
|
||||
1. defining a different transport protocol (https vs ipfs or DAT) in
|
||||
src or href values can make a difference
|
||||
|
@ -1341,17 +1341,21 @@ console.log( xrtext.encode(text,tags) ) // multiplex text & bibtex back to
|
|||
|
||||
|
||||
|
||||
van Kammen Expires 25 March 2024 [Page 24]
|
||||
van Kammen Expires 14 April 2024 [Page 24]
|
||||
|
||||
Internet-Draft XR Fragments September 2023
|
||||
Internet-Draft XR Fragments October 2023
|
||||
|
||||
|
||||
2. mirroring files on another protocol using errorcodes in src or
|
||||
href properties
|
||||
2. mirroring files on another protocol using (HTTP) errorcode tags
|
||||
in src or href properties
|
||||
3. in case of src: nesting a copy of the embedded object in the
|
||||
placeholder object (embeddedObject) will not be replaced when the
|
||||
request fails
|
||||
|
||||
| due to the popularity, maturity and extensiveness of HTTP codes
|
||||
| for client/server communication, non-HTTP protocols easily map to
|
||||
| HTTP codes (ipfs ERR_NOT_FOUND maps to 404 e.g.)
|
||||
|
||||
For example:
|
||||
|
||||
+────────────────────────────────────────────────────────+
|
||||
|
@ -1362,18 +1366,53 @@ Internet-Draft XR Fragments September 2023
|
|||
│ │ │
|
||||
│ ├── ◻ buttonA │
|
||||
│ │ └ href: http://foo.io/campagne.fbx │
|
||||
│ │ └ href!404: ipfs://foo.io/campagne.fbx │
|
||||
│ │ └ href!400: #q=clienterrortext │
|
||||
│ │ └ href@404: ipfs://foo.io/campagne.fbx │
|
||||
│ │ └ href@400: #q=clienterrortext │
|
||||
│ │ └ ◻ offlinetext │
|
||||
│ │ │
|
||||
│ └── ◻ embeddedObject <--------- the meshdata inside embeddedObject will (not)
|
||||
│ └ src: https://foo.io/bar.gltf │ be flushed when the request (does not) succeed.
|
||||
│ └ src!404: http://foo.io/bar.gltf │ So worstcase the 3D data (of the time of publishing index.gltf)
|
||||
│ └ src!400: https://archive.org/l2kj43.gltf │ will be displayed.
|
||||
│ └ src@404: http://foo.io/bar.gltf │ So worstcase the 3D data (of the time of publishing index.gltf)
|
||||
│ └ src@400: https://archive.org/l2kj43.gltf │ will be displayed.
|
||||
│ │
|
||||
+────────────────────────────────────────────────────────+
|
||||
|
||||
15. Security Considerations
|
||||
15. Topic-based index-less Webrings
|
||||
|
||||
As hashtags in URLs map to the XWRG, href-values can be used to
|
||||
promote topic-based index-less webrings.
|
||||
Consider 3D scenes linking to eachother using these href values:
|
||||
|
||||
* href: schoolA.edu/projects.gltf#math
|
||||
* href: schoolB.edu/projects.gltf#math
|
||||
* href: university.edu/projects.gltf#math
|
||||
|
||||
These links would all show visible links to math-tagged objects in
|
||||
the scene.
|
||||
To filter out non-related objects one could take it a step further
|
||||
using queries:
|
||||
|
||||
* href: schoolA.edu/projects.gltf#math&q=-topics math
|
||||
* href: schoolB.edu/projects.gltf#math&q=-courses math
|
||||
|
||||
|
||||
|
||||
van Kammen Expires 14 April 2024 [Page 25]
|
||||
|
||||
Internet-Draft XR Fragments October 2023
|
||||
|
||||
|
||||
* href: university.edu/projects.gltf#math&q=-theme math
|
||||
|
||||
| This would hide all object tagged with topic, courses or theme
|
||||
| (including math) so that later only objects tagged with math will
|
||||
| be visible
|
||||
|
||||
This makes spatial content multi-purpose, without the need to
|
||||
separate content into separate files, or show/hide things using a
|
||||
complex logiclayer like javascript.
|
||||
|
||||
16. Security Considerations
|
||||
|
||||
Since XR Text contains metadata too, the user should be able to set
|
||||
up tagging-rules, so the copy-paste feature can :
|
||||
|
@ -1381,7 +1420,7 @@ Internet-Draft XR Fragments September 2023
|
|||
* filter out sensitive data when copy/pasting (XR text with
|
||||
tag:secret e.g.)
|
||||
|
||||
16. FAQ
|
||||
17. FAQ
|
||||
|
||||
*Q:* Why is everything HTTP GET-based, what about POST/PUT/DELETE
|
||||
HATEOS
|
||||
|
@ -1390,38 +1429,50 @@ Internet-Draft XR Fragments September 2023
|
|||
(for example, an XR Hypermedia browser can decide to support
|
||||
POST/PUT/DELETE requests for embedded HTML thru src values)
|
||||
|
||||
*Q:* Why isn't there support for scripting *A:* This is out of scope,
|
||||
and up to the XR hypermedia browser. Javascript seems to been able
|
||||
to turn webpages from hypermedia documents into its opposite
|
||||
(hyperscripted nonhypermedia documents). In order to prevent this
|
||||
|
||||
|
||||
|
||||
van Kammen Expires 25 March 2024 [Page 25]
|
||||
|
||||
Internet-Draft XR Fragments September 2023
|
||||
|
||||
|
||||
backward-movement (hypermedia tends to liberate people from finnicky
|
||||
scripting) XR Fragments should never unhyperify itself by
|
||||
hardcoupling to a particular markup or scripting language. XR
|
||||
Macro's (https://xrfragment.org/doc/RFC_XR_Macros.html) are an
|
||||
example of something which is probably smarter and safer for
|
||||
*Q:* Why isn't there support for scripting, while we have things like
|
||||
WASM *A:* This is out of scope as it unhyperifies hypermedia, and
|
||||
this is up to XR hypermedia browser-extensions.
|
||||
Historically scripting/Javascript seems to been able to turn webpages
|
||||
from hypermedia documents into its opposite (hyperscripted
|
||||
nonhypermedia documents).
|
||||
In order to prevent this backward-movement (hypermedia tends to
|
||||
liberate people from finnicky scripting) XR Fragments should never
|
||||
unhyperify itself by hardcoupling to a particular markup or scripting
|
||||
language. XR Macro's (https://xrfragment.org/doc/RFC_XR_Macros.html)
|
||||
are an example of something which is probably smarter and safer for
|
||||
hypermedia browsers to implement, instead of going full-in with a
|
||||
turing-complete scripting language (and suffer the security
|
||||
consequences later).
|
||||
XR Fragments supports filtering objects in a scene only, because in
|
||||
the history of the javascript-powered web, showing/hiding document-
|
||||
entities seems to be one of the most popular basic usecases.
|
||||
Doing advanced scripting & networkrequests under the hood are
|
||||
obviously interesting endavours, but this is something which should
|
||||
not be hardcoupled with hypermedia.
|
||||
This belongs to browser extensions.
|
||||
|
||||
17. IANA Considerations
|
||||
|
||||
|
||||
van Kammen Expires 14 April 2024 [Page 26]
|
||||
|
||||
Internet-Draft XR Fragments October 2023
|
||||
|
||||
|
||||
Non-HTML Hypermedia browsers should make browser extensions the right
|
||||
place, to 'extend' experiences, in contrast to code/javascript inside
|
||||
hypermedia documents (this turned out as a hypermedia antipattern).
|
||||
|
||||
18. IANA Considerations
|
||||
|
||||
This document has no IANA actions.
|
||||
|
||||
18. Acknowledgments
|
||||
19. Acknowledgments
|
||||
|
||||
* NLNET (https://nlnet.nl)
|
||||
* Future of Text (https://futureoftext.org)
|
||||
* visual-meta.info (https://visual-meta.info)
|
||||
|
||||
19. Appendix: Definitions
|
||||
20. Appendix: Definitions
|
||||
|
||||
+=================+===============================================+
|
||||
| definition | explanation |
|
||||
|
@ -1450,19 +1501,19 @@ Internet-Draft XR Fragments September 2023
|
|||
| spacetime | positions camera, triggers scene-preset/time |
|
||||
| hashtags | |
|
||||
+-----------------+-----------------------------------------------+
|
||||
|
||||
|
||||
|
||||
van Kammen Expires 25 March 2024 [Page 26]
|
||||
|
||||
Internet-Draft XR Fragments September 2023
|
||||
|
||||
|
||||
| teleportation | repositioning the enduser to a different |
|
||||
| | position (or 3D scene/file) |
|
||||
+-----------------+-----------------------------------------------+
|
||||
| sourceportation | teleporting the enduser to the original XR |
|
||||
| | Document of an src embedded object. |
|
||||
|
||||
|
||||
|
||||
van Kammen Expires 14 April 2024 [Page 27]
|
||||
|
||||
Internet-Draft XR Fragments October 2023
|
||||
|
||||
|
||||
+-----------------+-----------------------------------------------+
|
||||
| placeholder | a 3D object which with src-metadata (which |
|
||||
| object | will be replaced by the src-data.) |
|
||||
|
@ -1506,14 +1557,6 @@ Internet-Draft XR Fragments September 2023
|
|||
| BibTag | a BibTeX tag |
|
||||
+-----------------+-----------------------------------------------+
|
||||
| (hashtag)bibs | an easy to speak/type/scan tagging SDL (see |
|
||||
|
||||
|
||||
|
||||
van Kammen Expires 25 March 2024 [Page 27]
|
||||
|
||||
Internet-Draft XR Fragments September 2023
|
||||
|
||||
|
||||
| | here (https://github.com/coderofsalvation/ |
|
||||
| | hashtagbibs) which expands to BibTex/JSON/XML |
|
||||
+-----------------+-----------------------------------------------+
|
||||
|
@ -1522,47 +1565,4 @@ Internet-Draft XR Fragments September 2023
|
|||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
van Kammen Expires 25 March 2024 [Page 28]
|
||||
van Kammen Expires 14 April 2024 [Page 28]
|
||||
|
|
|
@ -10,7 +10,7 @@
|
|||
<workgroup>Internet Engineering Task Force</workgroup>
|
||||
|
||||
<abstract>
|
||||
<t>This draft is a specification for 4D URLs & navigation, which links together space, time & text together, for hypermedia browsers with- or without a network-connection.<br />
|
||||
<t>This draft is a specification for 4D URLs & <eref target="https://github.com/coderofsalvation/hypermediatic">hypermediatic</eref> navigation, which links together space, time & text together, for hypermedia browsers with- or without a network-connection.<br />
|
||||
|
||||
The specification promotes spatial addressibility, sharing, navigation, query-ing and annotating interactive (text)objects across for (XR) Browsers.<br />
|
||||
|
||||
|
@ -28,13 +28,13 @@ XR Fragments allows us to enrich existing dataformats, by recursive use of exist
|
|||
|
||||
Historically, there's many attempts to create the ultimate markuplanguage or 3D fileformat.<br />
|
||||
|
||||
Their lowest common denominator is: (co)authoring using plain text.<br />
|
||||
The lowest common denominator is: describing/tagging/naming nodes using <strong>plain text</strong>.<br />
|
||||
|
||||
XR Fragments allows us to enrich/connect existing dataformats, by introducing existing technologies/ideas:<br />
|
||||
</t>
|
||||
|
||||
<ol spacing="compact">
|
||||
<li>addressibility and navigation of 3D scenes/objects: <eref target="https://en.wikipedia.org/wiki/URI_fragment">URI Fragments</eref> + src/href spatial metadata</li>
|
||||
<li>addressibility and <eref target="https://github.com/coderofsalvation/hypermediatic">hypermediatic</eref> navigation of 3D scenes/objects: <eref target="https://en.wikipedia.org/wiki/URI_fragment">URI Fragments</eref> + src/href spatial metadata</li>
|
||||
<li>Interlinking text/& 3D by collapsing space into a Word Graph (XRWG) to show <eref target="#visible-links">visible links</eref> (and augmenting text with <eref target="https://github.com/coderofsalvation/tagbibs">bibs</eref> / <eref target="https://en.wikipedia.org/wiki/BibTeX">BibTags</eref> appendices (see <eref target="https://visual-meta.info">visual-meta</eref> e.g.)</li>
|
||||
<li>unlocking spatial potential of the (originally 2D) hashtag (which jumps to a chapter) for navigating XR documents</li>
|
||||
</ol>
|
||||
|
@ -132,11 +132,11 @@ But approaches things from a higherlevel feedbackloop/hypermedia browser-perspec
|
|||
<t>Traditional webbrowsers can become 4D document-ready by:</t>
|
||||
|
||||
<ul spacing="compact">
|
||||
<li>loading 3D assets (gltf/fbx e.g.) natively (with or without using HTML).</li>
|
||||
<li><eref target="https://github.com/coderofsalvation/hypermediatic">hypermediatic</eref> loading 3D assets (gltf/fbx e.g.) natively (with or without using HTML).</li>
|
||||
<li>allowing assets to publish hashtags to themselves (the scene) using the hashbus (like hashtags controlling the scrollbar).</li>
|
||||
<li>collapsing the 3D scene to an wordgraph (for essential navigation purposes) controllable thru a hash(tag)bus</li>
|
||||
</ul>
|
||||
<t>XR Fragments itself are HTML-agnostic, though pseudo-XR Fragment browsers <strong>can</strong> be implemented on top of HTML/Javascript.</t>
|
||||
<t>XR Fragments itself are <eref target="https://github.com/coderofsalvation/hypermediatic">hypermediatic</eref> and HTML-agnostic, though pseudo-XR Fragment browsers <strong>can</strong> be implemented on top of HTML/Javascript.</t>
|
||||
</section>
|
||||
|
||||
<section anchor="conventions-and-definitions"><name>Conventions and Definitions</name>
|
||||
|
@ -200,9 +200,9 @@ sub-delims = "," / "="
|
|||
|
||||
<tr>
|
||||
<td><tt>#t</tt></td>
|
||||
<td>vector2</td>
|
||||
<td><tt>#t=500,1000</tt></td>
|
||||
<td>sets animation-loop range between frame 500 and 1000</td>
|
||||
<td>vector3</td>
|
||||
<td><tt>#t=1,500,1000</tt></td>
|
||||
<td>play animation-loop range between frame 500 and 1000, at normal speed</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
|
@ -228,22 +228,6 @@ sub-delims = "," / "="
|
|||
</thead>
|
||||
|
||||
<tbody>
|
||||
<tr>
|
||||
<td><tt>name</tt></td>
|
||||
<td>string</td>
|
||||
<td><tt>"name": "cube"</tt></td>
|
||||
<td>identify/tag</td>
|
||||
<td>object supported in all 3D fileformats & scenes</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td><tt>tag</tt></td>
|
||||
<td>string</td>
|
||||
<td><tt>"tag": "cubes geo"</tt></td>
|
||||
<td>tag object</td>
|
||||
<td>custom property in 3D fileformats</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td><tt>href</tt></td>
|
||||
<td>string</td>
|
||||
|
@ -259,12 +243,21 @@ sub-delims = "," / "="
|
|||
<td>XR embed / teleport</td>
|
||||
<td>custom property in 3D fileformats</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td><tt>tag</tt></td>
|
||||
<td>string</td>
|
||||
<td><tt>"tag": "cubes geo"</tt></td>
|
||||
<td>tag object (for query-use / XRWG highlighting)</td>
|
||||
<td>custom property in 3D fileformats</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table><t>Supported popular compatible 3D fileformats: <tt>.gltf</tt>, <tt>.obj</tt>, <tt>.fbx</tt>, <tt>.usdz</tt>, <tt>.json</tt> (THREE.js), <tt>.dae</tt> and so on.</t>
|
||||
<blockquote><t>NOTE: XR Fragments are file-agnostic, which means that the metadata exist in programmatic 3D scene(nodes) too.</t>
|
||||
<blockquote><t>NOTE: XR Fragments are optional but also file- and protocol-agnostic, which means that programmatic 3D scene(nodes) can also use the mechanism/metadata.</t>
|
||||
</blockquote></section>
|
||||
|
||||
<section anchor="spatial-referencing-3d"><name>Spatial Referencing 3D</name>
|
||||
<t>XR Fragments assume the following objectname-to-URIFragment mapping:</t>
|
||||
|
||||
<artwork>
|
||||
my.io/scene.fbx
|
||||
|
@ -283,7 +276,8 @@ sub-delims = "," / "="
|
|||
+─────────────────────────────+
|
||||
|
||||
</artwork>
|
||||
<t>Clever nested design of 3D scenes allow great ways for re-using content, and/or previewing scenes.<br />
|
||||
<blockquote><t>Every 3D fileformat supports named 3D object, and this name allows URLs (fragments) to reference them (and their children objects).</t>
|
||||
</blockquote><t>Clever nested design of 3D scenes allow great ways for re-using content, and/or previewing scenes.<br />
|
||||
|
||||
For example, to render a portal with a preview-version of the scene, create an 3D object with:</t>
|
||||
|
||||
|
@ -291,7 +285,7 @@ For example, to render a portal with a preview-version of the scene, create an 3
|
|||
<li>href: <tt>https://scene.fbx</tt></li>
|
||||
<li>src: <tt>https://otherworld.gltf#mainobject</tt></li>
|
||||
</ul>
|
||||
<blockquote><t>It also allows <strong>sourceportation</strong>, which basically means the enduser can teleport to the original XR Document of an <tt>src</tt> embedded object, and see a visible connection to the particular embedded object.</t>
|
||||
<blockquote><t>It also allows <strong>sourceportation</strong>, which basically means the enduser can teleport to the original XR Document of an <tt>src</tt> embedded object, and see a visible connection to the particular embedded object. Basically an embedded link becoming an outbound link by activating it.</t>
|
||||
</blockquote></section>
|
||||
|
||||
<section anchor="navigating-3d"><name>Navigating 3D</name>
|
||||
|
@ -313,8 +307,8 @@ For example, to render a portal with a preview-version of the scene, create an 3
|
|||
|
||||
<tr>
|
||||
<td><b>#t</b>=0,100</td>
|
||||
<td>vector2</td>
|
||||
<td>(re)position looprange of scene-animation or <tt>src</tt>-mediacontent</td>
|
||||
<td>vector3</td>
|
||||
<td>set playback speed, and (re)position looprange of scene-animation or <tt>src</tt>-mediacontent</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
|
@ -332,7 +326,7 @@ For example, to render a portal with a preview-version of the scene, create an 3
|
|||
<li>the Y-coordinate of <tt>pos</tt> identifies the floorposition. This means that desktop-projections usually need to add 1.5m (average person height) on top (which is done automatically by VR/AR headsets).</li>
|
||||
<li>set the position of the camera accordingly to the vector3 values of <tt>#pos</tt></li>
|
||||
<li><tt>rot</tt> sets the rotation of the camera (only for non-VR/AR headsets)</li>
|
||||
<li><tt>t</tt> sets the animation-range of the current scene animation(s) or <tt>src</tt>-mediacontent (video/audioframes e.g., use <tt>t=7,7</tt> to 'STOP' at certain frame)</li>
|
||||
<li><tt>t</tt> sets the playbackspeed and animation-range of the current scene animation(s) or <tt>src</tt>-mediacontent (video/audioframes e.g., use <tt>t=0,7,7</tt> to 'STOP' at frame 7 e.g.)</li>
|
||||
<li>in case an <tt>href</tt> does not mention any <tt>pos</tt>-coordinate, <tt>pos=0,0,0</tt> will be assumed</li>
|
||||
</ol>
|
||||
<t>Here's an ascii representation of a 3D scene-graph which contains 3D objects <tt>◻</tt> and their metadata:</t>
|
||||
|
@ -450,7 +444,7 @@ Resizing will be happen accordingly to its placeholder object <tt>aquariumcube</
|
|||
</t>
|
||||
</section>
|
||||
|
||||
<section anchor="navigating-content-href-portals"><name>Navigating content (href portals)</name>
|
||||
<section anchor="navigating-content-internal-outbound-href-portals"><name>Navigating content (internal/outbound href portals)</name>
|
||||
<t>navigation, portals & mutations</t>
|
||||
<table>
|
||||
<thead>
|
||||
|
@ -473,7 +467,7 @@ Resizing will be happen accordingly to its placeholder object <tt>aquariumcube</
|
|||
</tbody>
|
||||
</table>
|
||||
<ol>
|
||||
<li><t>clicking an ''external''- or ''file URI'' fully replaces the current scene and assumes <tt>pos=0,0,0&rot=0,0,0</tt> by default (unless specified)</t>
|
||||
<li><t>clicking an outbound ''external''- or ''file URI'' fully replaces the current scene and assumes <tt>pos=0,0,0&rot=0,0,0</tt> by default (unless specified)</t>
|
||||
</li>
|
||||
<li><t>relocation/reorientation should happen locally for local URI's (<tt>#pos=....</tt>)</t>
|
||||
</li>
|
||||
|
@ -943,15 +937,16 @@ here are some hashtagbibs followed by bibtex:
|
|||
</blockquote></section>
|
||||
</section>
|
||||
|
||||
<section anchor="broken-links"><name>Broken links</name>
|
||||
<t>There's a soft-mechanism to harden links & prevent broken links in various ways:</t>
|
||||
<section anchor="transclusion-broken-link-resolution"><name>Transclusion (broken link) resolution</name>
|
||||
<t>In spirit of Ted Nelson's 'transclusion resolution', there's a soft-mechanism to harden links & minimize broken links in various ways:</t>
|
||||
|
||||
<ol spacing="compact">
|
||||
<li>defining a different transport protocol (https vs ipfs or DAT) in <tt>src</tt> or <tt>href</tt> values can make a difference</li>
|
||||
<li>mirroring files on another protocol using errorcodes in <tt>src</tt> or <tt>href</tt> properties</li>
|
||||
<li>mirroring files on another protocol using (HTTP) errorcode tags in <tt>src</tt> or <tt>href</tt> properties</li>
|
||||
<li>in case of <tt>src</tt>: nesting a copy of the embedded object in the placeholder object (<tt>embeddedObject</tt>) will not be replaced when the request fails</li>
|
||||
</ol>
|
||||
<t>For example:</t>
|
||||
<blockquote><t>due to the popularity, maturity and extensiveness of HTTP codes for client/server communication, non-HTTP protocols easily map to HTTP codes (ipfs ERR_NOT_FOUND maps to 404 e.g.)</t>
|
||||
</blockquote><t>For example:</t>
|
||||
|
||||
<artwork> +────────────────────────────────────────────────────────+
|
||||
│ │
|
||||
|
@ -961,20 +956,43 @@ here are some hashtagbibs followed by bibtex:
|
|||
│ │ │
|
||||
│ ├── ◻ buttonA │
|
||||
│ │ └ href: http://foo.io/campagne.fbx │
|
||||
│ │ └ href!404: ipfs://foo.io/campagne.fbx │
|
||||
│ │ └ href!400: #q=clienterrortext │
|
||||
│ │ └ href@404: ipfs://foo.io/campagne.fbx │
|
||||
│ │ └ href@400: #q=clienterrortext │
|
||||
│ │ └ ◻ offlinetext │
|
||||
│ │ │
|
||||
│ └── ◻ embeddedObject <--------- the meshdata inside embeddedObject will (not)
|
||||
│ └ src: https://foo.io/bar.gltf │ be flushed when the request (does not) succeed.
|
||||
│ └ src!404: http://foo.io/bar.gltf │ So worstcase the 3D data (of the time of publishing index.gltf)
|
||||
│ └ src!400: https://archive.org/l2kj43.gltf │ will be displayed.
|
||||
│ └ src@404: http://foo.io/bar.gltf │ So worstcase the 3D data (of the time of publishing index.gltf)
|
||||
│ └ src@400: https://archive.org/l2kj43.gltf │ will be displayed.
|
||||
│ │
|
||||
+────────────────────────────────────────────────────────+
|
||||
|
||||
</artwork>
|
||||
</section>
|
||||
|
||||
<section anchor="topic-based-index-less-webrings"><name>Topic-based index-less Webrings</name>
|
||||
<t>As hashtags in URLs map to the XWRG, <tt>href</tt>-values can be used to promote topic-based index-less webrings.<br />
|
||||
|
||||
Consider 3D scenes linking to eachother using these <tt>href</tt> values:</t>
|
||||
|
||||
<ul spacing="compact">
|
||||
<li><tt>href: schoolA.edu/projects.gltf#math</tt></li>
|
||||
<li><tt>href: schoolB.edu/projects.gltf#math</tt></li>
|
||||
<li><tt>href: university.edu/projects.gltf#math</tt></li>
|
||||
</ul>
|
||||
<t>These links would all show visible links to math-tagged objects in the scene.<br />
|
||||
|
||||
To filter out non-related objects one could take it a step further using queries:</t>
|
||||
|
||||
<ul spacing="compact">
|
||||
<li><tt>href: schoolA.edu/projects.gltf#math&q=-topics math</tt></li>
|
||||
<li><tt>href: schoolB.edu/projects.gltf#math&q=-courses math</tt></li>
|
||||
<li><tt>href: university.edu/projects.gltf#math&q=-theme math</tt></li>
|
||||
</ul>
|
||||
<blockquote><t>This would hide all object tagged with <tt>topic</tt>, <tt>courses</tt> or <tt>theme</tt> (including math) so that later only objects tagged with <tt>math</tt> will be visible</t>
|
||||
</blockquote><t>This makes spatial content multi-purpose, without the need to separate content into separate files, or show/hide things using a complex logiclayer like javascript.</t>
|
||||
</section>
|
||||
|
||||
<section anchor="security-considerations"><name>Security Considerations</name>
|
||||
<t>Since XR Text contains metadata too, the user should be able to set up tagging-rules, so the copy-paste feature can :</t>
|
||||
|
||||
|
@ -987,8 +1005,17 @@ here are some hashtagbibs followed by bibtex:
|
|||
<t><strong>Q:</strong> Why is everything HTTP GET-based, what about POST/PUT/DELETE HATEOS<br />
|
||||
|
||||
<strong>A:</strong> Because it's out of scope: XR Fragment specifies a read-only way to surf XR documents. These things belong in the application layer (for example, an XR Hypermedia browser can decide to support POST/PUT/DELETE requests for embedded HTML thru <tt>src</tt> values)</t>
|
||||
<t><strong>Q:</strong> Why isn't there support for scripting
|
||||
<strong>A:</strong> This is out of scope, and up to the XR hypermedia browser. Javascript seems to been able to turn webpages from hypermedia documents into its opposite (hyperscripted nonhypermedia documents). In order to prevent this backward-movement (hypermedia tends to liberate people from finnicky scripting) XR Fragments should never unhyperify itself by hardcoupling to a particular markup or scripting language. <eref target="https://xrfragment.org/doc/RFC_XR_Macros.html">XR Macro's</eref> are an example of something which is probably smarter and safer for hypermedia browsers to implement, instead of going full-in with a turing-complete scripting language (and suffer the security consequences later).</t>
|
||||
<t><strong>Q:</strong> Why isn't there support for scripting, while we have things like WASM
|
||||
<strong>A:</strong> This is out of scope as it unhyperifies hypermedia, and this is up to XR hypermedia browser-extensions.<br />
|
||||
Historically scripting/Javascript seems to been able to turn webpages from hypermedia documents into its opposite (hyperscripted nonhypermedia documents).<br />
|
||||
In order to prevent this backward-movement (hypermedia tends to liberate people from finnicky scripting) XR Fragments should never unhyperify itself by hardcoupling to a particular markup or scripting language. <eref target="https://xrfragment.org/doc/RFC_XR_Macros.html">XR Macro's</eref> are an example of something which is probably smarter and safer for hypermedia browsers to implement, instead of going full-in with a turing-complete scripting language (and suffer the security consequences later).<br />
|
||||
|
||||
XR Fragments supports filtering objects in a scene only, because in the history of the javascript-powered web, showing/hiding document-entities seems to be one of the most popular basic usecases.<br />
|
||||
|
||||
Doing advanced scripting & networkrequests under the hood are obviously interesting endavours, but this is something which should not be hardcoupled with hypermedia.<br />
|
||||
This belongs to browser extensions.<br />
|
||||
|
||||
Non-HTML Hypermedia browsers should make browser extensions the right place, to 'extend' experiences, in contrast to code/javascript inside hypermedia documents (this turned out as a hypermedia antipattern).</t>
|
||||
</section>
|
||||
|
||||
<section anchor="iana-considerations"><name>IANA Considerations</name>
|
||||
|
|
|
@ -129,6 +129,52 @@ Macros enrich existing spatial content with a lowcode, limited logic-layer, by r
|
|||
This is done by allowing string/integer variables, and the <code>|</code> symbol to roundrobin variable values.<br>
|
||||
Macros also act as events, so more serious scripting languages can react to them as well.<br></p>
|
||||
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>key</th>
|
||||
<th>type</th>
|
||||
<th>example (JSON)</th>
|
||||
<th>function</th>
|
||||
<th>existing compatibility</th>
|
||||
</tr>
|
||||
</thead>
|
||||
|
||||
<tbody>
|
||||
<tr>
|
||||
<td><code>@bg</code></td>
|
||||
<td>string</td>
|
||||
<td><code>"@bg":"#cube"</code></td>
|
||||
<td>bg: binds fog near/far based to cube x/y/z (anim) values</td>
|
||||
<td>custom property in 3D fileformats</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td><code>@fog</code></td>
|
||||
<td>string</td>
|
||||
<td><code>"@fog":"#cube"</code></td>
|
||||
<td>fog: binds fog near/far based to cube x/y (anim) values</td>
|
||||
<td>custom property in 3D fileformats</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td><code>@scroll</code></td>
|
||||
<td>string</td>
|
||||
<td><code>"@scroll":"#cube"</code></td>
|
||||
<td>texturescrolling: binds texture x/y/rot based to cube x/y/z (anim) values</td>
|
||||
<td>custom property in 3D fileformats</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td><code>@emissive</code></td>
|
||||
<td>string</td>
|
||||
<td><code>"@emissive":"#cube"</code></td>
|
||||
<td>day/night/mood: binds material’s emissive value to cube x/y/z (anim) values</td>
|
||||
<td>custom property in 3D fileformats</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
<h2 id="usecase-click-object">Usecase: click object</h2>
|
||||
|
||||
<table>
|
||||
|
|
|
@ -134,6 +134,13 @@ Macros enrich existing spatial content with a lowcode, limited logic-layer, by r
|
|||
This is done by allowing string/integer variables, and the `|` symbol to roundrobin variable values.<br>
|
||||
Macros also act as events, so more serious scripting languages can react to them as well.<br>
|
||||
|
||||
| key | type | example (JSON) | function | existing compatibility |
|
||||
|--------------|----------|------------------------|---------------------|----------------------------------------|
|
||||
| `@bg` | string | `"@bg":"#cube"` | bg: binds fog near/far based to cube x/y/z (anim) values | custom property in 3D fileformats |
|
||||
| `@fog` | string | `"@fog":"#cube"` | fog: binds fog near/far based to cube x/y (anim) values | custom property in 3D fileformats |
|
||||
| `@scroll` | string | `"@scroll":"#cube"` | texturescrolling: binds texture x/y/rot based to cube x/y/z (anim) values | custom property in 3D fileformats |
|
||||
| `@emissive` | string | `"@emissive":"#cube"` | day/night/mood: binds material's emissive value to cube x/y/z (anim) values | custom property in 3D fileformats |
|
||||
|
||||
## Usecase: click object
|
||||
|
||||
| custom property | value | trigger when |
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
|
||||
|
||||
Internet Engineering Task Force L.R. van Kammen
|
||||
Internet-Draft 22 September 2023
|
||||
Internet-Draft 12 October 2023
|
||||
Intended status: Informational
|
||||
|
||||
|
||||
|
@ -38,7 +38,7 @@ Status of This Memo
|
|||
time. It is inappropriate to use Internet-Drafts as reference
|
||||
material or to cite them other than as "work in progress."
|
||||
|
||||
This Internet-Draft will expire on 25 March 2024.
|
||||
This Internet-Draft will expire on 14 April 2024.
|
||||
|
||||
Copyright Notice
|
||||
|
||||
|
@ -53,9 +53,9 @@ Copyright Notice
|
|||
|
||||
|
||||
|
||||
van Kammen Expires 25 March 2024 [Page 1]
|
||||
van Kammen Expires 14 April 2024 [Page 1]
|
||||
|
||||
Internet-Draft XR Macros September 2023
|
||||
Internet-Draft XR Macros October 2023
|
||||
|
||||
|
||||
extracted from this document must include Revised BSD License text as
|
||||
|
@ -68,17 +68,17 @@ Table of Contents
|
|||
2. Core principle . . . . . . . . . . . . . . . . . . . . . . . 2
|
||||
3. Conventions and Definitions . . . . . . . . . . . . . . . . . 3
|
||||
4. List of XR Macros . . . . . . . . . . . . . . . . . . . . . . 3
|
||||
4.1. Usecase: click object . . . . . . . . . . . . . . . . . . 3
|
||||
4.2. Usecase: conditional click object . . . . . . . . . . . . 3
|
||||
4.3. Usecase: click object (roundrobin) . . . . . . . . . . . 4
|
||||
4.1. Usecase: click object . . . . . . . . . . . . . . . . . . 4
|
||||
4.2. Usecase: conditional click object . . . . . . . . . . . . 4
|
||||
4.3. Usecase: click object (roundrobin) . . . . . . . . . . . 5
|
||||
4.4. Usecase: click object or URI fragment, and scene load
|
||||
trigger . . . . . . . . . . . . . . . . . . . . . . . . . 4
|
||||
4.5. Usecase: present context menu with options . . . . . . . 5
|
||||
4.6. Event Bubble-flow . . . . . . . . . . . . . . . . . . . . 5
|
||||
5. Security Considerations . . . . . . . . . . . . . . . . . . . 6
|
||||
6. IANA Considerations . . . . . . . . . . . . . . . . . . . . . 6
|
||||
7. Acknowledgments . . . . . . . . . . . . . . . . . . . . . . . 6
|
||||
8. Appendix: Definitions . . . . . . . . . . . . . . . . . . . . 6
|
||||
trigger . . . . . . . . . . . . . . . . . . . . . . . . . 5
|
||||
4.5. Usecase: present context menu with options . . . . . . . 6
|
||||
4.6. Event Bubble-flow . . . . . . . . . . . . . . . . . . . . 6
|
||||
5. Security Considerations . . . . . . . . . . . . . . . . . . . 7
|
||||
6. IANA Considerations . . . . . . . . . . . . . . . . . . . . . 7
|
||||
7. Acknowledgments . . . . . . . . . . . . . . . . . . . . . . . 7
|
||||
8. Appendix: Definitions . . . . . . . . . . . . . . . . . . . . 7
|
||||
|
||||
1. Introduction
|
||||
|
||||
|
@ -109,9 +109,9 @@ Table of Contents
|
|||
|
||||
|
||||
|
||||
van Kammen Expires 25 March 2024 [Page 2]
|
||||
van Kammen Expires 14 April 2024 [Page 2]
|
||||
|
||||
Internet-Draft XR Macros September 2023
|
||||
Internet-Draft XR Macros October 2023
|
||||
|
||||
|
||||
3. Metadata-values can contain the | symbol to 🎲 roundrobin
|
||||
|
@ -144,6 +144,61 @@ Internet-Draft XR Macros September 2023
|
|||
Macros also act as events, so more serious scripting languages can
|
||||
react to them as well.
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
van Kammen Expires 14 April 2024 [Page 3]
|
||||
|
||||
Internet-Draft XR Macros October 2023
|
||||
|
||||
|
||||
+=========+======+===================+=================+=============+
|
||||
|key |type |example (JSON) |function |existing |
|
||||
| | | | |compatibility|
|
||||
+=========+======+===================+=================+=============+
|
||||
|@bg |string|"@bg":"#cube" |bg: binds fog |custom |
|
||||
| | | |near/far based to|property in |
|
||||
| | | |cube x/y/z (anim)|3D |
|
||||
| | | |values |fileformats |
|
||||
+---------+------+-------------------+-----------------+-------------+
|
||||
|@fog |string|"@fog":"#cube" |fog: binds fog |custom |
|
||||
| | | |near/far based to|property in |
|
||||
| | | |cube x/y (anim) |3D |
|
||||
| | | |values |fileformats |
|
||||
+---------+------+-------------------+-----------------+-------------+
|
||||
|@scroll |string|"@scroll":"#cube" |texturescrolling:|custom |
|
||||
| | | |binds texture |property in |
|
||||
| | | |x/y/rot based to |3D |
|
||||
| | | |cube x/y/z (anim)|fileformats |
|
||||
| | | |values | |
|
||||
+---------+------+-------------------+-----------------+-------------+
|
||||
|@emissive|string|"@emissive":"#cube"|day/night/mood: |custom |
|
||||
| | | |binds material's |property in |
|
||||
| | | |emissive value to|3D |
|
||||
| | | |cube x/y/z (anim)|fileformats |
|
||||
| | | |values | |
|
||||
+---------+------+-------------------+-----------------+-------------+
|
||||
|
||||
Table 1
|
||||
|
||||
4.1. Usecase: click object
|
||||
|
||||
+=================+================+================+
|
||||
|
@ -152,7 +207,7 @@ Internet-Draft XR Macros September 2023
|
|||
| !clickme | bg=1,1,1&foo=2 | object clicked |
|
||||
+-----------------+----------------+----------------+
|
||||
|
||||
Table 1
|
||||
Table 2
|
||||
|
||||
4.2. Usecase: conditional click object
|
||||
|
||||
|
@ -162,17 +217,16 @@ Internet-Draft XR Macros September 2023
|
|||
| # | foo=1 | scene |
|
||||
+-----------------+------------------+----------------------------+
|
||||
| !clickme | q=foo>2&bg=1,1,1 | object clicked and foo > 2 |
|
||||
|
||||
|
||||
|
||||
van Kammen Expires 25 March 2024 [Page 3]
|
||||
|
||||
Internet-Draft XR Macros September 2023
|
||||
|
||||
|
||||
+-----------------+------------------+----------------------------+
|
||||
|
||||
Table 2
|
||||
|
||||
|
||||
van Kammen Expires 14 April 2024 [Page 4]
|
||||
|
||||
Internet-Draft XR Macros October 2023
|
||||
|
||||
|
||||
Table 3
|
||||
|
||||
| when a user clicks an object with the custom properties above, it
|
||||
| should set the backgroundcolor to 1,1,1 when foo is greater than 2
|
||||
|
@ -192,7 +246,7 @@ Internet-Draft XR Macros September 2023
|
|||
| night | bg=0,0,0&foo=2 | roundrobin |
|
||||
+-----------------+----------------+----------------+
|
||||
|
||||
Table 3
|
||||
Table 4
|
||||
|
||||
| when a user clicks an object with the custom properties above, it
|
||||
| should trigger either day noon or night in roundrobin fashion.
|
||||
|
@ -215,15 +269,17 @@ Internet-Draft XR Macros September 2023
|
|||
| night | bg=0,0,0&foo=2 | roundrobin |
|
||||
+-----------------+----------------+----------------------+
|
||||
|
||||
Table 4
|
||||
Table 5
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
van Kammen Expires 25 March 2024 [Page 4]
|
||||
|
||||
|
||||
van Kammen Expires 14 April 2024 [Page 5]
|
||||
|
||||
Internet-Draft XR Macros September 2023
|
||||
Internet-Draft XR Macros October 2023
|
||||
|
||||
|
||||
4.5. Usecase: present context menu with options
|
||||
|
@ -240,7 +296,7 @@ Internet-Draft XR Macros September 2023
|
|||
| !night | bg=0,0,0&foo=2 | clicked in contextmenu |
|
||||
+-----------------+----------------+------------------------+
|
||||
|
||||
Table 5
|
||||
Table 6
|
||||
|
||||
| When interacting with an object with more than one !-macro, the XR
|
||||
| Browser should offer a contextmenu to execute a macro.
|
||||
|
@ -277,9 +333,9 @@ click object with (`!clickme`:`!foo|!bar|!flop` e.g.)
|
|||
|
||||
|
||||
|
||||
van Kammen Expires 25 March 2024 [Page 5]
|
||||
van Kammen Expires 14 April 2024 [Page 6]
|
||||
|
||||
Internet-Draft XR Macros September 2023
|
||||
Internet-Draft XR Macros October 2023
|
||||
|
||||
|
||||
| Note that only macro's can trigger roundrobin values or
|
||||
|
@ -326,11 +382,11 @@ Internet-Draft XR Macros September 2023
|
|||
| | a salad of machine-symbols and words |
|
||||
+---------------+---------------------------------------------------+
|
||||
|
||||
Table 6
|
||||
Table 7
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
van Kammen Expires 25 March 2024 [Page 6]
|
||||
van Kammen Expires 14 April 2024 [Page 7]
|
||||
|
|
|
@ -63,7 +63,51 @@ This is done by allowing string/integer variables, and the <tt>|</tt> symbol to
|
|||
|
||||
Macros also act as events, so more serious scripting languages can react to them as well.<br />
|
||||
</t>
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>key</th>
|
||||
<th>type</th>
|
||||
<th>example (JSON)</th>
|
||||
<th>function</th>
|
||||
<th>existing compatibility</th>
|
||||
</tr>
|
||||
</thead>
|
||||
|
||||
<tbody>
|
||||
<tr>
|
||||
<td><tt>@bg</tt></td>
|
||||
<td>string</td>
|
||||
<td><tt>"@bg":"#cube"</tt></td>
|
||||
<td>bg: binds fog near/far based to cube x/y/z (anim) values</td>
|
||||
<td>custom property in 3D fileformats</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td><tt>@fog</tt></td>
|
||||
<td>string</td>
|
||||
<td><tt>"@fog":"#cube"</tt></td>
|
||||
<td>fog: binds fog near/far based to cube x/y (anim) values</td>
|
||||
<td>custom property in 3D fileformats</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td><tt>@scroll</tt></td>
|
||||
<td>string</td>
|
||||
<td><tt>"@scroll":"#cube"</tt></td>
|
||||
<td>texturescrolling: binds texture x/y/rot based to cube x/y/z (anim) values</td>
|
||||
<td>custom property in 3D fileformats</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td><tt>@emissive</tt></td>
|
||||
<td>string</td>
|
||||
<td><tt>"@emissive":"#cube"</tt></td>
|
||||
<td>day/night/mood: binds material's emissive value to cube x/y/z (anim) values</td>
|
||||
<td>custom property in 3D fileformats</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<section anchor="usecase-click-object"><name>Usecase: click object</name>
|
||||
<table>
|
||||
<thead>
|
||||
|
|
|
@ -12,16 +12,19 @@
|
|||
<script src="./../../../dist/xrfragment.aframe.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<div id="overlay">
|
||||
<div id="overlay" style="display:none">
|
||||
<img src="./../../assets/logo.png" class="logo"/>
|
||||
<button id="navback" onclick="history.back()"><</button>
|
||||
<button id="navforward" onclick="history.forward()">></button>
|
||||
<input type="submit" value="load 3D asset"></input>
|
||||
<input type="submit" value="load 3D file"></input>
|
||||
<input type="text" id="uri" value="" onchange="AFRAME.XRF.navigator.to( $('#uri').value )"/>
|
||||
</div>
|
||||
|
||||
<!-- open AFRAME inspector: $('a-scene').components.inspector.openInspector() -->
|
||||
<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="example.gltf">⬇️ model</a>
|
||||
<a class="btn-foot" id="more" target="_blank">XRF</a>
|
||||
<textarea style="display:none"></textarea>
|
||||
<a-scene light="defaultLightsEnabled: false">
|
||||
<a-entity id="player" wasd-controls look-controls>
|
||||
|
|
|
@ -73,7 +73,6 @@ input[type="submit"] {
|
|||
}
|
||||
|
||||
#overlay > #uri {
|
||||
display:none;
|
||||
height: 29px;
|
||||
font-size: 21px;
|
||||
position: absolute;
|
||||
|
@ -92,25 +91,40 @@ input[type="submit"] {
|
|||
border: 5px solid #1c1c3299;
|
||||
padding: 0px 6px;
|
||||
position: absolute;
|
||||
font-weight: bold;
|
||||
font-weight: 1000;
|
||||
font-family: sans-serif;
|
||||
color: #7c7c7c;
|
||||
font-size:17px;
|
||||
color: #888;
|
||||
height:43px;
|
||||
z-index:2000;
|
||||
cursor:pointer;
|
||||
right: 10px;
|
||||
text-transform:uppercase;
|
||||
}
|
||||
|
||||
a.btn-foot#embed{
|
||||
color: #888;
|
||||
bottom: 126px;
|
||||
bottom: 129px;
|
||||
}
|
||||
|
||||
a.btn-foot#model{
|
||||
bottom:73px;
|
||||
bottom:72px;
|
||||
}
|
||||
|
||||
a.btn-foot#more{
|
||||
bottom:72px;
|
||||
width: 60px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
a.btn-foot#source{
|
||||
bottom:179px;
|
||||
bottom:186px;
|
||||
}
|
||||
|
||||
a#source,
|
||||
a#embed,
|
||||
a#model{
|
||||
display:none
|
||||
}
|
||||
|
||||
html.a-fullscreen a.btn-foot {
|
||||
|
@ -251,3 +265,7 @@ html{
|
|||
background-color: #4443;
|
||||
}
|
||||
|
||||
.a-enter-vr-button, .a-enter-ar-button{
|
||||
height:41px;
|
||||
}
|
||||
|
||||
|
|
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
|
@ -54,17 +54,22 @@ export function setupConsole(el){
|
|||
}
|
||||
|
||||
export function setupUrlBar(el,XRF){
|
||||
|
||||
var isIframe = (window === window.parent || window.opener) ? false : true;
|
||||
if( isIframe || document.location.href.match(/localhost/) ){
|
||||
// show internal URL bar to test XR fragments interactively
|
||||
el.style.display = 'block'
|
||||
|
||||
XRF.addEventListener('updateHash', () => reflectUrl() )
|
||||
|
||||
const reflectUrl = (url) => el.value = url || document.location.search.substr(1) + document.location.hash
|
||||
reflectUrl()
|
||||
var isIframe = document.location.hash.match(/embed=1/)
|
||||
let ids = ['#overlay','a#embed','a#source','a#model']
|
||||
let showButtons = () => {
|
||||
ids.map( (i) => $(i).style.display = 'block' )
|
||||
$('a#more').style.display = 'none'
|
||||
}
|
||||
if( isIframe ){
|
||||
// show internal URL bar & backbuttons to test XR fragments interactively
|
||||
showButtons()
|
||||
}else{
|
||||
$('a#more').addEventListener('click', () => showButtons() )
|
||||
}
|
||||
|
||||
XRF.addEventListener('updateHash', () => reflectUrl() )
|
||||
const reflectUrl = (url) => el.value = url || document.location.search.substr(1) + document.location.hash
|
||||
reflectUrl()
|
||||
}
|
||||
|
||||
function SnackBar(userOptions) {
|
||||
|
|
|
@ -10,12 +10,15 @@
|
|||
<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="submit" value="load 3D file"></input>
|
||||
<input type="text" id="uri" value="" onchange="XRF.navigator.to( $('#uri').value )"/>
|
||||
</div>
|
||||
|
||||
<!-- open AFRAME inspector: $('a-scene').components.inspector.openInspector() -->
|
||||
<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>
|
||||
<a class="btn-foot" id="more" target="_blank" href="index.gltf">XRF</a>
|
||||
<textarea style="display:none"></textarea>
|
||||
|
||||
<script async src="./../../assets/js/alpine.min.js"></script>
|
||||
|
|
35
index.html
35
index.html
File diff suppressed because one or more lines are too long
|
@ -12,9 +12,9 @@ window.AFRAME.registerComponent('xrf', {
|
|||
let aScene = document.querySelector('a-scene')
|
||||
let XRF = AFRAME.XRF = xrf.init({
|
||||
THREE,
|
||||
camera: aScene.camera,
|
||||
scene: aScene.object3D,
|
||||
renderer: aScene.renderer,
|
||||
camera: aScene.camera,
|
||||
scene: aScene.object3D,
|
||||
renderer: aScene.renderer,
|
||||
debug: true,
|
||||
loaders: {
|
||||
gltf: THREE.GLTFLoader, // which 3D assets (exts) to check for XR fragments?
|
||||
|
|
|
@ -32,7 +32,7 @@ xrf.InteractiveGroup = function(THREE,renderer,camera){
|
|||
function nocollide(){
|
||||
if( nocollide.tid ) return // ratelimit
|
||||
_event.type = "nocollide"
|
||||
scope.children.map( (c) => c.dispatchEvent(_event) )
|
||||
scope.objects.map( (c) => c.dispatchEvent(_event) )
|
||||
nocollide.tid = setTimeout( () => nocollide.tid = null, 100 )
|
||||
}
|
||||
|
||||
|
|
|
@ -34,6 +34,7 @@ pub.mesh = (mesh,model) => { // evaluate embedded fragments (metadata) insid
|
|||
|
||||
pub.fragment = (k, opts ) => { // evaluate one fragment
|
||||
let frag = opts.frag[k];
|
||||
|
||||
// call native function (xrf/env.js e.g.), or pass it to user decorator
|
||||
xrf.emit(k,opts)
|
||||
.then( () => {
|
||||
|
|
|
@ -52,6 +52,7 @@ xrf.parseModel = function(model,url){
|
|||
model.mixer = new xrf.THREE.AnimationMixer(model.scene)
|
||||
model.animations.map( (anim) => {
|
||||
anim.action = model.mixer.clipAction( anim )
|
||||
//anim.action.setLoop(0)
|
||||
anim.action.play()
|
||||
})
|
||||
|
||||
|
@ -65,9 +66,10 @@ xrf.parseModel = function(model,url){
|
|||
xrf.focusLine.material.dashSize = 0.2 + 0.02*Math.sin( model.clock.getElapsedTime() )
|
||||
xrf.focusLine.material.gapSize = 0.1 + 0.02*Math.sin( model.clock.getElapsedTime() *3 )
|
||||
xrf.focusLine.material.opacity = (0.25 + 0.15*Math.sin( model.clock.getElapsedTime() * 3 )) * xrf.focusLine.opacity;
|
||||
if( xrf.focusLine.opacity > 0.0 ) xrf.focusLine.opacity -= time*0.3
|
||||
if( xrf.focusLine.opacity > 0.0 ) xrf.focusLine.opacity -= time*0.2
|
||||
if( xrf.focusLine.opacity < 0.0 ) xrf.focusLine.opacity = 0
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
xrf.getLastModel = () => xrf.model.last
|
||||
|
|
|
@ -35,8 +35,12 @@ xrf.navigator.to = (url,flags,loader,data) => {
|
|||
xrf.XRWG.generate({model,scene:model.scene})
|
||||
// spec: 1. execute the default predefined view '#' (if exist) (https://xrfragment.org/#predefined_view)
|
||||
xrf.frag.defaultPredefinedView({model,scene:model.scene})
|
||||
// spec: 2. execute predefined view(s) from URL (https://xrfragment.org/#predefined_view)
|
||||
hashbus.pub( url, model ) // and eval URI XR fragments
|
||||
// spec: 2. init metadata
|
||||
let frag = hashbus.pub( url, model ) // and eval URI XR fragments
|
||||
// spec: predefined view(s) from URL (https://xrfragment.org/#predefined_view)
|
||||
setTimeout( () => { // give external objects some slack
|
||||
xrf.frag.updatePredefinedView({model,scene:model.scene,frag})
|
||||
},2000)
|
||||
xrf.add( model.scene )
|
||||
xrf.navigator.updateHash(hash)
|
||||
resolve(model)
|
||||
|
@ -49,9 +53,14 @@ xrf.navigator.to = (url,flags,loader,data) => {
|
|||
|
||||
xrf.navigator.init = () => {
|
||||
if( xrf.navigator.init.inited ) return
|
||||
|
||||
window.addEventListener('popstate', function (event){
|
||||
xrf.navigator.to( document.location.search.substr(1) + document.location.hash )
|
||||
})
|
||||
|
||||
window.addEventListener('hashchange', function (e){
|
||||
xrf.emit('hash', {hash: document.location.hash })
|
||||
})
|
||||
|
||||
// this allows selectionlines to be updated according to the camera (renderloop)
|
||||
xrf.focusLine = new xrf.THREE.Group()
|
||||
|
|
|
@ -81,7 +81,7 @@ xrf.frag.href = function(v, opts){
|
|||
vec4 color = texture2D(pano, sampleUV);
|
||||
// Convert color to grayscale (lazy lite approach to not having to match tonemapping/shaderstacking of THREE.js)
|
||||
float luminance = 0.2126 * color.r + 0.7152 * color.g + 0.0722 * color.b;
|
||||
vec4 grayscale_color = color; //selected ? color : vec4(vec3(luminance) + vec3(0.33), color.a);
|
||||
vec4 grayscale_color = selected ? color : vec4(vec3(luminance) + vec3(0.33), color.a);
|
||||
gl_FragColor = grayscale_color;
|
||||
}
|
||||
`,
|
||||
|
@ -109,14 +109,18 @@ xrf.frag.href = function(v, opts){
|
|||
|
||||
let selected = (state) => () => {
|
||||
if( mesh.selected == state ) return // nothing changed
|
||||
if( mesh.material ){
|
||||
if( mesh.material.uniforms ) mesh.material.uniforms.selected.value = state
|
||||
else mesh.material.color.r = mesh.material.color.g = mesh.material.color.b = state ? 2.0 : 1.0
|
||||
}
|
||||
xrf.interactive.objects.map( (o) => {
|
||||
let newState = o.name == mesh.name ? state : false
|
||||
if( o.material ){
|
||||
if( o.material.uniforms ) o.material.uniforms.selected.value = newState
|
||||
if( o.material.emissive ) o.material.emissive.r = o.material.emissive.g = o.material.emissive.b = newState ? 2.0 : 1.0
|
||||
}
|
||||
})
|
||||
// update mouse cursor
|
||||
if( !renderer.domElement.lastCursor )
|
||||
renderer.domElement.lastCursor = renderer.domElement.style.cursor
|
||||
renderer.domElement.style.cursor = state ? 'pointer' : renderer.domElement.lastCursor
|
||||
|
||||
xrf
|
||||
.emit('href',{selected:state,mesh,xrf:v}) // let all listeners agree
|
||||
.then( () => mesh.selected = state )
|
||||
|
|
|
@ -6,7 +6,7 @@ xrf.frag.defaultPredefinedView = (opts) => {
|
|||
}
|
||||
|
||||
xrf.frag.updatePredefinedView = (opts) => {
|
||||
let {frag,scene,model} = opts
|
||||
let {frag,scene,model,renderer} = opts
|
||||
|
||||
// spec: https://xrfragment.org/#Selection%20of%20interest
|
||||
const selectionOfInterest = (frag,scene,mesh) => {
|
||||
|
@ -14,7 +14,7 @@ xrf.frag.updatePredefinedView = (opts) => {
|
|||
let oldSelection
|
||||
if(!id) return id // important: ignore empty strings
|
||||
// Selection of Interest if predefined_view matches object name
|
||||
if( mesh.visible ){
|
||||
if( mesh.visible && mesh.material){
|
||||
xrf.emit('focus',{...opts,frag})
|
||||
.then( () => {
|
||||
const color = new THREE.Color();
|
||||
|
@ -82,14 +82,13 @@ xrf.frag.updatePredefinedView = (opts) => {
|
|||
remove.map( (n) => scene.remove(n.selection) )
|
||||
// create new selections
|
||||
match.map( (w) => {
|
||||
if( w.key == `#${id}` && w.value && w.value[0] == '#' ){
|
||||
// if value is alias, execute fragment value
|
||||
xrf.hashbus.pub( w.value, xrf.model, xrf.XRF.METADATA | xrf.XRF.PV_OVERRIDE | xrf.XRF.NAVIGATOR )
|
||||
if( w.key == `#${id}` ){
|
||||
if( w.value && w.value[0] == '#' ){
|
||||
// if value is alias, execute fragment value
|
||||
xrf.hashbus.pub( w.value, xrf.model, xrf.XRF.METADATA | xrf.XRF.PV_OVERRIDE | xrf.XRF.NAVIGATOR )
|
||||
}
|
||||
}
|
||||
w.nodes.map( (mesh) => {
|
||||
if( mesh.material )
|
||||
selectionOfInterest( v, scene, mesh )
|
||||
})
|
||||
w.nodes.map( (mesh) => selectionOfInterest( v, scene, mesh ) )
|
||||
})
|
||||
}
|
||||
|
||||
|
@ -99,6 +98,8 @@ xrf.frag.updatePredefinedView = (opts) => {
|
|||
console.log("filtering predefined view of src")
|
||||
console.dir(frag)
|
||||
}else{
|
||||
console.log("updatePredefinedView")
|
||||
console.dir(frag)
|
||||
for ( let i in frag ) {
|
||||
let v = frag[i]
|
||||
if( v.is( xrf.XRF.PV_EXECUTE ) ){
|
||||
|
@ -113,7 +114,6 @@ xrf.frag.updatePredefinedView = (opts) => {
|
|||
// react to enduser typing url
|
||||
xrf.addEventListener('hash', (opts) => {
|
||||
let frag = xrf.URI.parse( opts.hash, xrf.XRF.NAVIGATOR | xrf.XRF.PV_OVERRIDE | xrf.XRF.METADATA )
|
||||
console.dir({opts,frag})
|
||||
xrf.frag.updatePredefinedView({frag,scene:xrf.scene})
|
||||
})
|
||||
|
||||
|
|
|
@ -27,10 +27,8 @@ xrf.frag.q = function(v, opts){
|
|||
xrf.frag.q.filter = function(scene,frag){
|
||||
// spec: https://xrfragment.org/#queries
|
||||
let q = frag.q.query
|
||||
console.dir(q)
|
||||
scene.traverse( (mesh) => {
|
||||
for ( let i in q ) {
|
||||
if( i == '' ) continue
|
||||
let isMeshId = q[i].id != undefined
|
||||
let isMeshProperty = q[i].rules != undefined && q[i].rules.length && !isMeshId
|
||||
if( q[i].root && mesh.isSRC ) continue; // ignore nested object for root-items (queryseletor '/foo' e.g.)
|
||||
|
|
|
@ -3,23 +3,41 @@
|
|||
xrf.frag.src = function(v, opts){
|
||||
|
||||
opts.embedded = v // indicate embedded XR fragment
|
||||
let { mesh, model, camera, scene, renderer, THREE, hashbus} = opts
|
||||
let { mesh, model, camera, scene, renderer, THREE, hashbus, frag} = opts
|
||||
|
||||
console.log(" └ instancing src")
|
||||
let src;
|
||||
let url = v.string
|
||||
let frag = xrfragment.URI.parse(url)
|
||||
let vfrag = xrfragment.URI.parse(url)
|
||||
opts.isPlane = mesh.geometry && mesh.geometry.attributes.uv && mesh.geometry.attributes.uv.count == 4
|
||||
|
||||
const addScene = (scene,url,frag) => {
|
||||
src = xrf.frag.src.filterScene(scene,{...opts,frag})
|
||||
xrf.frag.src.scale( src, opts, url )
|
||||
xrf.frag.src.eval( src, opts, url )
|
||||
enableSourcePortation(src)
|
||||
mesh.add(src)
|
||||
mesh.traverse( (n) => n.isSRC = n.isXRF = true )
|
||||
if( mesh.material ) mesh.material.visible = false
|
||||
}
|
||||
|
||||
const enableSourcePortation = (src) => {
|
||||
if( vfrag.href || v.string[0] == '#' ) return
|
||||
let scale = new THREE.Vector3()
|
||||
let size = new THREE.Vector3()
|
||||
mesh.getWorldScale(scale)
|
||||
new THREE.Box3().setFromObject(src).getSize(size)
|
||||
const geo = new THREE.SphereGeometry( Math.max(size.x, size.y, size.z) / scale.x, 10, 10 )
|
||||
const mat = new THREE.MeshBasicMaterial()
|
||||
mat.transparent = true
|
||||
mat.roughness = 0.05
|
||||
mat.metalness = 1
|
||||
mat.opacity = 0
|
||||
const cube = new THREE.Mesh( geo, mat )
|
||||
console.log("todo: sourceportate")
|
||||
//mesh.add(cube)
|
||||
}
|
||||
|
||||
const externalSRC = (url,frag,src) => {
|
||||
fetch(url, { method: 'HEAD' })
|
||||
.then( (res) => {
|
||||
|
@ -38,8 +56,8 @@ xrf.frag.src = function(v, opts){
|
|||
.catch( console.error )
|
||||
}
|
||||
|
||||
if( url[0] == "#" ) addScene(scene,url,frag) // current file
|
||||
else externalSRC(url,frag) // external file
|
||||
if( url[0] == "#" ) addScene(scene,url,vfrag) // current file
|
||||
else externalSRC(url,vfrag) // external file
|
||||
}
|
||||
|
||||
xrf.frag.src.eval = function(scene, opts, url){
|
||||
|
|
Loading…
Reference in New Issue