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
|
pub.fragment = (k, opts ) => { // evaluate one fragment
|
||||||
let frag = opts.frag[k];
|
let frag = opts.frag[k];
|
||||||
|
|
||||||
// call native function (xrf/env.js e.g.), or pass it to user decorator
|
// call native function (xrf/env.js e.g.), or pass it to user decorator
|
||||||
xrf.emit(k,opts)
|
xrf.emit(k,opts)
|
||||||
.then( () => {
|
.then( () => {
|
||||||
|
@ -852,6 +853,7 @@ xrf.parseModel = function(model,url){
|
||||||
model.mixer = new xrf.THREE.AnimationMixer(model.scene)
|
model.mixer = new xrf.THREE.AnimationMixer(model.scene)
|
||||||
model.animations.map( (anim) => {
|
model.animations.map( (anim) => {
|
||||||
anim.action = model.mixer.clipAction( anim )
|
anim.action = model.mixer.clipAction( anim )
|
||||||
|
//anim.action.setLoop(0)
|
||||||
anim.action.play()
|
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.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.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;
|
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
|
if( xrf.focusLine.opacity < 0.0 ) xrf.focusLine.opacity = 0
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
xrf.getLastModel = () => xrf.model.last
|
xrf.getLastModel = () => xrf.model.last
|
||||||
|
@ -940,7 +943,7 @@ xrf.InteractiveGroup = function(THREE,renderer,camera){
|
||||||
function nocollide(){
|
function nocollide(){
|
||||||
if( nocollide.tid ) return // ratelimit
|
if( nocollide.tid ) return // ratelimit
|
||||||
_event.type = "nocollide"
|
_event.type = "nocollide"
|
||||||
scope.children.map( (c) => c.dispatchEvent(_event) )
|
scope.objects.map( (c) => c.dispatchEvent(_event) )
|
||||||
nocollide.tid = setTimeout( () => nocollide.tid = null, 100 )
|
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})
|
xrf.XRWG.generate({model,scene:model.scene})
|
||||||
// spec: 1. execute the default predefined view '#' (if exist) (https://xrfragment.org/#predefined_view)
|
// spec: 1. execute the default predefined view '#' (if exist) (https://xrfragment.org/#predefined_view)
|
||||||
xrf.frag.defaultPredefinedView({model,scene:model.scene})
|
xrf.frag.defaultPredefinedView({model,scene:model.scene})
|
||||||
// spec: 2. execute predefined view(s) from URL (https://xrfragment.org/#predefined_view)
|
// spec: 2. init metadata
|
||||||
hashbus.pub( url, model ) // and eval URI XR fragments
|
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.add( model.scene )
|
||||||
xrf.navigator.updateHash(hash)
|
xrf.navigator.updateHash(hash)
|
||||||
resolve(model)
|
resolve(model)
|
||||||
|
@ -1096,9 +1103,14 @@ xrf.navigator.to = (url,flags,loader,data) => {
|
||||||
|
|
||||||
xrf.navigator.init = () => {
|
xrf.navigator.init = () => {
|
||||||
if( xrf.navigator.init.inited ) return
|
if( xrf.navigator.init.inited ) return
|
||||||
|
|
||||||
window.addEventListener('popstate', function (event){
|
window.addEventListener('popstate', function (event){
|
||||||
xrf.navigator.to( document.location.search.substr(1) + document.location.hash )
|
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)
|
// this allows selectionlines to be updated according to the camera (renderloop)
|
||||||
xrf.focusLine = new xrf.THREE.Group()
|
xrf.focusLine = new xrf.THREE.Group()
|
||||||
|
@ -1398,7 +1410,7 @@ xrf.frag.href = function(v, opts){
|
||||||
vec4 color = texture2D(pano, sampleUV);
|
vec4 color = texture2D(pano, sampleUV);
|
||||||
// Convert color to grayscale (lazy lite approach to not having to match tonemapping/shaderstacking of THREE.js)
|
// 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;
|
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;
|
gl_FragColor = grayscale_color;
|
||||||
}
|
}
|
||||||
`,
|
`,
|
||||||
|
@ -1426,14 +1438,18 @@ xrf.frag.href = function(v, opts){
|
||||||
|
|
||||||
let selected = (state) => () => {
|
let selected = (state) => () => {
|
||||||
if( mesh.selected == state ) return // nothing changed
|
if( mesh.selected == state ) return // nothing changed
|
||||||
if( mesh.material ){
|
xrf.interactive.objects.map( (o) => {
|
||||||
if( mesh.material.uniforms ) mesh.material.uniforms.selected.value = state
|
let newState = o.name == mesh.name ? state : false
|
||||||
else mesh.material.color.r = mesh.material.color.g = mesh.material.color.b = state ? 2.0 : 1.0
|
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
|
// update mouse cursor
|
||||||
if( !renderer.domElement.lastCursor )
|
if( !renderer.domElement.lastCursor )
|
||||||
renderer.domElement.lastCursor = renderer.domElement.style.cursor
|
renderer.domElement.lastCursor = renderer.domElement.style.cursor
|
||||||
renderer.domElement.style.cursor = state ? 'pointer' : renderer.domElement.lastCursor
|
renderer.domElement.style.cursor = state ? 'pointer' : renderer.domElement.lastCursor
|
||||||
|
|
||||||
xrf
|
xrf
|
||||||
.emit('href',{selected:state,mesh,xrf:v}) // let all listeners agree
|
.emit('href',{selected:state,mesh,xrf:v}) // let all listeners agree
|
||||||
.then( () => mesh.selected = state )
|
.then( () => mesh.selected = state )
|
||||||
|
@ -1481,7 +1497,7 @@ xrf.frag.defaultPredefinedView = (opts) => {
|
||||||
}
|
}
|
||||||
|
|
||||||
xrf.frag.updatePredefinedView = (opts) => {
|
xrf.frag.updatePredefinedView = (opts) => {
|
||||||
let {frag,scene,model} = opts
|
let {frag,scene,model,renderer} = opts
|
||||||
|
|
||||||
// spec: https://xrfragment.org/#Selection%20of%20interest
|
// spec: https://xrfragment.org/#Selection%20of%20interest
|
||||||
const selectionOfInterest = (frag,scene,mesh) => {
|
const selectionOfInterest = (frag,scene,mesh) => {
|
||||||
|
@ -1489,7 +1505,7 @@ xrf.frag.updatePredefinedView = (opts) => {
|
||||||
let oldSelection
|
let oldSelection
|
||||||
if(!id) return id // important: ignore empty strings
|
if(!id) return id // important: ignore empty strings
|
||||||
// Selection of Interest if predefined_view matches object name
|
// Selection of Interest if predefined_view matches object name
|
||||||
if( mesh.visible ){
|
if( mesh.visible && mesh.material){
|
||||||
xrf.emit('focus',{...opts,frag})
|
xrf.emit('focus',{...opts,frag})
|
||||||
.then( () => {
|
.then( () => {
|
||||||
const color = new THREE.Color();
|
const color = new THREE.Color();
|
||||||
|
@ -1557,14 +1573,13 @@ xrf.frag.updatePredefinedView = (opts) => {
|
||||||
remove.map( (n) => scene.remove(n.selection) )
|
remove.map( (n) => scene.remove(n.selection) )
|
||||||
// create new selections
|
// create new selections
|
||||||
match.map( (w) => {
|
match.map( (w) => {
|
||||||
if( w.key == `#${id}` && w.value && w.value[0] == '#' ){
|
if( w.key == `#${id}` ){
|
||||||
// if value is alias, execute fragment value
|
if( w.value && w.value[0] == '#' ){
|
||||||
xrf.hashbus.pub( w.value, xrf.model, xrf.XRF.METADATA | xrf.XRF.PV_OVERRIDE | xrf.XRF.NAVIGATOR )
|
// 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) => {
|
w.nodes.map( (mesh) => selectionOfInterest( v, scene, mesh ) )
|
||||||
if( mesh.material )
|
|
||||||
selectionOfInterest( v, scene, mesh )
|
|
||||||
})
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1574,6 +1589,8 @@ xrf.frag.updatePredefinedView = (opts) => {
|
||||||
console.log("filtering predefined view of src")
|
console.log("filtering predefined view of src")
|
||||||
console.dir(frag)
|
console.dir(frag)
|
||||||
}else{
|
}else{
|
||||||
|
console.log("updatePredefinedView")
|
||||||
|
console.dir(frag)
|
||||||
for ( let i in frag ) {
|
for ( let i in frag ) {
|
||||||
let v = frag[i]
|
let v = frag[i]
|
||||||
if( v.is( xrf.XRF.PV_EXECUTE ) ){
|
if( v.is( xrf.XRF.PV_EXECUTE ) ){
|
||||||
|
@ -1588,7 +1605,6 @@ xrf.frag.updatePredefinedView = (opts) => {
|
||||||
// react to enduser typing url
|
// react to enduser typing url
|
||||||
xrf.addEventListener('hash', (opts) => {
|
xrf.addEventListener('hash', (opts) => {
|
||||||
let frag = xrf.URI.parse( opts.hash, xrf.XRF.NAVIGATOR | xrf.XRF.PV_OVERRIDE | xrf.XRF.METADATA )
|
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})
|
xrf.frag.updatePredefinedView({frag,scene:xrf.scene})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
@ -1627,10 +1643,8 @@ xrf.frag.q = function(v, opts){
|
||||||
xrf.frag.q.filter = function(scene,frag){
|
xrf.frag.q.filter = function(scene,frag){
|
||||||
// spec: https://xrfragment.org/#queries
|
// spec: https://xrfragment.org/#queries
|
||||||
let q = frag.q.query
|
let q = frag.q.query
|
||||||
console.dir(q)
|
|
||||||
scene.traverse( (mesh) => {
|
scene.traverse( (mesh) => {
|
||||||
for ( let i in q ) {
|
for ( let i in q ) {
|
||||||
if( i == '' ) continue
|
|
||||||
let isMeshId = q[i].id != undefined
|
let isMeshId = q[i].id != undefined
|
||||||
let isMeshProperty = q[i].rules != undefined && q[i].rules.length && !isMeshId
|
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.)
|
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){
|
xrf.frag.src = function(v, opts){
|
||||||
|
|
||||||
opts.embedded = v // indicate embedded XR fragment
|
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")
|
console.log(" └ instancing src")
|
||||||
let src;
|
let src;
|
||||||
let url = v.string
|
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
|
opts.isPlane = mesh.geometry && mesh.geometry.attributes.uv && mesh.geometry.attributes.uv.count == 4
|
||||||
|
|
||||||
const addScene = (scene,url,frag) => {
|
const addScene = (scene,url,frag) => {
|
||||||
src = xrf.frag.src.filterScene(scene,{...opts,frag})
|
src = xrf.frag.src.filterScene(scene,{...opts,frag})
|
||||||
xrf.frag.src.scale( src, opts, url )
|
xrf.frag.src.scale( src, opts, url )
|
||||||
xrf.frag.src.eval( src, opts, url )
|
xrf.frag.src.eval( src, opts, url )
|
||||||
|
enableSourcePortation(src)
|
||||||
mesh.add(src)
|
mesh.add(src)
|
||||||
mesh.traverse( (n) => n.isSRC = n.isXRF = true )
|
mesh.traverse( (n) => n.isSRC = n.isXRF = true )
|
||||||
if( mesh.material ) mesh.material.visible = false
|
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) => {
|
const externalSRC = (url,frag,src) => {
|
||||||
fetch(url, { method: 'HEAD' })
|
fetch(url, { method: 'HEAD' })
|
||||||
.then( (res) => {
|
.then( (res) => {
|
||||||
|
@ -1690,8 +1722,8 @@ xrf.frag.src = function(v, opts){
|
||||||
.catch( console.error )
|
.catch( console.error )
|
||||||
}
|
}
|
||||||
|
|
||||||
if( url[0] == "#" ) addScene(scene,url,frag) // current file
|
if( url[0] == "#" ) addScene(scene,url,vfrag) // current file
|
||||||
else externalSRC(url,frag) // external file
|
else externalSRC(url,vfrag) // external file
|
||||||
}
|
}
|
||||||
|
|
||||||
xrf.frag.src.eval = function(scene, opts, url){
|
xrf.frag.src.eval = function(scene, opts, url){
|
||||||
|
@ -1916,9 +1948,9 @@ window.AFRAME.registerComponent('xrf', {
|
||||||
let aScene = document.querySelector('a-scene')
|
let aScene = document.querySelector('a-scene')
|
||||||
let XRF = AFRAME.XRF = xrf.init({
|
let XRF = AFRAME.XRF = xrf.init({
|
||||||
THREE,
|
THREE,
|
||||||
camera: aScene.camera,
|
camera: aScene.camera,
|
||||||
scene: aScene.object3D,
|
scene: aScene.object3D,
|
||||||
renderer: aScene.renderer,
|
renderer: aScene.renderer,
|
||||||
debug: true,
|
debug: true,
|
||||||
loaders: {
|
loaders: {
|
||||||
gltf: THREE.GLTFLoader, // which 3D assets (exts) to check for XR fragments?
|
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
|
pub.fragment = (k, opts ) => { // evaluate one fragment
|
||||||
let frag = opts.frag[k];
|
let frag = opts.frag[k];
|
||||||
|
|
||||||
// call native function (xrf/env.js e.g.), or pass it to user decorator
|
// call native function (xrf/env.js e.g.), or pass it to user decorator
|
||||||
xrf.emit(k,opts)
|
xrf.emit(k,opts)
|
||||||
.then( () => {
|
.then( () => {
|
||||||
|
@ -852,6 +853,7 @@ xrf.parseModel = function(model,url){
|
||||||
model.mixer = new xrf.THREE.AnimationMixer(model.scene)
|
model.mixer = new xrf.THREE.AnimationMixer(model.scene)
|
||||||
model.animations.map( (anim) => {
|
model.animations.map( (anim) => {
|
||||||
anim.action = model.mixer.clipAction( anim )
|
anim.action = model.mixer.clipAction( anim )
|
||||||
|
//anim.action.setLoop(0)
|
||||||
anim.action.play()
|
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.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.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;
|
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
|
if( xrf.focusLine.opacity < 0.0 ) xrf.focusLine.opacity = 0
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
xrf.getLastModel = () => xrf.model.last
|
xrf.getLastModel = () => xrf.model.last
|
||||||
|
@ -940,7 +943,7 @@ xrf.InteractiveGroup = function(THREE,renderer,camera){
|
||||||
function nocollide(){
|
function nocollide(){
|
||||||
if( nocollide.tid ) return // ratelimit
|
if( nocollide.tid ) return // ratelimit
|
||||||
_event.type = "nocollide"
|
_event.type = "nocollide"
|
||||||
scope.children.map( (c) => c.dispatchEvent(_event) )
|
scope.objects.map( (c) => c.dispatchEvent(_event) )
|
||||||
nocollide.tid = setTimeout( () => nocollide.tid = null, 100 )
|
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})
|
xrf.XRWG.generate({model,scene:model.scene})
|
||||||
// spec: 1. execute the default predefined view '#' (if exist) (https://xrfragment.org/#predefined_view)
|
// spec: 1. execute the default predefined view '#' (if exist) (https://xrfragment.org/#predefined_view)
|
||||||
xrf.frag.defaultPredefinedView({model,scene:model.scene})
|
xrf.frag.defaultPredefinedView({model,scene:model.scene})
|
||||||
// spec: 2. execute predefined view(s) from URL (https://xrfragment.org/#predefined_view)
|
// spec: 2. init metadata
|
||||||
hashbus.pub( url, model ) // and eval URI XR fragments
|
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.add( model.scene )
|
||||||
xrf.navigator.updateHash(hash)
|
xrf.navigator.updateHash(hash)
|
||||||
resolve(model)
|
resolve(model)
|
||||||
|
@ -1096,9 +1103,14 @@ xrf.navigator.to = (url,flags,loader,data) => {
|
||||||
|
|
||||||
xrf.navigator.init = () => {
|
xrf.navigator.init = () => {
|
||||||
if( xrf.navigator.init.inited ) return
|
if( xrf.navigator.init.inited ) return
|
||||||
|
|
||||||
window.addEventListener('popstate', function (event){
|
window.addEventListener('popstate', function (event){
|
||||||
xrf.navigator.to( document.location.search.substr(1) + document.location.hash )
|
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)
|
// this allows selectionlines to be updated according to the camera (renderloop)
|
||||||
xrf.focusLine = new xrf.THREE.Group()
|
xrf.focusLine = new xrf.THREE.Group()
|
||||||
|
@ -1398,7 +1410,7 @@ xrf.frag.href = function(v, opts){
|
||||||
vec4 color = texture2D(pano, sampleUV);
|
vec4 color = texture2D(pano, sampleUV);
|
||||||
// Convert color to grayscale (lazy lite approach to not having to match tonemapping/shaderstacking of THREE.js)
|
// 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;
|
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;
|
gl_FragColor = grayscale_color;
|
||||||
}
|
}
|
||||||
`,
|
`,
|
||||||
|
@ -1426,14 +1438,18 @@ xrf.frag.href = function(v, opts){
|
||||||
|
|
||||||
let selected = (state) => () => {
|
let selected = (state) => () => {
|
||||||
if( mesh.selected == state ) return // nothing changed
|
if( mesh.selected == state ) return // nothing changed
|
||||||
if( mesh.material ){
|
xrf.interactive.objects.map( (o) => {
|
||||||
if( mesh.material.uniforms ) mesh.material.uniforms.selected.value = state
|
let newState = o.name == mesh.name ? state : false
|
||||||
else mesh.material.color.r = mesh.material.color.g = mesh.material.color.b = state ? 2.0 : 1.0
|
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
|
// update mouse cursor
|
||||||
if( !renderer.domElement.lastCursor )
|
if( !renderer.domElement.lastCursor )
|
||||||
renderer.domElement.lastCursor = renderer.domElement.style.cursor
|
renderer.domElement.lastCursor = renderer.domElement.style.cursor
|
||||||
renderer.domElement.style.cursor = state ? 'pointer' : renderer.domElement.lastCursor
|
renderer.domElement.style.cursor = state ? 'pointer' : renderer.domElement.lastCursor
|
||||||
|
|
||||||
xrf
|
xrf
|
||||||
.emit('href',{selected:state,mesh,xrf:v}) // let all listeners agree
|
.emit('href',{selected:state,mesh,xrf:v}) // let all listeners agree
|
||||||
.then( () => mesh.selected = state )
|
.then( () => mesh.selected = state )
|
||||||
|
@ -1481,7 +1497,7 @@ xrf.frag.defaultPredefinedView = (opts) => {
|
||||||
}
|
}
|
||||||
|
|
||||||
xrf.frag.updatePredefinedView = (opts) => {
|
xrf.frag.updatePredefinedView = (opts) => {
|
||||||
let {frag,scene,model} = opts
|
let {frag,scene,model,renderer} = opts
|
||||||
|
|
||||||
// spec: https://xrfragment.org/#Selection%20of%20interest
|
// spec: https://xrfragment.org/#Selection%20of%20interest
|
||||||
const selectionOfInterest = (frag,scene,mesh) => {
|
const selectionOfInterest = (frag,scene,mesh) => {
|
||||||
|
@ -1489,7 +1505,7 @@ xrf.frag.updatePredefinedView = (opts) => {
|
||||||
let oldSelection
|
let oldSelection
|
||||||
if(!id) return id // important: ignore empty strings
|
if(!id) return id // important: ignore empty strings
|
||||||
// Selection of Interest if predefined_view matches object name
|
// Selection of Interest if predefined_view matches object name
|
||||||
if( mesh.visible ){
|
if( mesh.visible && mesh.material){
|
||||||
xrf.emit('focus',{...opts,frag})
|
xrf.emit('focus',{...opts,frag})
|
||||||
.then( () => {
|
.then( () => {
|
||||||
const color = new THREE.Color();
|
const color = new THREE.Color();
|
||||||
|
@ -1557,14 +1573,13 @@ xrf.frag.updatePredefinedView = (opts) => {
|
||||||
remove.map( (n) => scene.remove(n.selection) )
|
remove.map( (n) => scene.remove(n.selection) )
|
||||||
// create new selections
|
// create new selections
|
||||||
match.map( (w) => {
|
match.map( (w) => {
|
||||||
if( w.key == `#${id}` && w.value && w.value[0] == '#' ){
|
if( w.key == `#${id}` ){
|
||||||
// if value is alias, execute fragment value
|
if( w.value && w.value[0] == '#' ){
|
||||||
xrf.hashbus.pub( w.value, xrf.model, xrf.XRF.METADATA | xrf.XRF.PV_OVERRIDE | xrf.XRF.NAVIGATOR )
|
// 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) => {
|
w.nodes.map( (mesh) => selectionOfInterest( v, scene, mesh ) )
|
||||||
if( mesh.material )
|
|
||||||
selectionOfInterest( v, scene, mesh )
|
|
||||||
})
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1574,6 +1589,8 @@ xrf.frag.updatePredefinedView = (opts) => {
|
||||||
console.log("filtering predefined view of src")
|
console.log("filtering predefined view of src")
|
||||||
console.dir(frag)
|
console.dir(frag)
|
||||||
}else{
|
}else{
|
||||||
|
console.log("updatePredefinedView")
|
||||||
|
console.dir(frag)
|
||||||
for ( let i in frag ) {
|
for ( let i in frag ) {
|
||||||
let v = frag[i]
|
let v = frag[i]
|
||||||
if( v.is( xrf.XRF.PV_EXECUTE ) ){
|
if( v.is( xrf.XRF.PV_EXECUTE ) ){
|
||||||
|
@ -1588,7 +1605,6 @@ xrf.frag.updatePredefinedView = (opts) => {
|
||||||
// react to enduser typing url
|
// react to enduser typing url
|
||||||
xrf.addEventListener('hash', (opts) => {
|
xrf.addEventListener('hash', (opts) => {
|
||||||
let frag = xrf.URI.parse( opts.hash, xrf.XRF.NAVIGATOR | xrf.XRF.PV_OVERRIDE | xrf.XRF.METADATA )
|
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})
|
xrf.frag.updatePredefinedView({frag,scene:xrf.scene})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
@ -1627,10 +1643,8 @@ xrf.frag.q = function(v, opts){
|
||||||
xrf.frag.q.filter = function(scene,frag){
|
xrf.frag.q.filter = function(scene,frag){
|
||||||
// spec: https://xrfragment.org/#queries
|
// spec: https://xrfragment.org/#queries
|
||||||
let q = frag.q.query
|
let q = frag.q.query
|
||||||
console.dir(q)
|
|
||||||
scene.traverse( (mesh) => {
|
scene.traverse( (mesh) => {
|
||||||
for ( let i in q ) {
|
for ( let i in q ) {
|
||||||
if( i == '' ) continue
|
|
||||||
let isMeshId = q[i].id != undefined
|
let isMeshId = q[i].id != undefined
|
||||||
let isMeshProperty = q[i].rules != undefined && q[i].rules.length && !isMeshId
|
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.)
|
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){
|
xrf.frag.src = function(v, opts){
|
||||||
|
|
||||||
opts.embedded = v // indicate embedded XR fragment
|
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")
|
console.log(" └ instancing src")
|
||||||
let src;
|
let src;
|
||||||
let url = v.string
|
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
|
opts.isPlane = mesh.geometry && mesh.geometry.attributes.uv && mesh.geometry.attributes.uv.count == 4
|
||||||
|
|
||||||
const addScene = (scene,url,frag) => {
|
const addScene = (scene,url,frag) => {
|
||||||
src = xrf.frag.src.filterScene(scene,{...opts,frag})
|
src = xrf.frag.src.filterScene(scene,{...opts,frag})
|
||||||
xrf.frag.src.scale( src, opts, url )
|
xrf.frag.src.scale( src, opts, url )
|
||||||
xrf.frag.src.eval( src, opts, url )
|
xrf.frag.src.eval( src, opts, url )
|
||||||
|
enableSourcePortation(src)
|
||||||
mesh.add(src)
|
mesh.add(src)
|
||||||
mesh.traverse( (n) => n.isSRC = n.isXRF = true )
|
mesh.traverse( (n) => n.isSRC = n.isXRF = true )
|
||||||
if( mesh.material ) mesh.material.visible = false
|
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) => {
|
const externalSRC = (url,frag,src) => {
|
||||||
fetch(url, { method: 'HEAD' })
|
fetch(url, { method: 'HEAD' })
|
||||||
.then( (res) => {
|
.then( (res) => {
|
||||||
|
@ -1690,8 +1722,8 @@ xrf.frag.src = function(v, opts){
|
||||||
.catch( console.error )
|
.catch( console.error )
|
||||||
}
|
}
|
||||||
|
|
||||||
if( url[0] == "#" ) addScene(scene,url,frag) // current file
|
if( url[0] == "#" ) addScene(scene,url,vfrag) // current file
|
||||||
else externalSRC(url,frag) // external file
|
else externalSRC(url,vfrag) // external file
|
||||||
}
|
}
|
||||||
|
|
||||||
xrf.frag.src.eval = function(scene, opts, url){
|
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
|
pub.fragment = (k, opts ) => { // evaluate one fragment
|
||||||
let frag = opts.frag[k];
|
let frag = opts.frag[k];
|
||||||
|
|
||||||
// call native function (xrf/env.js e.g.), or pass it to user decorator
|
// call native function (xrf/env.js e.g.), or pass it to user decorator
|
||||||
xrf.emit(k,opts)
|
xrf.emit(k,opts)
|
||||||
.then( () => {
|
.then( () => {
|
||||||
|
@ -852,6 +853,7 @@ xrf.parseModel = function(model,url){
|
||||||
model.mixer = new xrf.THREE.AnimationMixer(model.scene)
|
model.mixer = new xrf.THREE.AnimationMixer(model.scene)
|
||||||
model.animations.map( (anim) => {
|
model.animations.map( (anim) => {
|
||||||
anim.action = model.mixer.clipAction( anim )
|
anim.action = model.mixer.clipAction( anim )
|
||||||
|
//anim.action.setLoop(0)
|
||||||
anim.action.play()
|
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.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.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;
|
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
|
if( xrf.focusLine.opacity < 0.0 ) xrf.focusLine.opacity = 0
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
xrf.getLastModel = () => xrf.model.last
|
xrf.getLastModel = () => xrf.model.last
|
||||||
|
@ -940,7 +943,7 @@ xrf.InteractiveGroup = function(THREE,renderer,camera){
|
||||||
function nocollide(){
|
function nocollide(){
|
||||||
if( nocollide.tid ) return // ratelimit
|
if( nocollide.tid ) return // ratelimit
|
||||||
_event.type = "nocollide"
|
_event.type = "nocollide"
|
||||||
scope.children.map( (c) => c.dispatchEvent(_event) )
|
scope.objects.map( (c) => c.dispatchEvent(_event) )
|
||||||
nocollide.tid = setTimeout( () => nocollide.tid = null, 100 )
|
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})
|
xrf.XRWG.generate({model,scene:model.scene})
|
||||||
// spec: 1. execute the default predefined view '#' (if exist) (https://xrfragment.org/#predefined_view)
|
// spec: 1. execute the default predefined view '#' (if exist) (https://xrfragment.org/#predefined_view)
|
||||||
xrf.frag.defaultPredefinedView({model,scene:model.scene})
|
xrf.frag.defaultPredefinedView({model,scene:model.scene})
|
||||||
// spec: 2. execute predefined view(s) from URL (https://xrfragment.org/#predefined_view)
|
// spec: 2. init metadata
|
||||||
hashbus.pub( url, model ) // and eval URI XR fragments
|
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.add( model.scene )
|
||||||
xrf.navigator.updateHash(hash)
|
xrf.navigator.updateHash(hash)
|
||||||
resolve(model)
|
resolve(model)
|
||||||
|
@ -1096,9 +1103,14 @@ xrf.navigator.to = (url,flags,loader,data) => {
|
||||||
|
|
||||||
xrf.navigator.init = () => {
|
xrf.navigator.init = () => {
|
||||||
if( xrf.navigator.init.inited ) return
|
if( xrf.navigator.init.inited ) return
|
||||||
|
|
||||||
window.addEventListener('popstate', function (event){
|
window.addEventListener('popstate', function (event){
|
||||||
xrf.navigator.to( document.location.search.substr(1) + document.location.hash )
|
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)
|
// this allows selectionlines to be updated according to the camera (renderloop)
|
||||||
xrf.focusLine = new xrf.THREE.Group()
|
xrf.focusLine = new xrf.THREE.Group()
|
||||||
|
@ -1398,7 +1410,7 @@ xrf.frag.href = function(v, opts){
|
||||||
vec4 color = texture2D(pano, sampleUV);
|
vec4 color = texture2D(pano, sampleUV);
|
||||||
// Convert color to grayscale (lazy lite approach to not having to match tonemapping/shaderstacking of THREE.js)
|
// 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;
|
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;
|
gl_FragColor = grayscale_color;
|
||||||
}
|
}
|
||||||
`,
|
`,
|
||||||
|
@ -1426,14 +1438,18 @@ xrf.frag.href = function(v, opts){
|
||||||
|
|
||||||
let selected = (state) => () => {
|
let selected = (state) => () => {
|
||||||
if( mesh.selected == state ) return // nothing changed
|
if( mesh.selected == state ) return // nothing changed
|
||||||
if( mesh.material ){
|
xrf.interactive.objects.map( (o) => {
|
||||||
if( mesh.material.uniforms ) mesh.material.uniforms.selected.value = state
|
let newState = o.name == mesh.name ? state : false
|
||||||
else mesh.material.color.r = mesh.material.color.g = mesh.material.color.b = state ? 2.0 : 1.0
|
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
|
// update mouse cursor
|
||||||
if( !renderer.domElement.lastCursor )
|
if( !renderer.domElement.lastCursor )
|
||||||
renderer.domElement.lastCursor = renderer.domElement.style.cursor
|
renderer.domElement.lastCursor = renderer.domElement.style.cursor
|
||||||
renderer.domElement.style.cursor = state ? 'pointer' : renderer.domElement.lastCursor
|
renderer.domElement.style.cursor = state ? 'pointer' : renderer.domElement.lastCursor
|
||||||
|
|
||||||
xrf
|
xrf
|
||||||
.emit('href',{selected:state,mesh,xrf:v}) // let all listeners agree
|
.emit('href',{selected:state,mesh,xrf:v}) // let all listeners agree
|
||||||
.then( () => mesh.selected = state )
|
.then( () => mesh.selected = state )
|
||||||
|
@ -1481,7 +1497,7 @@ xrf.frag.defaultPredefinedView = (opts) => {
|
||||||
}
|
}
|
||||||
|
|
||||||
xrf.frag.updatePredefinedView = (opts) => {
|
xrf.frag.updatePredefinedView = (opts) => {
|
||||||
let {frag,scene,model} = opts
|
let {frag,scene,model,renderer} = opts
|
||||||
|
|
||||||
// spec: https://xrfragment.org/#Selection%20of%20interest
|
// spec: https://xrfragment.org/#Selection%20of%20interest
|
||||||
const selectionOfInterest = (frag,scene,mesh) => {
|
const selectionOfInterest = (frag,scene,mesh) => {
|
||||||
|
@ -1489,7 +1505,7 @@ xrf.frag.updatePredefinedView = (opts) => {
|
||||||
let oldSelection
|
let oldSelection
|
||||||
if(!id) return id // important: ignore empty strings
|
if(!id) return id // important: ignore empty strings
|
||||||
// Selection of Interest if predefined_view matches object name
|
// Selection of Interest if predefined_view matches object name
|
||||||
if( mesh.visible ){
|
if( mesh.visible && mesh.material){
|
||||||
xrf.emit('focus',{...opts,frag})
|
xrf.emit('focus',{...opts,frag})
|
||||||
.then( () => {
|
.then( () => {
|
||||||
const color = new THREE.Color();
|
const color = new THREE.Color();
|
||||||
|
@ -1557,14 +1573,13 @@ xrf.frag.updatePredefinedView = (opts) => {
|
||||||
remove.map( (n) => scene.remove(n.selection) )
|
remove.map( (n) => scene.remove(n.selection) )
|
||||||
// create new selections
|
// create new selections
|
||||||
match.map( (w) => {
|
match.map( (w) => {
|
||||||
if( w.key == `#${id}` && w.value && w.value[0] == '#' ){
|
if( w.key == `#${id}` ){
|
||||||
// if value is alias, execute fragment value
|
if( w.value && w.value[0] == '#' ){
|
||||||
xrf.hashbus.pub( w.value, xrf.model, xrf.XRF.METADATA | xrf.XRF.PV_OVERRIDE | xrf.XRF.NAVIGATOR )
|
// 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) => {
|
w.nodes.map( (mesh) => selectionOfInterest( v, scene, mesh ) )
|
||||||
if( mesh.material )
|
|
||||||
selectionOfInterest( v, scene, mesh )
|
|
||||||
})
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1574,6 +1589,8 @@ xrf.frag.updatePredefinedView = (opts) => {
|
||||||
console.log("filtering predefined view of src")
|
console.log("filtering predefined view of src")
|
||||||
console.dir(frag)
|
console.dir(frag)
|
||||||
}else{
|
}else{
|
||||||
|
console.log("updatePredefinedView")
|
||||||
|
console.dir(frag)
|
||||||
for ( let i in frag ) {
|
for ( let i in frag ) {
|
||||||
let v = frag[i]
|
let v = frag[i]
|
||||||
if( v.is( xrf.XRF.PV_EXECUTE ) ){
|
if( v.is( xrf.XRF.PV_EXECUTE ) ){
|
||||||
|
@ -1588,7 +1605,6 @@ xrf.frag.updatePredefinedView = (opts) => {
|
||||||
// react to enduser typing url
|
// react to enduser typing url
|
||||||
xrf.addEventListener('hash', (opts) => {
|
xrf.addEventListener('hash', (opts) => {
|
||||||
let frag = xrf.URI.parse( opts.hash, xrf.XRF.NAVIGATOR | xrf.XRF.PV_OVERRIDE | xrf.XRF.METADATA )
|
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})
|
xrf.frag.updatePredefinedView({frag,scene:xrf.scene})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
@ -1627,10 +1643,8 @@ xrf.frag.q = function(v, opts){
|
||||||
xrf.frag.q.filter = function(scene,frag){
|
xrf.frag.q.filter = function(scene,frag){
|
||||||
// spec: https://xrfragment.org/#queries
|
// spec: https://xrfragment.org/#queries
|
||||||
let q = frag.q.query
|
let q = frag.q.query
|
||||||
console.dir(q)
|
|
||||||
scene.traverse( (mesh) => {
|
scene.traverse( (mesh) => {
|
||||||
for ( let i in q ) {
|
for ( let i in q ) {
|
||||||
if( i == '' ) continue
|
|
||||||
let isMeshId = q[i].id != undefined
|
let isMeshId = q[i].id != undefined
|
||||||
let isMeshProperty = q[i].rules != undefined && q[i].rules.length && !isMeshId
|
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.)
|
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){
|
xrf.frag.src = function(v, opts){
|
||||||
|
|
||||||
opts.embedded = v // indicate embedded XR fragment
|
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")
|
console.log(" └ instancing src")
|
||||||
let src;
|
let src;
|
||||||
let url = v.string
|
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
|
opts.isPlane = mesh.geometry && mesh.geometry.attributes.uv && mesh.geometry.attributes.uv.count == 4
|
||||||
|
|
||||||
const addScene = (scene,url,frag) => {
|
const addScene = (scene,url,frag) => {
|
||||||
src = xrf.frag.src.filterScene(scene,{...opts,frag})
|
src = xrf.frag.src.filterScene(scene,{...opts,frag})
|
||||||
xrf.frag.src.scale( src, opts, url )
|
xrf.frag.src.scale( src, opts, url )
|
||||||
xrf.frag.src.eval( src, opts, url )
|
xrf.frag.src.eval( src, opts, url )
|
||||||
|
enableSourcePortation(src)
|
||||||
mesh.add(src)
|
mesh.add(src)
|
||||||
mesh.traverse( (n) => n.isSRC = n.isXRF = true )
|
mesh.traverse( (n) => n.isSRC = n.isXRF = true )
|
||||||
if( mesh.material ) mesh.material.visible = false
|
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) => {
|
const externalSRC = (url,frag,src) => {
|
||||||
fetch(url, { method: 'HEAD' })
|
fetch(url, { method: 'HEAD' })
|
||||||
.then( (res) => {
|
.then( (res) => {
|
||||||
|
@ -1690,8 +1722,8 @@ xrf.frag.src = function(v, opts){
|
||||||
.catch( console.error )
|
.catch( console.error )
|
||||||
}
|
}
|
||||||
|
|
||||||
if( url[0] == "#" ) addScene(scene,url,frag) // current file
|
if( url[0] == "#" ) addScene(scene,url,vfrag) // current file
|
||||||
else externalSRC(url,frag) // external file
|
else externalSRC(url,vfrag) // external file
|
||||||
}
|
}
|
||||||
|
|
||||||
xrf.frag.src.eval = function(scene, opts, url){
|
xrf.frag.src.eval = function(scene, opts, url){
|
||||||
|
|
|
@ -80,7 +80,7 @@ value: draft-XRFRAGMENTS-leonvankammen-00
|
||||||
|
|
||||||
<h1 class="special" id="abstract">Abstract</h1>
|
<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>
|
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>
|
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>
|
<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>
|
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>
|
XR Fragments allows us to enrich/connect existing dataformats, by introducing existing technologies/ideas:<br></p>
|
||||||
|
|
||||||
<ol>
|
<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>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>
|
<li>unlocking spatial potential of the (originally 2D) hashtag (which jumps to a chapter) for navigating XR documents</li>
|
||||||
</ol>
|
</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>
|
<p>Traditional webbrowsers can become 4D document-ready by:</p>
|
||||||
|
|
||||||
<ul>
|
<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>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>
|
<li>collapsing the 3D scene to an wordgraph (for essential navigation purposes) controllable thru a hash(tag)bus</li>
|
||||||
</ul>
|
</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>
|
<h1 id="conventions-and-definitions">Conventions and Definitions</h1>
|
||||||
|
|
||||||
|
@ -275,9 +275,9 @@ sub-delims = "," / "="
|
||||||
|
|
||||||
<tr>
|
<tr>
|
||||||
<td><code>#t</code></td>
|
<td><code>#t</code></td>
|
||||||
<td>vector2</td>
|
<td>vector3</td>
|
||||||
<td><code>#t=500,1000</code></td>
|
<td><code>#t=1,500,1000</code></td>
|
||||||
<td>sets animation-loop range between frame 500 and 1000</td>
|
<td>play animation-loop range between frame 500 and 1000, at normal speed</td>
|
||||||
</tr>
|
</tr>
|
||||||
|
|
||||||
<tr>
|
<tr>
|
||||||
|
@ -307,22 +307,6 @@ sub-delims = "," / "="
|
||||||
</thead>
|
</thead>
|
||||||
|
|
||||||
<tbody>
|
<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>
|
<tr>
|
||||||
<td><code>href</code></td>
|
<td><code>href</code></td>
|
||||||
<td>string</td>
|
<td>string</td>
|
||||||
|
@ -338,16 +322,26 @@ sub-delims = "," / "="
|
||||||
<td>XR embed / teleport</td>
|
<td>XR embed / teleport</td>
|
||||||
<td>custom property in 3D fileformats</td>
|
<td>custom property in 3D fileformats</td>
|
||||||
</tr>
|
</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>
|
</tbody>
|
||||||
</table>
|
</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>
|
<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>
|
<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>
|
</blockquote>
|
||||||
|
|
||||||
<h1 id="spatial-referencing-3d">Spatial Referencing 3D</h1>
|
<h1 id="spatial-referencing-3d">Spatial Referencing 3D</h1>
|
||||||
|
|
||||||
|
<p>XR Fragments assume the following objectname-to-URIFragment mapping:</p>
|
||||||
|
|
||||||
<pre><code>
|
<pre><code>
|
||||||
my.io/scene.fbx
|
my.io/scene.fbx
|
||||||
+─────────────────────────────+
|
+─────────────────────────────+
|
||||||
|
@ -366,6 +360,10 @@ sub-delims = "," / "="
|
||||||
|
|
||||||
</code></pre>
|
</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>
|
<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>
|
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>
|
</ul>
|
||||||
|
|
||||||
<blockquote>
|
<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>
|
</blockquote>
|
||||||
|
|
||||||
<h1 id="navigating-3d">Navigating 3D</h1>
|
<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>
|
<tr>
|
||||||
<td><b>#t</b>=0,100</td>
|
<td><b>#t</b>=0,100</td>
|
||||||
<td>vector2</td>
|
<td>vector3</td>
|
||||||
<td>(re)position looprange of scene-animation or <code>src</code>-mediacontent</td>
|
<td>set playback speed, and (re)position looprange of scene-animation or <code>src</code>-mediacontent</td>
|
||||||
</tr>
|
</tr>
|
||||||
|
|
||||||
<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>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>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>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>
|
<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>
|
</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/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>
|
<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>
|
<p>navigation, portals & mutations</p>
|
||||||
|
|
||||||
|
@ -556,7 +554,7 @@ Resizing will be happen accordingly to its placeholder object <code>aquariumcube
|
||||||
</table>
|
</table>
|
||||||
|
|
||||||
<ol>
|
<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>
|
<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>
|
<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>
|
</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>
|
<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>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>
|
<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>
|
</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>
|
<p>For example:</p>
|
||||||
|
|
||||||
<pre><code> +────────────────────────────────────────────────────────+
|
<pre><code> +────────────────────────────────────────────────────────+
|
||||||
|
@ -1105,19 +1107,45 @@ here are some hashtagbibs followed by bibtex:
|
||||||
│ │ │
|
│ │ │
|
||||||
│ ├── ◻ buttonA │
|
│ ├── ◻ buttonA │
|
||||||
│ │ └ href: http://foo.io/campagne.fbx │
|
│ │ └ href: http://foo.io/campagne.fbx │
|
||||||
│ │ └ href!404: ipfs://foo.io/campagne.fbx │
|
│ │ └ href@404: ipfs://foo.io/campagne.fbx │
|
||||||
│ │ └ href!400: #q=clienterrortext │
|
│ │ └ href@400: #q=clienterrortext │
|
||||||
│ │ └ ◻ offlinetext │
|
│ │ └ ◻ offlinetext │
|
||||||
│ │ │
|
│ │ │
|
||||||
│ └── ◻ embeddedObject <--------- the meshdata inside embeddedObject will (not)
|
│ └── ◻ embeddedObject <--------- the meshdata inside embeddedObject will (not)
|
||||||
│ └ src: https://foo.io/bar.gltf │ be flushed when the request (does not) succeed.
|
│ └ 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@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@400: https://archive.org/l2kj43.gltf │ will be displayed.
|
||||||
│ │
|
│ │
|
||||||
+────────────────────────────────────────────────────────+
|
+────────────────────────────────────────────────────────+
|
||||||
|
|
||||||
</code></pre>
|
</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>
|
<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>
|
<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>
|
<hr>
|
||||||
|
|
||||||
<p><strong>Q:</strong> Why isn’t there support for scripting
|
<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, 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>
|
<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>
|
<h1 id="iana-considerations">IANA Considerations</h1>
|
||||||
|
|
||||||
|
|
|
@ -199,17 +199,19 @@ sub-delims = "," / "="
|
||||||
|
|
||||||
| key | type | example (JSON) | function | existing compatibility |
|
| 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 |
|
| `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.
|
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
|
# Spatial Referencing 3D
|
||||||
|
|
||||||
|
|
||||||
|
XR Fragments assume the following objectname-to-URIFragment mapping:
|
||||||
|
|
||||||
```
|
```
|
||||||
|
|
||||||
my.io/scene.fbx
|
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>
|
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:
|
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 Engineering Task Force L.R. van Kammen
|
||||||
Internet-Draft 22 September 2023
|
Internet-Draft 12 October 2023
|
||||||
Intended status: Informational
|
Intended status: Informational
|
||||||
|
|
||||||
|
|
||||||
|
@ -13,9 +13,10 @@ Intended status: Informational
|
||||||
|
|
||||||
Abstract
|
Abstract
|
||||||
|
|
||||||
This draft is a specification for 4D URLs & navigation, which links
|
This draft is a specification for 4D URLs & hypermediatic
|
||||||
together space, time & text together, for hypermedia browsers with-
|
(https://github.com/coderofsalvation/hypermediatic) navigation, which
|
||||||
or without a network-connection.
|
links together space, time & text together, for hypermedia browsers
|
||||||
|
with- or without a network-connection.
|
||||||
The specification promotes spatial addressibility, sharing,
|
The specification promotes spatial addressibility, sharing,
|
||||||
navigation, query-ing and annotating interactive (text)objects across
|
navigation, query-ing and annotating interactive (text)objects across
|
||||||
for (XR) Browsers.
|
for (XR) Browsers.
|
||||||
|
@ -41,7 +42,7 @@ Status of This Memo
|
||||||
time. It is inappropriate to use Internet-Drafts as reference
|
time. It is inappropriate to use Internet-Drafts as reference
|
||||||
material or to cite them other than as "work in progress."
|
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
|
Copyright Notice
|
||||||
|
|
||||||
|
@ -52,10 +53,9 @@ Copyright Notice
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
van Kammen Expires 14 April 2024 [Page 1]
|
||||||
van Kammen Expires 25 March 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
|
This document is subject to BCP 78 and the IETF Trust's Legal
|
||||||
|
@ -79,7 +79,7 @@ Table of Contents
|
||||||
7. Navigating 3D . . . . . . . . . . . . . . . . . . . . . . . . 8
|
7. Navigating 3D . . . . . . . . . . . . . . . . . . . . . . . . 8
|
||||||
8. Top-level URL processing . . . . . . . . . . . . . . . . . . 9
|
8. Top-level URL processing . . . . . . . . . . . . . . . . . . 9
|
||||||
9. Embedding XR content (src-instancing) . . . . . . . . . . . . 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.1. UX spec . . . . . . . . . . . . . . . . . . . . . . . . 13
|
||||||
10.2. Scaling instanced content . . . . . . . . . . . . . . . 13
|
10.2. Scaling instanced content . . . . . . . . . . . . . . . 13
|
||||||
11. XR Fragment queries . . . . . . . . . . . . . . . . . . . . . 14
|
11. XR Fragment queries . . . . . . . . . . . . . . . . . . . . . 14
|
||||||
|
@ -90,12 +90,13 @@ Table of Contents
|
||||||
13.1. Default Data URI mimetype . . . . . . . . . . . . . . . 20
|
13.1. Default Data URI mimetype . . . . . . . . . . . . . . . 20
|
||||||
13.2. URL and Data URI . . . . . . . . . . . . . . . . . . . . 21
|
13.2. URL and Data URI . . . . . . . . . . . . . . . . . . . . 21
|
||||||
13.3. XR Text example parser . . . . . . . . . . . . . . . . . 22
|
13.3. XR Text example parser . . . . . . . . . . . . . . . . . 22
|
||||||
14. Broken links . . . . . . . . . . . . . . . . . . . . . . . . 24
|
14. Transclusion (broken link) resolution . . . . . . . . . . . . 24
|
||||||
15. Security Considerations . . . . . . . . . . . . . . . . . . . 25
|
15. Topic-based index-less Webrings . . . . . . . . . . . . . . . 25
|
||||||
16. FAQ . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 25
|
16. Security Considerations . . . . . . . . . . . . . . . . . . . 26
|
||||||
17. IANA Considerations . . . . . . . . . . . . . . . . . . . . . 26
|
17. FAQ . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 26
|
||||||
18. Acknowledgments . . . . . . . . . . . . . . . . . . . . . . . 26
|
18. IANA Considerations . . . . . . . . . . . . . . . . . . . . . 27
|
||||||
19. Appendix: Definitions . . . . . . . . . . . . . . . . . . . . 26
|
19. Acknowledgments . . . . . . . . . . . . . . . . . . . . . . . 27
|
||||||
|
20. Appendix: Definitions . . . . . . . . . . . . . . . . . . . . 27
|
||||||
|
|
||||||
1. Introduction
|
1. Introduction
|
||||||
|
|
||||||
|
@ -103,20 +104,23 @@ Table of Contents
|
||||||
introducing new dataformats?
|
introducing new dataformats?
|
||||||
Historically, there's many attempts to create the ultimate
|
Historically, there's many attempts to create the ultimate
|
||||||
markuplanguage or 3D fileformat.
|
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
|
XR Fragments allows us to enrich/connect existing dataformats, by
|
||||||
introducing existing technologies/ideas:
|
introducing existing technologies/ideas:
|
||||||
|
|
||||||
|
1. addressibility and hypermediatic
|
||||||
|
(https://github.com/coderofsalvation/hypermediatic) navigation of
|
||||||
van Kammen Expires 25 March 2024 [Page 2]
|
3D scenes/objects: URI Fragments (https://en.wikipedia.org/wiki/
|
||||||
|
URI_fragment) + src/href spatial metadata
|
||||||
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
|
|
||||||
2. Interlinking text/& 3D by collapsing space into a Word Graph
|
2. Interlinking text/& 3D by collapsing space into a Word Graph
|
||||||
(XRWG) to show visible links (#visible-links) (and augmenting
|
(XRWG) to show visible links (#visible-links) (and augmenting
|
||||||
text with bibs (https://github.com/coderofsalvation/tagbibs) /
|
text with bibs (https://github.com/coderofsalvation/tagbibs) /
|
||||||
|
@ -161,13 +165,9 @@ Internet-Draft XR Fragments September 2023
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
van Kammen Expires 14 April 2024 [Page 3]
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
van Kammen Expires 25 March 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:
|
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).
|
HTML).
|
||||||
* allowing assets to publish hashtags to themselves (the scene)
|
* allowing assets to publish hashtags to themselves (the scene)
|
||||||
using the hashbus (like hashtags controlling the scrollbar).
|
using the hashbus (like hashtags controlling the scrollbar).
|
||||||
* collapsing the 3D scene to an wordgraph (for essential navigation
|
* collapsing the 3D scene to an wordgraph (for essential navigation
|
||||||
purposes) controllable thru a hash(tag)bus
|
purposes) controllable thru a hash(tag)bus
|
||||||
|
|
||||||
XR Fragments itself are HTML-agnostic, though pseudo-XR Fragment
|
XR Fragments itself are hypermediatic
|
||||||
browsers *can* be implemented on top of HTML/Javascript.
|
(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
|
3. Conventions and Definitions
|
||||||
|
|
||||||
|
@ -274,12 +277,9 @@ Internet-Draft XR Fragments September 2023
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
van Kammen Expires 14 April 2024 [Page 5]
|
||||||
|
|
||||||
|
|
||||||
van Kammen Expires 25 March 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
|
4. List of URI Fragments
|
||||||
|
|
||||||
+==========+=========+==============+==============================+
|
+==========+=========+===============+==============================+
|
||||||
| fragment | type | example | info |
|
| fragment | type | example | info |
|
||||||
+==========+=========+==============+==============================+
|
+==========+=========+===============+==============================+
|
||||||
| #pos | vector3 | #pos=0.5,0,0 | positions camera (or XR |
|
| #pos | vector3 | #pos=0.5,0,0 | positions camera (or XR |
|
||||||
| | | | floor) to xyz-coord 0.5,0,0, |
|
| | | | floor) to xyz-coord |
|
||||||
+----------+---------+--------------+------------------------------+
|
| | | | 0.5,0,0, |
|
||||||
| #rot | vector3 | #rot=0,90,0 | rotates camera 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 |
|
| #t | vector3 | #t=1,500,1000 | play animation-loop range |
|
||||||
+----------+---------+--------------+------------------------------+
|
| | | | between frame 500 and |
|
||||||
| #...... | string | #.cubes | predefined views, XRWG |
|
| | | | 1000, at normal speed |
|
||||||
| | | #cube | fragments and ID fragments |
|
+----------+---------+---------------+------------------------------+
|
||||||
+----------+---------+--------------+------------------------------+
|
| #...... | 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
|
| xyz coordinates are similar to ones found in SVG Media Fragments
|
||||||
|
|
||||||
5. List of metadata for 3D nodes
|
5. List of metadata for 3D nodes
|
||||||
|
|
||||||
+======+========+=============+===========+=========================+
|
+======+========+==========+==================+===================+
|
||||||
| key | type | example | function | existing compatibility |
|
| key | type | example | function | existing |
|
||||||
| | | (JSON) | | |
|
| | | (JSON) | | compatibility |
|
||||||
+======+========+=============+===========+=========================+
|
+======+========+==========+==================+===================+
|
||||||
| name | string | "name": | identify/ | object supported in all |
|
| href | string | "href": | XR teleport | custom property |
|
||||||
| | | "cube" | tag | 3D fileformats & scenes |
|
| | | "b.gltf" | | in 3D fileformats |
|
||||||
+------+--------+-------------+-----------+-------------------------+
|
+------+--------+----------+------------------+-------------------+
|
||||||
| tag | string | "tag": | tag | custom property in 3D |
|
| src | string | "src": | XR embed / | custom property |
|
||||||
| | | "cubes | object | fileformats |
|
| | | "#cube" | teleport | in 3D fileformats |
|
||||||
| | | geo" | | |
|
|
||||||
+------+--------+-------------+-----------+-------------------------+
|
|
||||||
| href | string | "href": | XR | custom property in 3D |
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
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 |
|
+------+--------+----------+------------------+-------------------+
|
||||||
+------+--------+-------------+-----------+-------------------------+
|
| tag | string | "tag": | tag object (for | custom property |
|
||||||
| src | string | "src": | XR embed | custom property in 3D |
|
| | | "cubes | query-use / XRWG | in 3D fileformats |
|
||||||
| | | "#cube" | / | fileformats |
|
| | | geo" | highlighting) | |
|
||||||
| | | | teleport | |
|
+------+--------+----------+------------------+-------------------+
|
||||||
+------+--------+-------------+-----------+-------------------------+
|
|
||||||
|
|
||||||
Table 4
|
Table 4
|
||||||
|
|
||||||
Supported popular compatible 3D fileformats: .gltf, .obj, .fbx,
|
Supported popular compatible 3D fileformats: .gltf, .obj, .fbx,
|
||||||
.usdz, .json (THREE.js), .dae and so on.
|
.usdz, .json (THREE.js), .dae and so on.
|
||||||
|
|
||||||
| NOTE: XR Fragments are file-agnostic, which means that the
|
| NOTE: XR Fragments are optional but also file- and protocol-
|
||||||
| metadata exist in programmatic 3D scene(nodes) too.
|
| agnostic, which means that programmatic 3D scene(nodes) can also
|
||||||
|
| use the mechanism/metadata.
|
||||||
|
|
||||||
6. Spatial Referencing 3D
|
6. Spatial Referencing 3D
|
||||||
|
|
||||||
|
XR Fragments assume the following objectname-to-URIFragment mapping:
|
||||||
|
|
||||||
my.io/scene.fbx
|
my.io/scene.fbx
|
||||||
+─────────────────────────────+
|
+─────────────────────────────+
|
||||||
│ sky │ src: http://my.io/scene.fbx#sky (includes building,mainobject,floor)
|
│ 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
|
Clever nested design of 3D scenes allow great ways for re-using
|
||||||
content, and/or previewing scenes.
|
content, and/or previewing scenes.
|
||||||
For example, to render a portal with a preview-version of the scene,
|
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
|
* href: https://scene.fbx
|
||||||
* src: https://otherworld.gltf#mainobject
|
* 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
|
| It also allows *sourceportation*, which basically means the
|
||||||
| enduser can teleport to the original XR Document of an src
|
| enduser can teleport to the original XR Document of an src
|
||||||
| embedded object, and see a visible connection to the particular
|
| embedded object, and see a visible connection to the particular
|
||||||
| embedded object.
|
| embedded object. Basically an embedded link becoming an outbound
|
||||||
|
| link by activating it.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
van Kammen Expires 25 March 2024 [Page 7]
|
|
||||||
|
|
||||||
Internet-Draft XR Fragments September 2023
|
|
||||||
|
|
||||||
|
|
||||||
7. Navigating 3D
|
7. Navigating 3D
|
||||||
|
|
||||||
|
@ -401,7 +407,8 @@ Internet-Draft XR Fragments September 2023
|
||||||
+====================+=========+==================================+
|
+====================+=========+==================================+
|
||||||
| <b>#pos</b>=0,0,0 | vector3 | (re)position camera |
|
| <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 |
|
| | | animation or src-mediacontent |
|
||||||
+--------------------+---------+----------------------------------+
|
+--------------------+---------+----------------------------------+
|
||||||
| <b>#rot</b>=0,90,0 | vector3 | rotate camera |
|
| <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
|
2. set the position of the camera accordingly to the vector3 values
|
||||||
of #pos
|
of #pos
|
||||||
3. rot sets the rotation of the camera (only for non-VR/AR headsets)
|
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
|
4. t sets the playbackspeed and animation-range of the current scene
|
||||||
src-mediacontent (video/audioframes e.g., use t=7,7 to 'STOP' at
|
animation(s) or src-mediacontent (video/audioframes e.g., use
|
||||||
certain frame)
|
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
|
5. in case an href does not mention any pos-coordinate, pos=0,0,0
|
||||||
will be assumed
|
will be assumed
|
||||||
|
|
||||||
Here's an ascii representation of a 3D scene-graph which contains 3D
|
Here's an ascii representation of a 3D scene-graph which contains 3D
|
||||||
objects ◻ and their metadata:
|
objects ◻ and their metadata:
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
van Kammen Expires 14 April 2024 [Page 8]
|
||||||
|
|
||||||
|
Internet-Draft XR Fragments October 2023
|
||||||
|
|
||||||
|
|
||||||
+────────────────────────────────────────────────────────+
|
+────────────────────────────────────────────────────────+
|
||||||
│ │
|
│ │
|
||||||
│ index.gltf │
|
│ 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-
|
An XR Fragment-compatible browser viewing this scene, allows the end-
|
||||||
user to interact with the buttonA and buttonB.
|
user to interact with the buttonA and buttonB.
|
||||||
In case of buttonA the end-user will be teleported to another
|
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 14 April 2024 [Page 9]
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
van Kammen Expires 25 March 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
|
| 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
|
» example implementation
|
||||||
|
@ -627,7 +627,7 @@ Internet-Draft XR Fragments September 2023
|
||||||
» discussion (https://github.com/coderofsalvation/xrfragment/
|
» discussion (https://github.com/coderofsalvation/xrfragment/
|
||||||
issues/4)
|
issues/4)
|
||||||
|
|
||||||
10. Navigating content (href portals)
|
10. Navigating content (internal/outbound href portals)
|
||||||
|
|
||||||
navigation, portals & mutations
|
navigation, portals & mutations
|
||||||
|
|
||||||
|
@ -641,9 +641,9 @@ Internet-Draft XR Fragments September 2023
|
||||||
|
|
||||||
Table 7
|
Table 7
|
||||||
|
|
||||||
1. clicking an ''external''- or ''file URI'' fully replaces the
|
1. clicking an outbound ''external''- or ''file URI'' fully replaces
|
||||||
current scene and assumes pos=0,0,0&rot=0,0,0 by default (unless
|
the current scene and assumes pos=0,0,0&rot=0,0,0 by default
|
||||||
specified)
|
(unless specified)
|
||||||
|
|
||||||
2. relocation/reorientation should happen locally for local URI's
|
2. relocation/reorientation should happen locally for local URI's
|
||||||
(#pos=....)
|
(#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
|
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
|
| 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
|
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
|
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
|
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)
|
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
|
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
|
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
|
* 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
|
// 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 = `
|
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
|
| nonmatching tags (@book{nonmatchingbook e.g.) should be performed
|
||||||
| and prompt the enduser for deleting them.
|
| 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
|
In spirit of Ted Nelson's 'transclusion resolution', there's a soft-
|
||||||
various ways:
|
mechanism to harden links & minimize broken links in various ways:
|
||||||
|
|
||||||
1. defining a different transport protocol (https vs ipfs or DAT) in
|
1. defining a different transport protocol (https vs ipfs or DAT) in
|
||||||
src or href values can make a difference
|
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
|
2. mirroring files on another protocol using (HTTP) errorcode tags
|
||||||
href properties
|
in src or href properties
|
||||||
3. in case of src: nesting a copy of the embedded object in the
|
3. in case of src: nesting a copy of the embedded object in the
|
||||||
placeholder object (embeddedObject) will not be replaced when the
|
placeholder object (embeddedObject) will not be replaced when the
|
||||||
request fails
|
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:
|
For example:
|
||||||
|
|
||||||
+────────────────────────────────────────────────────────+
|
+────────────────────────────────────────────────────────+
|
||||||
|
@ -1362,18 +1366,53 @@ Internet-Draft XR Fragments September 2023
|
||||||
│ │ │
|
│ │ │
|
||||||
│ ├── ◻ buttonA │
|
│ ├── ◻ buttonA │
|
||||||
│ │ └ href: http://foo.io/campagne.fbx │
|
│ │ └ href: http://foo.io/campagne.fbx │
|
||||||
│ │ └ href!404: ipfs://foo.io/campagne.fbx │
|
│ │ └ href@404: ipfs://foo.io/campagne.fbx │
|
||||||
│ │ └ href!400: #q=clienterrortext │
|
│ │ └ href@400: #q=clienterrortext │
|
||||||
│ │ └ ◻ offlinetext │
|
│ │ └ ◻ offlinetext │
|
||||||
│ │ │
|
│ │ │
|
||||||
│ └── ◻ embeddedObject <--------- the meshdata inside embeddedObject will (not)
|
│ └── ◻ embeddedObject <--------- the meshdata inside embeddedObject will (not)
|
||||||
│ └ src: https://foo.io/bar.gltf │ be flushed when the request (does not) succeed.
|
│ └ 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@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@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
|
Since XR Text contains metadata too, the user should be able to set
|
||||||
up tagging-rules, so the copy-paste feature can :
|
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
|
* filter out sensitive data when copy/pasting (XR text with
|
||||||
tag:secret e.g.)
|
tag:secret e.g.)
|
||||||
|
|
||||||
16. FAQ
|
17. FAQ
|
||||||
|
|
||||||
*Q:* Why is everything HTTP GET-based, what about POST/PUT/DELETE
|
*Q:* Why is everything HTTP GET-based, what about POST/PUT/DELETE
|
||||||
HATEOS
|
HATEOS
|
||||||
|
@ -1390,38 +1429,50 @@ Internet-Draft XR Fragments September 2023
|
||||||
(for example, an XR Hypermedia browser can decide to support
|
(for example, an XR Hypermedia browser can decide to support
|
||||||
POST/PUT/DELETE requests for embedded HTML thru src values)
|
POST/PUT/DELETE requests for embedded HTML thru src values)
|
||||||
|
|
||||||
*Q:* Why isn't there support for scripting *A:* This is out of scope,
|
*Q:* Why isn't there support for scripting, while we have things like
|
||||||
and up to the XR hypermedia browser. Javascript seems to been able
|
WASM *A:* This is out of scope as it unhyperifies hypermedia, and
|
||||||
to turn webpages from hypermedia documents into its opposite
|
this is up to XR hypermedia browser-extensions.
|
||||||
(hyperscripted nonhypermedia documents). In order to prevent this
|
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
|
||||||
van Kammen Expires 25 March 2024 [Page 25]
|
liberate people from finnicky scripting) XR Fragments should never
|
||||||
|
unhyperify itself by hardcoupling to a particular markup or scripting
|
||||||
Internet-Draft XR Fragments September 2023
|
language. XR Macro's (https://xrfragment.org/doc/RFC_XR_Macros.html)
|
||||||
|
are an example of something which is probably smarter and safer for
|
||||||
|
|
||||||
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
|
hypermedia browsers to implement, instead of going full-in with a
|
||||||
turing-complete scripting language (and suffer the security
|
turing-complete scripting language (and suffer the security
|
||||||
consequences later).
|
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.
|
This document has no IANA actions.
|
||||||
|
|
||||||
18. Acknowledgments
|
19. Acknowledgments
|
||||||
|
|
||||||
* NLNET (https://nlnet.nl)
|
* NLNET (https://nlnet.nl)
|
||||||
* Future of Text (https://futureoftext.org)
|
* Future of Text (https://futureoftext.org)
|
||||||
* visual-meta.info (https://visual-meta.info)
|
* visual-meta.info (https://visual-meta.info)
|
||||||
|
|
||||||
19. Appendix: Definitions
|
20. Appendix: Definitions
|
||||||
|
|
||||||
+=================+===============================================+
|
+=================+===============================================+
|
||||||
| definition | explanation |
|
| definition | explanation |
|
||||||
|
@ -1450,19 +1501,19 @@ Internet-Draft XR Fragments September 2023
|
||||||
| spacetime | positions camera, triggers scene-preset/time |
|
| spacetime | positions camera, triggers scene-preset/time |
|
||||||
| hashtags | |
|
| hashtags | |
|
||||||
+-----------------+-----------------------------------------------+
|
+-----------------+-----------------------------------------------+
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
van Kammen Expires 25 March 2024 [Page 26]
|
|
||||||
|
|
||||||
Internet-Draft XR Fragments September 2023
|
|
||||||
|
|
||||||
|
|
||||||
| teleportation | repositioning the enduser to a different |
|
| teleportation | repositioning the enduser to a different |
|
||||||
| | position (or 3D scene/file) |
|
| | position (or 3D scene/file) |
|
||||||
+-----------------+-----------------------------------------------+
|
+-----------------+-----------------------------------------------+
|
||||||
| sourceportation | teleporting the enduser to the original XR |
|
| sourceportation | teleporting the enduser to the original XR |
|
||||||
| | Document of an src embedded object. |
|
| | 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 |
|
| placeholder | a 3D object which with src-metadata (which |
|
||||||
| object | will be replaced by the src-data.) |
|
| object | will be replaced by the src-data.) |
|
||||||
|
@ -1506,14 +1557,6 @@ Internet-Draft XR Fragments September 2023
|
||||||
| BibTag | a BibTeX tag |
|
| BibTag | a BibTeX tag |
|
||||||
+-----------------+-----------------------------------------------+
|
+-----------------+-----------------------------------------------+
|
||||||
| (hashtag)bibs | an easy to speak/type/scan tagging SDL (see |
|
| (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/ |
|
| | here (https://github.com/coderofsalvation/ |
|
||||||
| | hashtagbibs) which expands to BibTex/JSON/XML |
|
| | hashtagbibs) which expands to BibTex/JSON/XML |
|
||||||
+-----------------+-----------------------------------------------+
|
+-----------------+-----------------------------------------------+
|
||||||
|
@ -1522,47 +1565,4 @@ Internet-Draft XR Fragments September 2023
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
van Kammen Expires 14 April 2024 [Page 28]
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
van Kammen Expires 25 March 2024 [Page 28]
|
|
||||||
|
|
|
@ -10,7 +10,7 @@
|
||||||
<workgroup>Internet Engineering Task Force</workgroup>
|
<workgroup>Internet Engineering Task Force</workgroup>
|
||||||
|
|
||||||
<abstract>
|
<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 />
|
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 />
|
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 />
|
XR Fragments allows us to enrich/connect existing dataformats, by introducing existing technologies/ideas:<br />
|
||||||
</t>
|
</t>
|
||||||
|
|
||||||
<ol spacing="compact">
|
<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>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>
|
<li>unlocking spatial potential of the (originally 2D) hashtag (which jumps to a chapter) for navigating XR documents</li>
|
||||||
</ol>
|
</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>
|
<t>Traditional webbrowsers can become 4D document-ready by:</t>
|
||||||
|
|
||||||
<ul spacing="compact">
|
<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>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>
|
<li>collapsing the 3D scene to an wordgraph (for essential navigation purposes) controllable thru a hash(tag)bus</li>
|
||||||
</ul>
|
</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>
|
||||||
|
|
||||||
<section anchor="conventions-and-definitions"><name>Conventions and Definitions</name>
|
<section anchor="conventions-and-definitions"><name>Conventions and Definitions</name>
|
||||||
|
@ -200,9 +200,9 @@ sub-delims = "," / "="
|
||||||
|
|
||||||
<tr>
|
<tr>
|
||||||
<td><tt>#t</tt></td>
|
<td><tt>#t</tt></td>
|
||||||
<td>vector2</td>
|
<td>vector3</td>
|
||||||
<td><tt>#t=500,1000</tt></td>
|
<td><tt>#t=1,500,1000</tt></td>
|
||||||
<td>sets animation-loop range between frame 500 and 1000</td>
|
<td>play animation-loop range between frame 500 and 1000, at normal speed</td>
|
||||||
</tr>
|
</tr>
|
||||||
|
|
||||||
<tr>
|
<tr>
|
||||||
|
@ -228,22 +228,6 @@ sub-delims = "," / "="
|
||||||
</thead>
|
</thead>
|
||||||
|
|
||||||
<tbody>
|
<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>
|
<tr>
|
||||||
<td><tt>href</tt></td>
|
<td><tt>href</tt></td>
|
||||||
<td>string</td>
|
<td>string</td>
|
||||||
|
@ -259,12 +243,21 @@ sub-delims = "," / "="
|
||||||
<td>XR embed / teleport</td>
|
<td>XR embed / teleport</td>
|
||||||
<td>custom property in 3D fileformats</td>
|
<td>custom property in 3D fileformats</td>
|
||||||
</tr>
|
</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>
|
</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>
|
</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>
|
</blockquote></section>
|
||||||
|
|
||||||
<section anchor="spatial-referencing-3d"><name>Spatial Referencing 3D</name>
|
<section anchor="spatial-referencing-3d"><name>Spatial Referencing 3D</name>
|
||||||
|
<t>XR Fragments assume the following objectname-to-URIFragment mapping:</t>
|
||||||
|
|
||||||
<artwork>
|
<artwork>
|
||||||
my.io/scene.fbx
|
my.io/scene.fbx
|
||||||
|
@ -283,7 +276,8 @@ sub-delims = "," / "="
|
||||||
+─────────────────────────────+
|
+─────────────────────────────+
|
||||||
|
|
||||||
</artwork>
|
</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>
|
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>href: <tt>https://scene.fbx</tt></li>
|
||||||
<li>src: <tt>https://otherworld.gltf#mainobject</tt></li>
|
<li>src: <tt>https://otherworld.gltf#mainobject</tt></li>
|
||||||
</ul>
|
</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>
|
</blockquote></section>
|
||||||
|
|
||||||
<section anchor="navigating-3d"><name>Navigating 3D</name>
|
<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>
|
<tr>
|
||||||
<td><b>#t</b>=0,100</td>
|
<td><b>#t</b>=0,100</td>
|
||||||
<td>vector2</td>
|
<td>vector3</td>
|
||||||
<td>(re)position looprange of scene-animation or <tt>src</tt>-mediacontent</td>
|
<td>set playback speed, and (re)position looprange of scene-animation or <tt>src</tt>-mediacontent</td>
|
||||||
</tr>
|
</tr>
|
||||||
|
|
||||||
<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>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>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>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>
|
<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>
|
</ol>
|
||||||
<t>Here's an ascii representation of a 3D scene-graph which contains 3D objects <tt>◻</tt> and their metadata:</t>
|
<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>
|
</t>
|
||||||
</section>
|
</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>
|
<t>navigation, portals & mutations</t>
|
||||||
<table>
|
<table>
|
||||||
<thead>
|
<thead>
|
||||||
|
@ -473,7 +467,7 @@ Resizing will be happen accordingly to its placeholder object <tt>aquariumcube</
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
<ol>
|
<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>
|
||||||
<li><t>relocation/reorientation should happen locally for local URI's (<tt>#pos=....</tt>)</t>
|
<li><t>relocation/reorientation should happen locally for local URI's (<tt>#pos=....</tt>)</t>
|
||||||
</li>
|
</li>
|
||||||
|
@ -943,15 +937,16 @@ here are some hashtagbibs followed by bibtex:
|
||||||
</blockquote></section>
|
</blockquote></section>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
<section anchor="broken-links"><name>Broken links</name>
|
<section anchor="transclusion-broken-link-resolution"><name>Transclusion (broken link) resolution</name>
|
||||||
<t>There's a soft-mechanism to harden links & prevent broken links in various ways:</t>
|
<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">
|
<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>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>
|
<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>
|
</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> +────────────────────────────────────────────────────────+
|
<artwork> +────────────────────────────────────────────────────────+
|
||||||
│ │
|
│ │
|
||||||
|
@ -961,20 +956,43 @@ here are some hashtagbibs followed by bibtex:
|
||||||
│ │ │
|
│ │ │
|
||||||
│ ├── ◻ buttonA │
|
│ ├── ◻ buttonA │
|
||||||
│ │ └ href: http://foo.io/campagne.fbx │
|
│ │ └ href: http://foo.io/campagne.fbx │
|
||||||
│ │ └ href!404: ipfs://foo.io/campagne.fbx │
|
│ │ └ href@404: ipfs://foo.io/campagne.fbx │
|
||||||
│ │ └ href!400: #q=clienterrortext │
|
│ │ └ href@400: #q=clienterrortext │
|
||||||
│ │ └ ◻ offlinetext │
|
│ │ └ ◻ offlinetext │
|
||||||
│ │ │
|
│ │ │
|
||||||
│ └── ◻ embeddedObject <--------- the meshdata inside embeddedObject will (not)
|
│ └── ◻ embeddedObject <--------- the meshdata inside embeddedObject will (not)
|
||||||
│ └ src: https://foo.io/bar.gltf │ be flushed when the request (does not) succeed.
|
│ └ 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@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@400: https://archive.org/l2kj43.gltf │ will be displayed.
|
||||||
│ │
|
│ │
|
||||||
+────────────────────────────────────────────────────────+
|
+────────────────────────────────────────────────────────+
|
||||||
|
|
||||||
</artwork>
|
</artwork>
|
||||||
</section>
|
</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>
|
<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>
|
<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 />
|
<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>
|
<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
|
<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, 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>
|
<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>
|
||||||
|
|
||||||
<section anchor="iana-considerations"><name>IANA Considerations</name>
|
<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>
|
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>
|
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>
|
<h2 id="usecase-click-object">Usecase: click object</h2>
|
||||||
|
|
||||||
<table>
|
<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>
|
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>
|
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
|
## Usecase: click object
|
||||||
|
|
||||||
| custom property | value | trigger when |
|
| custom property | value | trigger when |
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
|
|
||||||
|
|
||||||
Internet Engineering Task Force L.R. van Kammen
|
Internet Engineering Task Force L.R. van Kammen
|
||||||
Internet-Draft 22 September 2023
|
Internet-Draft 12 October 2023
|
||||||
Intended status: Informational
|
Intended status: Informational
|
||||||
|
|
||||||
|
|
||||||
|
@ -38,7 +38,7 @@ Status of This Memo
|
||||||
time. It is inappropriate to use Internet-Drafts as reference
|
time. It is inappropriate to use Internet-Drafts as reference
|
||||||
material or to cite them other than as "work in progress."
|
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
|
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
|
extracted from this document must include Revised BSD License text as
|
||||||
|
@ -68,17 +68,17 @@ Table of Contents
|
||||||
2. Core principle . . . . . . . . . . . . . . . . . . . . . . . 2
|
2. Core principle . . . . . . . . . . . . . . . . . . . . . . . 2
|
||||||
3. Conventions and Definitions . . . . . . . . . . . . . . . . . 3
|
3. Conventions and Definitions . . . . . . . . . . . . . . . . . 3
|
||||||
4. List of XR Macros . . . . . . . . . . . . . . . . . . . . . . 3
|
4. List of XR Macros . . . . . . . . . . . . . . . . . . . . . . 3
|
||||||
4.1. Usecase: click object . . . . . . . . . . . . . . . . . . 3
|
4.1. Usecase: click object . . . . . . . . . . . . . . . . . . 4
|
||||||
4.2. Usecase: conditional click object . . . . . . . . . . . . 3
|
4.2. Usecase: conditional click object . . . . . . . . . . . . 4
|
||||||
4.3. Usecase: click object (roundrobin) . . . . . . . . . . . 4
|
4.3. Usecase: click object (roundrobin) . . . . . . . . . . . 5
|
||||||
4.4. Usecase: click object or URI fragment, and scene load
|
4.4. Usecase: click object or URI fragment, and scene load
|
||||||
trigger . . . . . . . . . . . . . . . . . . . . . . . . . 4
|
trigger . . . . . . . . . . . . . . . . . . . . . . . . . 5
|
||||||
4.5. Usecase: present context menu with options . . . . . . . 5
|
4.5. Usecase: present context menu with options . . . . . . . 6
|
||||||
4.6. Event Bubble-flow . . . . . . . . . . . . . . . . . . . . 5
|
4.6. Event Bubble-flow . . . . . . . . . . . . . . . . . . . . 6
|
||||||
5. Security Considerations . . . . . . . . . . . . . . . . . . . 6
|
5. Security Considerations . . . . . . . . . . . . . . . . . . . 7
|
||||||
6. IANA Considerations . . . . . . . . . . . . . . . . . . . . . 6
|
6. IANA Considerations . . . . . . . . . . . . . . . . . . . . . 7
|
||||||
7. Acknowledgments . . . . . . . . . . . . . . . . . . . . . . . 6
|
7. Acknowledgments . . . . . . . . . . . . . . . . . . . . . . . 7
|
||||||
8. Appendix: Definitions . . . . . . . . . . . . . . . . . . . . 6
|
8. Appendix: Definitions . . . . . . . . . . . . . . . . . . . . 7
|
||||||
|
|
||||||
1. Introduction
|
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
|
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
|
Macros also act as events, so more serious scripting languages can
|
||||||
react to them as well.
|
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
|
4.1. Usecase: click object
|
||||||
|
|
||||||
+=================+================+================+
|
+=================+================+================+
|
||||||
|
@ -152,7 +207,7 @@ Internet-Draft XR Macros September 2023
|
||||||
| !clickme | bg=1,1,1&foo=2 | object clicked |
|
| !clickme | bg=1,1,1&foo=2 | object clicked |
|
||||||
+-----------------+----------------+----------------+
|
+-----------------+----------------+----------------+
|
||||||
|
|
||||||
Table 1
|
Table 2
|
||||||
|
|
||||||
4.2. Usecase: conditional click object
|
4.2. Usecase: conditional click object
|
||||||
|
|
||||||
|
@ -162,17 +217,16 @@ Internet-Draft XR Macros September 2023
|
||||||
| # | foo=1 | scene |
|
| # | foo=1 | scene |
|
||||||
+-----------------+------------------+----------------------------+
|
+-----------------+------------------+----------------------------+
|
||||||
| !clickme | q=foo>2&bg=1,1,1 | object clicked and foo > 2 |
|
| !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
|
| 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
|
| 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 |
|
| night | bg=0,0,0&foo=2 | roundrobin |
|
||||||
+-----------------+----------------+----------------+
|
+-----------------+----------------+----------------+
|
||||||
|
|
||||||
Table 3
|
Table 4
|
||||||
|
|
||||||
| when a user clicks an object with the custom properties above, it
|
| when a user clicks an object with the custom properties above, it
|
||||||
| should trigger either day noon or night in roundrobin fashion.
|
| 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 |
|
| 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
|
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 |
|
| !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
|
| When interacting with an object with more than one !-macro, the XR
|
||||||
| Browser should offer a contextmenu to execute a macro.
|
| 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
|
| 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 |
|
| | 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 />
|
Macros also act as events, so more serious scripting languages can react to them as well.<br />
|
||||||
</t>
|
</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>
|
<section anchor="usecase-click-object"><name>Usecase: click object</name>
|
||||||
<table>
|
<table>
|
||||||
<thead>
|
<thead>
|
||||||
|
|
|
@ -12,16 +12,19 @@
|
||||||
<script src="./../../../dist/xrfragment.aframe.js"></script>
|
<script src="./../../../dist/xrfragment.aframe.js"></script>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<div id="overlay">
|
<div id="overlay" style="display:none">
|
||||||
<img src="./../../assets/logo.png" class="logo"/>
|
<img src="./../../assets/logo.png" class="logo"/>
|
||||||
<button id="navback" onclick="history.back()"><</button>
|
<button id="navback" onclick="history.back()"><</button>
|
||||||
<button id="navforward" onclick="history.forward()">></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 )"/>
|
<input type="text" id="uri" value="" onchange="AFRAME.XRF.navigator.to( $('#uri').value )"/>
|
||||||
</div>
|
</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="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="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="model" target="_blank" href="example.gltf">⬇️ model</a>
|
||||||
|
<a class="btn-foot" id="more" target="_blank">XRF</a>
|
||||||
<textarea style="display:none"></textarea>
|
<textarea style="display:none"></textarea>
|
||||||
<a-scene light="defaultLightsEnabled: false">
|
<a-scene light="defaultLightsEnabled: false">
|
||||||
<a-entity id="player" wasd-controls look-controls>
|
<a-entity id="player" wasd-controls look-controls>
|
||||||
|
|
|
@ -73,7 +73,6 @@ input[type="submit"] {
|
||||||
}
|
}
|
||||||
|
|
||||||
#overlay > #uri {
|
#overlay > #uri {
|
||||||
display:none;
|
|
||||||
height: 29px;
|
height: 29px;
|
||||||
font-size: 21px;
|
font-size: 21px;
|
||||||
position: absolute;
|
position: absolute;
|
||||||
|
@ -92,25 +91,40 @@ input[type="submit"] {
|
||||||
border: 5px solid #1c1c3299;
|
border: 5px solid #1c1c3299;
|
||||||
padding: 0px 6px;
|
padding: 0px 6px;
|
||||||
position: absolute;
|
position: absolute;
|
||||||
font-weight: bold;
|
font-weight: 1000;
|
||||||
font-family: sans-serif;
|
font-family: sans-serif;
|
||||||
color: #7c7c7c;
|
font-size:17px;
|
||||||
|
color: #888;
|
||||||
|
height:43px;
|
||||||
z-index:2000;
|
z-index:2000;
|
||||||
cursor:pointer;
|
cursor:pointer;
|
||||||
right: 10px;
|
right: 10px;
|
||||||
|
text-transform:uppercase;
|
||||||
}
|
}
|
||||||
|
|
||||||
a.btn-foot#embed{
|
a.btn-foot#embed{
|
||||||
color: #888;
|
color: #888;
|
||||||
bottom: 126px;
|
bottom: 129px;
|
||||||
}
|
}
|
||||||
|
|
||||||
a.btn-foot#model{
|
a.btn-foot#model{
|
||||||
bottom:73px;
|
bottom:72px;
|
||||||
|
}
|
||||||
|
|
||||||
|
a.btn-foot#more{
|
||||||
|
bottom:72px;
|
||||||
|
width: 60px;
|
||||||
|
text-align: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
a.btn-foot#source{
|
a.btn-foot#source{
|
||||||
bottom:179px;
|
bottom:186px;
|
||||||
|
}
|
||||||
|
|
||||||
|
a#source,
|
||||||
|
a#embed,
|
||||||
|
a#model{
|
||||||
|
display:none
|
||||||
}
|
}
|
||||||
|
|
||||||
html.a-fullscreen a.btn-foot {
|
html.a-fullscreen a.btn-foot {
|
||||||
|
@ -251,3 +265,7 @@ html{
|
||||||
background-color: #4443;
|
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){
|
export function setupUrlBar(el,XRF){
|
||||||
|
var isIframe = document.location.hash.match(/embed=1/)
|
||||||
var isIframe = (window === window.parent || window.opener) ? false : true;
|
let ids = ['#overlay','a#embed','a#source','a#model']
|
||||||
if( isIframe || document.location.href.match(/localhost/) ){
|
let showButtons = () => {
|
||||||
// show internal URL bar to test XR fragments interactively
|
ids.map( (i) => $(i).style.display = 'block' )
|
||||||
el.style.display = 'block'
|
$('a#more').style.display = 'none'
|
||||||
|
|
||||||
XRF.addEventListener('updateHash', () => reflectUrl() )
|
|
||||||
|
|
||||||
const reflectUrl = (url) => el.value = url || document.location.search.substr(1) + document.location.hash
|
|
||||||
reflectUrl()
|
|
||||||
}
|
}
|
||||||
|
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) {
|
function SnackBar(userOptions) {
|
||||||
|
|
|
@ -10,12 +10,15 @@
|
||||||
<body>
|
<body>
|
||||||
<div id="overlay" x-data="{ urls: ['#pos=0,1.6,15','#pos=0,1.6,15&rot=0,360,0'] }">
|
<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"/>
|
<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 )"/>
|
<input type="text" id="uri" value="" onchange="XRF.navigator.to( $('#uri').value )"/>
|
||||||
</div>
|
</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="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="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="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>
|
<textarea style="display:none"></textarea>
|
||||||
|
|
||||||
<script async src="./../../assets/js/alpine.min.js"></script>
|
<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 aScene = document.querySelector('a-scene')
|
||||||
let XRF = AFRAME.XRF = xrf.init({
|
let XRF = AFRAME.XRF = xrf.init({
|
||||||
THREE,
|
THREE,
|
||||||
camera: aScene.camera,
|
camera: aScene.camera,
|
||||||
scene: aScene.object3D,
|
scene: aScene.object3D,
|
||||||
renderer: aScene.renderer,
|
renderer: aScene.renderer,
|
||||||
debug: true,
|
debug: true,
|
||||||
loaders: {
|
loaders: {
|
||||||
gltf: THREE.GLTFLoader, // which 3D assets (exts) to check for XR fragments?
|
gltf: THREE.GLTFLoader, // which 3D assets (exts) to check for XR fragments?
|
||||||
|
|
|
@ -32,7 +32,7 @@ xrf.InteractiveGroup = function(THREE,renderer,camera){
|
||||||
function nocollide(){
|
function nocollide(){
|
||||||
if( nocollide.tid ) return // ratelimit
|
if( nocollide.tid ) return // ratelimit
|
||||||
_event.type = "nocollide"
|
_event.type = "nocollide"
|
||||||
scope.children.map( (c) => c.dispatchEvent(_event) )
|
scope.objects.map( (c) => c.dispatchEvent(_event) )
|
||||||
nocollide.tid = setTimeout( () => nocollide.tid = null, 100 )
|
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
|
pub.fragment = (k, opts ) => { // evaluate one fragment
|
||||||
let frag = opts.frag[k];
|
let frag = opts.frag[k];
|
||||||
|
|
||||||
// call native function (xrf/env.js e.g.), or pass it to user decorator
|
// call native function (xrf/env.js e.g.), or pass it to user decorator
|
||||||
xrf.emit(k,opts)
|
xrf.emit(k,opts)
|
||||||
.then( () => {
|
.then( () => {
|
||||||
|
|
|
@ -52,6 +52,7 @@ xrf.parseModel = function(model,url){
|
||||||
model.mixer = new xrf.THREE.AnimationMixer(model.scene)
|
model.mixer = new xrf.THREE.AnimationMixer(model.scene)
|
||||||
model.animations.map( (anim) => {
|
model.animations.map( (anim) => {
|
||||||
anim.action = model.mixer.clipAction( anim )
|
anim.action = model.mixer.clipAction( anim )
|
||||||
|
//anim.action.setLoop(0)
|
||||||
anim.action.play()
|
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.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.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;
|
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
|
if( xrf.focusLine.opacity < 0.0 ) xrf.focusLine.opacity = 0
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
xrf.getLastModel = () => xrf.model.last
|
xrf.getLastModel = () => xrf.model.last
|
||||||
|
|
|
@ -35,8 +35,12 @@ xrf.navigator.to = (url,flags,loader,data) => {
|
||||||
xrf.XRWG.generate({model,scene:model.scene})
|
xrf.XRWG.generate({model,scene:model.scene})
|
||||||
// spec: 1. execute the default predefined view '#' (if exist) (https://xrfragment.org/#predefined_view)
|
// spec: 1. execute the default predefined view '#' (if exist) (https://xrfragment.org/#predefined_view)
|
||||||
xrf.frag.defaultPredefinedView({model,scene:model.scene})
|
xrf.frag.defaultPredefinedView({model,scene:model.scene})
|
||||||
// spec: 2. execute predefined view(s) from URL (https://xrfragment.org/#predefined_view)
|
// spec: 2. init metadata
|
||||||
hashbus.pub( url, model ) // and eval URI XR fragments
|
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.add( model.scene )
|
||||||
xrf.navigator.updateHash(hash)
|
xrf.navigator.updateHash(hash)
|
||||||
resolve(model)
|
resolve(model)
|
||||||
|
@ -49,9 +53,14 @@ xrf.navigator.to = (url,flags,loader,data) => {
|
||||||
|
|
||||||
xrf.navigator.init = () => {
|
xrf.navigator.init = () => {
|
||||||
if( xrf.navigator.init.inited ) return
|
if( xrf.navigator.init.inited ) return
|
||||||
|
|
||||||
window.addEventListener('popstate', function (event){
|
window.addEventListener('popstate', function (event){
|
||||||
xrf.navigator.to( document.location.search.substr(1) + document.location.hash )
|
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)
|
// this allows selectionlines to be updated according to the camera (renderloop)
|
||||||
xrf.focusLine = new xrf.THREE.Group()
|
xrf.focusLine = new xrf.THREE.Group()
|
||||||
|
|
|
@ -81,7 +81,7 @@ xrf.frag.href = function(v, opts){
|
||||||
vec4 color = texture2D(pano, sampleUV);
|
vec4 color = texture2D(pano, sampleUV);
|
||||||
// Convert color to grayscale (lazy lite approach to not having to match tonemapping/shaderstacking of THREE.js)
|
// 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;
|
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;
|
gl_FragColor = grayscale_color;
|
||||||
}
|
}
|
||||||
`,
|
`,
|
||||||
|
@ -109,14 +109,18 @@ xrf.frag.href = function(v, opts){
|
||||||
|
|
||||||
let selected = (state) => () => {
|
let selected = (state) => () => {
|
||||||
if( mesh.selected == state ) return // nothing changed
|
if( mesh.selected == state ) return // nothing changed
|
||||||
if( mesh.material ){
|
xrf.interactive.objects.map( (o) => {
|
||||||
if( mesh.material.uniforms ) mesh.material.uniforms.selected.value = state
|
let newState = o.name == mesh.name ? state : false
|
||||||
else mesh.material.color.r = mesh.material.color.g = mesh.material.color.b = state ? 2.0 : 1.0
|
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
|
// update mouse cursor
|
||||||
if( !renderer.domElement.lastCursor )
|
if( !renderer.domElement.lastCursor )
|
||||||
renderer.domElement.lastCursor = renderer.domElement.style.cursor
|
renderer.domElement.lastCursor = renderer.domElement.style.cursor
|
||||||
renderer.domElement.style.cursor = state ? 'pointer' : renderer.domElement.lastCursor
|
renderer.domElement.style.cursor = state ? 'pointer' : renderer.domElement.lastCursor
|
||||||
|
|
||||||
xrf
|
xrf
|
||||||
.emit('href',{selected:state,mesh,xrf:v}) // let all listeners agree
|
.emit('href',{selected:state,mesh,xrf:v}) // let all listeners agree
|
||||||
.then( () => mesh.selected = state )
|
.then( () => mesh.selected = state )
|
||||||
|
|
|
@ -6,7 +6,7 @@ xrf.frag.defaultPredefinedView = (opts) => {
|
||||||
}
|
}
|
||||||
|
|
||||||
xrf.frag.updatePredefinedView = (opts) => {
|
xrf.frag.updatePredefinedView = (opts) => {
|
||||||
let {frag,scene,model} = opts
|
let {frag,scene,model,renderer} = opts
|
||||||
|
|
||||||
// spec: https://xrfragment.org/#Selection%20of%20interest
|
// spec: https://xrfragment.org/#Selection%20of%20interest
|
||||||
const selectionOfInterest = (frag,scene,mesh) => {
|
const selectionOfInterest = (frag,scene,mesh) => {
|
||||||
|
@ -14,7 +14,7 @@ xrf.frag.updatePredefinedView = (opts) => {
|
||||||
let oldSelection
|
let oldSelection
|
||||||
if(!id) return id // important: ignore empty strings
|
if(!id) return id // important: ignore empty strings
|
||||||
// Selection of Interest if predefined_view matches object name
|
// Selection of Interest if predefined_view matches object name
|
||||||
if( mesh.visible ){
|
if( mesh.visible && mesh.material){
|
||||||
xrf.emit('focus',{...opts,frag})
|
xrf.emit('focus',{...opts,frag})
|
||||||
.then( () => {
|
.then( () => {
|
||||||
const color = new THREE.Color();
|
const color = new THREE.Color();
|
||||||
|
@ -82,14 +82,13 @@ xrf.frag.updatePredefinedView = (opts) => {
|
||||||
remove.map( (n) => scene.remove(n.selection) )
|
remove.map( (n) => scene.remove(n.selection) )
|
||||||
// create new selections
|
// create new selections
|
||||||
match.map( (w) => {
|
match.map( (w) => {
|
||||||
if( w.key == `#${id}` && w.value && w.value[0] == '#' ){
|
if( w.key == `#${id}` ){
|
||||||
// if value is alias, execute fragment value
|
if( w.value && w.value[0] == '#' ){
|
||||||
xrf.hashbus.pub( w.value, xrf.model, xrf.XRF.METADATA | xrf.XRF.PV_OVERRIDE | xrf.XRF.NAVIGATOR )
|
// 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) => {
|
w.nodes.map( (mesh) => selectionOfInterest( v, scene, mesh ) )
|
||||||
if( mesh.material )
|
|
||||||
selectionOfInterest( v, scene, mesh )
|
|
||||||
})
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -99,6 +98,8 @@ xrf.frag.updatePredefinedView = (opts) => {
|
||||||
console.log("filtering predefined view of src")
|
console.log("filtering predefined view of src")
|
||||||
console.dir(frag)
|
console.dir(frag)
|
||||||
}else{
|
}else{
|
||||||
|
console.log("updatePredefinedView")
|
||||||
|
console.dir(frag)
|
||||||
for ( let i in frag ) {
|
for ( let i in frag ) {
|
||||||
let v = frag[i]
|
let v = frag[i]
|
||||||
if( v.is( xrf.XRF.PV_EXECUTE ) ){
|
if( v.is( xrf.XRF.PV_EXECUTE ) ){
|
||||||
|
@ -113,7 +114,6 @@ xrf.frag.updatePredefinedView = (opts) => {
|
||||||
// react to enduser typing url
|
// react to enduser typing url
|
||||||
xrf.addEventListener('hash', (opts) => {
|
xrf.addEventListener('hash', (opts) => {
|
||||||
let frag = xrf.URI.parse( opts.hash, xrf.XRF.NAVIGATOR | xrf.XRF.PV_OVERRIDE | xrf.XRF.METADATA )
|
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})
|
xrf.frag.updatePredefinedView({frag,scene:xrf.scene})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
|
@ -27,10 +27,8 @@ xrf.frag.q = function(v, opts){
|
||||||
xrf.frag.q.filter = function(scene,frag){
|
xrf.frag.q.filter = function(scene,frag){
|
||||||
// spec: https://xrfragment.org/#queries
|
// spec: https://xrfragment.org/#queries
|
||||||
let q = frag.q.query
|
let q = frag.q.query
|
||||||
console.dir(q)
|
|
||||||
scene.traverse( (mesh) => {
|
scene.traverse( (mesh) => {
|
||||||
for ( let i in q ) {
|
for ( let i in q ) {
|
||||||
if( i == '' ) continue
|
|
||||||
let isMeshId = q[i].id != undefined
|
let isMeshId = q[i].id != undefined
|
||||||
let isMeshProperty = q[i].rules != undefined && q[i].rules.length && !isMeshId
|
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.)
|
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){
|
xrf.frag.src = function(v, opts){
|
||||||
|
|
||||||
opts.embedded = v // indicate embedded XR fragment
|
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")
|
console.log(" └ instancing src")
|
||||||
let src;
|
let src;
|
||||||
let url = v.string
|
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
|
opts.isPlane = mesh.geometry && mesh.geometry.attributes.uv && mesh.geometry.attributes.uv.count == 4
|
||||||
|
|
||||||
const addScene = (scene,url,frag) => {
|
const addScene = (scene,url,frag) => {
|
||||||
src = xrf.frag.src.filterScene(scene,{...opts,frag})
|
src = xrf.frag.src.filterScene(scene,{...opts,frag})
|
||||||
xrf.frag.src.scale( src, opts, url )
|
xrf.frag.src.scale( src, opts, url )
|
||||||
xrf.frag.src.eval( src, opts, url )
|
xrf.frag.src.eval( src, opts, url )
|
||||||
|
enableSourcePortation(src)
|
||||||
mesh.add(src)
|
mesh.add(src)
|
||||||
mesh.traverse( (n) => n.isSRC = n.isXRF = true )
|
mesh.traverse( (n) => n.isSRC = n.isXRF = true )
|
||||||
if( mesh.material ) mesh.material.visible = false
|
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) => {
|
const externalSRC = (url,frag,src) => {
|
||||||
fetch(url, { method: 'HEAD' })
|
fetch(url, { method: 'HEAD' })
|
||||||
.then( (res) => {
|
.then( (res) => {
|
||||||
|
@ -38,8 +56,8 @@ xrf.frag.src = function(v, opts){
|
||||||
.catch( console.error )
|
.catch( console.error )
|
||||||
}
|
}
|
||||||
|
|
||||||
if( url[0] == "#" ) addScene(scene,url,frag) // current file
|
if( url[0] == "#" ) addScene(scene,url,vfrag) // current file
|
||||||
else externalSRC(url,frag) // external file
|
else externalSRC(url,vfrag) // external file
|
||||||
}
|
}
|
||||||
|
|
||||||
xrf.frag.src.eval = function(scene, opts, url){
|
xrf.frag.src.eval = function(scene, opts, url){
|
||||||
|
|
Loading…
Reference in New Issue