envmapping + bugfixes
This commit is contained in:
parent
0f7f482a3d
commit
b6715c1725
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* v0.5.1 generated at Thu Jul 11 01:59:18 PM UTC 2024
|
||||
* v0.5.1 generated at Fri Jul 12 04:11:54 PM UTC 2024
|
||||
* https://xrfragment.org
|
||||
* SPDX-License-Identifier: MPL-2.0
|
||||
*/
|
||||
|
@ -1955,7 +1955,7 @@ xrf.loadModel = function(model,url,noadd){
|
|||
const defaultFragment = xrf.frag.defaultPredefinedViews({model,scene:model.scene})
|
||||
// spec: predefined view(s) & objects-of-interest-in-XRWG from URI (https://xrfragment.org/#predefined_view)
|
||||
let frag = xrf.hashbus.pub( url, model) // and eval URI XR fragments
|
||||
|
||||
|
||||
if( !noadd ) xrf.add( model.scene )
|
||||
|
||||
// only change url when loading *another* file
|
||||
|
@ -2009,6 +2009,7 @@ xrf.reset = () => {
|
|||
}
|
||||
|
||||
xrf.add = (object) => {
|
||||
|
||||
object.isXRF = true // mark for easy deletion when replacing scene
|
||||
xrf.scene.add(object)
|
||||
}
|
||||
|
@ -3219,6 +3220,38 @@ xrf.addEventListener('dynamicKey', (opts) => {
|
|||
})
|
||||
})
|
||||
})
|
||||
// switch camera when multiple cameras for url #mycameraname
|
||||
|
||||
xrf.addEventListener('navigateLoaded', (opts) => {
|
||||
// select active camera if any
|
||||
let {id,match,v} = opts
|
||||
let envmap = {}
|
||||
let current = ''
|
||||
|
||||
// Recursive function to traverse the graph
|
||||
function traverseAndSetEnvMap(node, closestAncestorMaterialMap = null) {
|
||||
// Check if the current node has a material
|
||||
if (node.isMesh && node.material) {
|
||||
if (node.material.map && closestAncestorMaterialMap) {
|
||||
// If the node has a material map, set the closest ancestor material map
|
||||
node.material.envMap = closestAncestorMaterialMap;
|
||||
}
|
||||
}
|
||||
|
||||
// Update the closest ancestor's material map
|
||||
if (node.isMesh && node.material && node.material.map) {
|
||||
closestAncestorMaterialMap = node.material.map.clone();
|
||||
closestAncestorMaterialMap.mapping = THREE.EquirectangularReflectionMapping;
|
||||
closestAncestorMaterialMap.needsUpdate = true
|
||||
}
|
||||
|
||||
// Recursively traverse all children
|
||||
node.children.forEach(child => traverseAndSetEnvMap(child, closestAncestorMaterialMap));
|
||||
}
|
||||
|
||||
// Start traversal from the root node
|
||||
traverseAndSetEnvMap(xrf.scene);
|
||||
})
|
||||
|
||||
const doFilter = (opts) => {
|
||||
let {scene,id,match,v} = opts
|
||||
|
@ -4117,34 +4150,6 @@ let videoMimeTypes = [
|
|||
'video/mp4'
|
||||
]
|
||||
videoMimeTypes.map( (mimetype) => xrf.frag.src.type[ mimetype ] = loadVideo(mimetype) )
|
||||
// poor man's way to move forward using hand gesture pinch
|
||||
|
||||
window.AFRAME.registerComponent('envmap', {
|
||||
schema:{
|
||||
src: {type: "string"}
|
||||
},
|
||||
init: function(){
|
||||
const loader = new THREE.TextureLoader();
|
||||
const onLoad = (texture) => {
|
||||
texture.colorSpace = THREE.SRGBColorSpace;
|
||||
texture.mapping = THREE.EquirectangularReflectionMapping;
|
||||
texture.needsUpdate = true
|
||||
xrf.scene.environment = texture
|
||||
xrf.scene.texture = texture
|
||||
}
|
||||
new THREE.TextureLoader().load( this.data.src, onLoad, null, console.error );
|
||||
|
||||
xrf.addEventListener('navigateLoaded', () => {
|
||||
xrf.scene.traverse( (n) => {
|
||||
if( n.material && n.material.isMeshPhysicalMaterial){
|
||||
n.material.envMap = xrf.scene.environment
|
||||
n.material.needsUpdate = true
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
},
|
||||
})
|
||||
window.AFRAME.registerComponent('href', {
|
||||
schema: {
|
||||
},
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* v0.5.1 generated at Thu Jul 11 01:59:18 PM UTC 2024
|
||||
* v0.5.1 generated at Fri Jul 12 04:11:54 PM UTC 2024
|
||||
* https://xrfragment.org
|
||||
* SPDX-License-Identifier: MPL-2.0
|
||||
*/
|
||||
|
@ -1953,7 +1953,7 @@ xrf.loadModel = function(model,url,noadd){
|
|||
const defaultFragment = xrf.frag.defaultPredefinedViews({model,scene:model.scene})
|
||||
// spec: predefined view(s) & objects-of-interest-in-XRWG from URI (https://xrfragment.org/#predefined_view)
|
||||
let frag = xrf.hashbus.pub( url, model) // and eval URI XR fragments
|
||||
|
||||
|
||||
if( !noadd ) xrf.add( model.scene )
|
||||
|
||||
// only change url when loading *another* file
|
||||
|
@ -2007,6 +2007,7 @@ xrf.reset = () => {
|
|||
}
|
||||
|
||||
xrf.add = (object) => {
|
||||
|
||||
object.isXRF = true // mark for easy deletion when replacing scene
|
||||
xrf.scene.add(object)
|
||||
}
|
||||
|
@ -3217,6 +3218,38 @@ xrf.addEventListener('dynamicKey', (opts) => {
|
|||
})
|
||||
})
|
||||
})
|
||||
// switch camera when multiple cameras for url #mycameraname
|
||||
|
||||
xrf.addEventListener('navigateLoaded', (opts) => {
|
||||
// select active camera if any
|
||||
let {id,match,v} = opts
|
||||
let envmap = {}
|
||||
let current = ''
|
||||
|
||||
// Recursive function to traverse the graph
|
||||
function traverseAndSetEnvMap(node, closestAncestorMaterialMap = null) {
|
||||
// Check if the current node has a material
|
||||
if (node.isMesh && node.material) {
|
||||
if (node.material.map && closestAncestorMaterialMap) {
|
||||
// If the node has a material map, set the closest ancestor material map
|
||||
node.material.envMap = closestAncestorMaterialMap;
|
||||
}
|
||||
}
|
||||
|
||||
// Update the closest ancestor's material map
|
||||
if (node.isMesh && node.material && node.material.map) {
|
||||
closestAncestorMaterialMap = node.material.map.clone();
|
||||
closestAncestorMaterialMap.mapping = THREE.EquirectangularReflectionMapping;
|
||||
closestAncestorMaterialMap.needsUpdate = true
|
||||
}
|
||||
|
||||
// Recursively traverse all children
|
||||
node.children.forEach(child => traverseAndSetEnvMap(child, closestAncestorMaterialMap));
|
||||
}
|
||||
|
||||
// Start traversal from the root node
|
||||
traverseAndSetEnvMap(xrf.scene);
|
||||
})
|
||||
|
||||
const doFilter = (opts) => {
|
||||
let {scene,id,match,v} = opts
|
||||
|
@ -4115,34 +4148,6 @@ let videoMimeTypes = [
|
|||
'video/mp4'
|
||||
]
|
||||
videoMimeTypes.map( (mimetype) => xrf.frag.src.type[ mimetype ] = loadVideo(mimetype) )
|
||||
// poor man's way to move forward using hand gesture pinch
|
||||
|
||||
window.AFRAME.registerComponent('envmap', {
|
||||
schema:{
|
||||
src: {type: "string"}
|
||||
},
|
||||
init: function(){
|
||||
const loader = new THREE.TextureLoader();
|
||||
const onLoad = (texture) => {
|
||||
texture.colorSpace = THREE.SRGBColorSpace;
|
||||
texture.mapping = THREE.EquirectangularReflectionMapping;
|
||||
texture.needsUpdate = true
|
||||
xrf.scene.environment = texture
|
||||
xrf.scene.texture = texture
|
||||
}
|
||||
new THREE.TextureLoader().load( this.data.src, onLoad, null, console.error );
|
||||
|
||||
xrf.addEventListener('navigateLoaded', () => {
|
||||
xrf.scene.traverse( (n) => {
|
||||
if( n.material && n.material.isMeshPhysicalMaterial){
|
||||
n.material.envMap = xrf.scene.environment
|
||||
n.material.needsUpdate = true
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
},
|
||||
})
|
||||
window.AFRAME.registerComponent('href', {
|
||||
schema: {
|
||||
},
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -343,7 +343,6 @@ window.accessibility = (opts) => new Proxy({
|
|||
setupHrefCycling(){
|
||||
// speak arrow keys
|
||||
window.addEventListener('keydown', (e) => {
|
||||
console.log(e.key)
|
||||
if( e.key != "Tab" && e.key != "Enter" ) return
|
||||
let subScene = xrf.scene.getObjectByName( xrf.frag.pos.last )
|
||||
if( !subScene ) subScene = xrf.scene
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* v0.5.1 generated at Thu Jul 11 01:59:18 PM UTC 2024
|
||||
* v0.5.1 generated at Fri Jul 12 04:11:54 PM UTC 2024
|
||||
* https://xrfragment.org
|
||||
* SPDX-License-Identifier: MPL-2.0
|
||||
*/
|
||||
|
@ -1953,7 +1953,7 @@ xrf.loadModel = function(model,url,noadd){
|
|||
const defaultFragment = xrf.frag.defaultPredefinedViews({model,scene:model.scene})
|
||||
// spec: predefined view(s) & objects-of-interest-in-XRWG from URI (https://xrfragment.org/#predefined_view)
|
||||
let frag = xrf.hashbus.pub( url, model) // and eval URI XR fragments
|
||||
|
||||
|
||||
if( !noadd ) xrf.add( model.scene )
|
||||
|
||||
// only change url when loading *another* file
|
||||
|
@ -2007,6 +2007,7 @@ xrf.reset = () => {
|
|||
}
|
||||
|
||||
xrf.add = (object) => {
|
||||
|
||||
object.isXRF = true // mark for easy deletion when replacing scene
|
||||
xrf.scene.add(object)
|
||||
}
|
||||
|
@ -3217,6 +3218,38 @@ xrf.addEventListener('dynamicKey', (opts) => {
|
|||
})
|
||||
})
|
||||
})
|
||||
// switch camera when multiple cameras for url #mycameraname
|
||||
|
||||
xrf.addEventListener('navigateLoaded', (opts) => {
|
||||
// select active camera if any
|
||||
let {id,match,v} = opts
|
||||
let envmap = {}
|
||||
let current = ''
|
||||
|
||||
// Recursive function to traverse the graph
|
||||
function traverseAndSetEnvMap(node, closestAncestorMaterialMap = null) {
|
||||
// Check if the current node has a material
|
||||
if (node.isMesh && node.material) {
|
||||
if (node.material.map && closestAncestorMaterialMap) {
|
||||
// If the node has a material map, set the closest ancestor material map
|
||||
node.material.envMap = closestAncestorMaterialMap;
|
||||
}
|
||||
}
|
||||
|
||||
// Update the closest ancestor's material map
|
||||
if (node.isMesh && node.material && node.material.map) {
|
||||
closestAncestorMaterialMap = node.material.map.clone();
|
||||
closestAncestorMaterialMap.mapping = THREE.EquirectangularReflectionMapping;
|
||||
closestAncestorMaterialMap.needsUpdate = true
|
||||
}
|
||||
|
||||
// Recursively traverse all children
|
||||
node.children.forEach(child => traverseAndSetEnvMap(child, closestAncestorMaterialMap));
|
||||
}
|
||||
|
||||
// Start traversal from the root node
|
||||
traverseAndSetEnvMap(xrf.scene);
|
||||
})
|
||||
|
||||
const doFilter = (opts) => {
|
||||
let {scene,id,match,v} = opts
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* v0.5.1 generated at Thu Jul 11 01:59:18 PM UTC 2024
|
||||
* v0.5.1 generated at Fri Jul 12 04:11:54 PM UTC 2024
|
||||
* https://xrfragment.org
|
||||
* SPDX-License-Identifier: MPL-2.0
|
||||
*/
|
||||
|
@ -1953,7 +1953,7 @@ xrf.loadModel = function(model,url,noadd){
|
|||
const defaultFragment = xrf.frag.defaultPredefinedViews({model,scene:model.scene})
|
||||
// spec: predefined view(s) & objects-of-interest-in-XRWG from URI (https://xrfragment.org/#predefined_view)
|
||||
let frag = xrf.hashbus.pub( url, model) // and eval URI XR fragments
|
||||
|
||||
|
||||
if( !noadd ) xrf.add( model.scene )
|
||||
|
||||
// only change url when loading *another* file
|
||||
|
@ -2007,6 +2007,7 @@ xrf.reset = () => {
|
|||
}
|
||||
|
||||
xrf.add = (object) => {
|
||||
|
||||
object.isXRF = true // mark for easy deletion when replacing scene
|
||||
xrf.scene.add(object)
|
||||
}
|
||||
|
@ -3217,6 +3218,38 @@ xrf.addEventListener('dynamicKey', (opts) => {
|
|||
})
|
||||
})
|
||||
})
|
||||
// switch camera when multiple cameras for url #mycameraname
|
||||
|
||||
xrf.addEventListener('navigateLoaded', (opts) => {
|
||||
// select active camera if any
|
||||
let {id,match,v} = opts
|
||||
let envmap = {}
|
||||
let current = ''
|
||||
|
||||
// Recursive function to traverse the graph
|
||||
function traverseAndSetEnvMap(node, closestAncestorMaterialMap = null) {
|
||||
// Check if the current node has a material
|
||||
if (node.isMesh && node.material) {
|
||||
if (node.material.map && closestAncestorMaterialMap) {
|
||||
// If the node has a material map, set the closest ancestor material map
|
||||
node.material.envMap = closestAncestorMaterialMap;
|
||||
}
|
||||
}
|
||||
|
||||
// Update the closest ancestor's material map
|
||||
if (node.isMesh && node.material && node.material.map) {
|
||||
closestAncestorMaterialMap = node.material.map.clone();
|
||||
closestAncestorMaterialMap.mapping = THREE.EquirectangularReflectionMapping;
|
||||
closestAncestorMaterialMap.needsUpdate = true
|
||||
}
|
||||
|
||||
// Recursively traverse all children
|
||||
node.children.forEach(child => traverseAndSetEnvMap(child, closestAncestorMaterialMap));
|
||||
}
|
||||
|
||||
// Start traversal from the root node
|
||||
traverseAndSetEnvMap(xrf.scene);
|
||||
})
|
||||
|
||||
const doFilter = (opts) => {
|
||||
let {scene,id,match,v} = opts
|
||||
|
|
|
@ -1249,12 +1249,12 @@ Some pointers for good UX (but not necessary to be XR Fragment compatible):</p>
|
|||
| | | author.com/article.txt |
|
||||
| index.gltf | +------------------------+
|
||||
| │ | | |
|
||||
| ├── ◻ article_canvas | | Hello friends. |
|
||||
| ├── ◻ article_canvas | | Hello #friends |
|
||||
| │ └ src: ://author.com/article.txt | | |
|
||||
| │ | | @book{greatgatsby |
|
||||
| └── ◻ note_canvas | | ... |
|
||||
| └ src:`data:welcome human\n@book{sunday...}` | | } |
|
||||
| | +------------------------+
|
||||
| │ | +------------------------+
|
||||
| └── ◻ note_canvas |
|
||||
| └ src:`data:welcome human\n@book{sunday...}` |
|
||||
| |
|
||||
| |
|
||||
+--------------------------------------------------------------+
|
||||
</code></pre>
|
||||
|
@ -1276,84 +1276,95 @@ The XR Fragment-compatible browser can let the enduser access visual-meta(data)-
|
|||
<li>export: if the 3D scene contains relative src/href values, rewrite them into absolute URL values.</li>
|
||||
</ol>
|
||||
|
||||
<h1 id="transclusion-broken-link-resolution">Transclusion (broken link) resolution</h1>
|
||||
<h1 id="reflection-mapping">Reflection Mapping</h1>
|
||||
|
||||
<p>In spirit of Ted Nelson’s ‘transclusion resolution’, there’s a soft-mechanism to harden links & minimize broken links in various ways:</p>
|
||||
<p>Environment mapping is crucial for creating realistic reflections and lighting effects on 3D objects.
|
||||
To apply environment mapping efficiently in a 3D scene, traverse the scene graph and assign each object’s environment map based on the nearest ancestor’s texture map. This ensures that objects inherit the correct environment mapping from their closest parent with a texture, enhancing the visual consistency and realism.</p>
|
||||
|
||||
<ol>
|
||||
<li>defining a different transport protocol (https vs ipfs or DAT) in <code>src</code> or <code>href</code> values can make a difference</li>
|
||||
<li>mirroring files on another protocol using (HTTP) errorcode tags in <code>src</code> or <code>href</code> properties</li>
|
||||
<li>in case of <code>src</code>: nesting a copy of the embedded object in the placeholder object (<code>embeddedObject</code>) will not be replaced when the request fails</li>
|
||||
</ol>
|
||||
<p>”“”
|
||||
+——————————–+<br>
|
||||
| |<br>
|
||||
| index.usdz |<br>
|
||||
| │ |<br>
|
||||
| └── ◻ sphere (texture:foo) |
|
||||
| └ ◻ cube (texture:bar) | envMap = foo
|
||||
| └ ◻ cylinder | envMap = bar
|
||||
+——————————–+</p>
|
||||
|
||||
<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>
|
||||
<pre><code>
|
||||
Most 3D viewers apply one and the same environment map for various models, however this logic
|
||||
allows a more natural & automatic strategy for reflection mapping.
|
||||
|
||||
<p>For example:</p>
|
||||
# Transclusion (broken link) resolution
|
||||
|
||||
<pre><code> +────────────────────────────────────────────────────────+
|
||||
In spirit of Ted Nelson's 'transclusion resolution', there's a soft-mechanism to harden links & minimize broken links in various ways:
|
||||
|
||||
1. defining a different transport protocol (https vs ipfs or DAT) in `src` or `href` values can make a difference
|
||||
2. mirroring files on another protocol using (HTTP) errorcode tags in `src` or `href` properties
|
||||
3. in case of `src`: nesting a copy of the embedded object in the placeholder object (`embeddedObject`) will not be replaced when the request fails
|
||||
|
||||
> due to the popularity, maturity and extensiveness of HTTP codes for client/server communication, non-HTTP protocols easily map to HTTP codes (ipfs ERR_NOT_FOUND maps to 404 e.g.)
|
||||
|
||||
For example:
|
||||
|
||||
</code></pre>
|
||||
|
||||
<p>+────────────────────────────────────────────────────────+
|
||||
│ │
|
||||
│ index.gltf │
|
||||
│ │ │
|
||||
│ │ #: #-offlinetext │
|
||||
│ │ │
|
||||
│ ├── ◻ buttonA │
|
||||
│ │ └ href: http://foo.io/campagne.fbx │
|
||||
│ │ └ href: <a href="http://foo.io/campagne.fbx">http://foo.io/campagne.fbx</a> │
|
||||
│ │ └ href@404: ipfs://foo.io/campagne.fbx │
|
||||
│ │ └ href@400: #clienterrortext │
|
||||
│ │ └ ◻ offlinetext │
|
||||
│ │ │
|
||||
│ └── ◻ embeddedObject <--------- the meshdata inside embeddedObject will (not)
|
||||
│ └ src: https://foo.io/bar.gltf │ be flushed when the request (does not) succeed.
|
||||
│ └ src@404: http://foo.io/bar.gltf │ So worstcase the 3D data (of the time of publishing index.gltf)
|
||||
│ └ src@400: https://archive.org/l2kj43.gltf │ will be displayed.
|
||||
│ └── ◻ embeddedObject <——— the meshdata inside embeddedObject will (not)
|
||||
│ └ src: <a href="https://foo.io/bar.gltf">https://foo.io/bar.gltf</a> │ be flushed when the request (does not) succeed.
|
||||
│ └ src@404: <a href="http://foo.io/bar.gltf">http://foo.io/bar.gltf</a> │ So worstcase the 3D data (of the time of publishing index.gltf)
|
||||
│ └ src@400: <a href="https://archive.org/l2kj43.gltf">https://archive.org/l2kj43.gltf</a> │ will be displayed.
|
||||
│ │
|
||||
+────────────────────────────────────────────────────────+
|
||||
+────────────────────────────────────────────────────────+</p>
|
||||
|
||||
<pre><code>
|
||||
# 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.<br>
|
||||
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.<br>
|
||||
To filter out non-related objects one could take it a step further using filters:
|
||||
|
||||
* `href: schoolA.edu/projects.gltf#math&-topics math`
|
||||
* `href: schoolB.edu/projects.gltf#math&-courses math`
|
||||
* `href: university.edu/projects.gltf#math&-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.
|
||||
|
||||
# URI Templates (RFC6570)
|
||||
|
||||
XR Fragments adopts Level1 URI **Fragment** expansion to provide safe interactivity.<br>
|
||||
The following demonstrates a simple video player:
|
||||
|
||||
</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 filters:</p>
|
||||
|
||||
<ul>
|
||||
<li><code>href: schoolA.edu/projects.gltf#math&-topics math</code></li>
|
||||
<li><code>href: schoolB.edu/projects.gltf#math&-courses math</code></li>
|
||||
<li><code>href: university.edu/projects.gltf#math&-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="uri-templates-rfc6570">URI Templates (RFC6570)</h1>
|
||||
|
||||
<p>XR Fragments adopts Level1 URI <strong>Fragment</strong> expansion to provide safe interactivity.<br>
|
||||
The following demonstrates a simple video player:</p>
|
||||
|
||||
<pre><code>
|
||||
+─────────────────────────────────────────────+
|
||||
<p>+─────────────────────────────────────────────+
|
||||
│ │
|
||||
│ foo.usdz │
|
||||
│ │ │
|
||||
│ │ │
|
||||
│ foo.usdz │<br>
|
||||
│ │ │<br>
|
||||
│ │ │<br>
|
||||
│ ├── ◻ stopbutton │
|
||||
│ │ ├ #: #-stopbutton │
|
||||
│ │ └ href: #player=stop&-stopbutton │ (stop and hide stop-button)
|
||||
│ │ │
|
||||
│ │ │<br>
|
||||
│ └── ◻ plane │
|
||||
│ ├ play: #t=l:0,10 │
|
||||
│ ├ stop: #t=0,0 │
|
||||
|
@ -1361,10 +1372,9 @@ The following demonstrates a simple video player:</p>
|
|||
│ └ src: cat.mp4#{player} │
|
||||
│ │
|
||||
│ │
|
||||
+─────────────────────────────────────────────+
|
||||
+─────────────────────────────────────────────+</p>
|
||||
|
||||
|
||||
</code></pre>
|
||||
<p>”`</p>
|
||||
|
||||
<h1 id="additional-scene-metadata">Additional scene metadata</h1>
|
||||
|
||||
|
|
|
@ -763,12 +763,12 @@ For all other purposes, regular mimetypes can be used (but are not required by t
|
|||
| | | author.com/article.txt |
|
||||
| index.gltf | +------------------------+
|
||||
| │ | | |
|
||||
| ├── ◻ article_canvas | | Hello friends. |
|
||||
| ├── ◻ article_canvas | | Hello #friends |
|
||||
| │ └ src: ://author.com/article.txt | | |
|
||||
| │ | | @book{greatgatsby |
|
||||
| └── ◻ note_canvas | | ... |
|
||||
| └ src:`data:welcome human\n@book{sunday...}` | | } |
|
||||
| | +------------------------+
|
||||
| │ | +------------------------+
|
||||
| └── ◻ note_canvas |
|
||||
| └ src:`data:welcome human\n@book{sunday...}` |
|
||||
| |
|
||||
| |
|
||||
+--------------------------------------------------------------+
|
||||
```
|
||||
|
@ -786,6 +786,24 @@ For usecases like importing/exporting/p2p casting a scene, the issue of external
|
|||
|
||||
1. export: if the 3D scene contains relative src/href values, rewrite them into absolute URL values.
|
||||
|
||||
# Reflection Mapping
|
||||
|
||||
Environment mapping is crucial for creating realistic reflections and lighting effects on 3D objects.
|
||||
To apply environment mapping efficiently in a 3D scene, traverse the scene graph and assign each object's environment map based on the nearest ancestor's texture map. This ensures that objects inherit the correct environment mapping from their closest parent with a texture, enhancing the visual consistency and realism.
|
||||
|
||||
``````
|
||||
+--------------------------------+
|
||||
| |
|
||||
| index.usdz |
|
||||
| │ |
|
||||
| └── ◻ sphere (texture:foo) |
|
||||
| └ ◻ cube (texture:bar) | envMap = foo
|
||||
| └ ◻ cylinder | envMap = bar
|
||||
+--------------------------------+
|
||||
```
|
||||
|
||||
Most 3D viewers apply one and the same environment map for various models, however this logic
|
||||
allows a more natural & automatic strategy for reflection mapping.
|
||||
|
||||
# Transclusion (broken link) resolution
|
||||
|
||||
|
|
|
@ -103,9 +103,9 @@ Table of Contents
|
|||
17.1. Default Data URI mimetype . . . . . . . . . . . . . . . 28
|
||||
17.2. URL and Data URI . . . . . . . . . . . . . . . . . . . . 29
|
||||
18. Importing/exporting . . . . . . . . . . . . . . . . . . . . . 30
|
||||
19. Transclusion (broken link) resolution . . . . . . . . . . . . 30
|
||||
20. Topic-based index-less Webrings . . . . . . . . . . . . . . . 31
|
||||
21. URI Templates (RFC6570) . . . . . . . . . . . . . . . . . . . 31
|
||||
19. Reflection Mapping . . . . . . . . . . . . . . . . . . . . . 30
|
||||
20. Additional scene metadata . . . . . . . . . . . . . . . . . . 31
|
||||
21. Accessibility interface . . . . . . . . . . . . . . . . . . . 33
|
||||
|
||||
|
||||
|
||||
|
@ -114,15 +114,13 @@ van Kammen Expires 13 January 2025 [Page 2]
|
|||
Internet-Draft XR Fragments July 2024
|
||||
|
||||
|
||||
22. Additional scene metadata . . . . . . . . . . . . . . . . . . 32
|
||||
23. Accessibility interface . . . . . . . . . . . . . . . . . . . 33
|
||||
23.1. Two-button navigation . . . . . . . . . . . . . . . . . 34
|
||||
24. Security Considerations . . . . . . . . . . . . . . . . . . . 35
|
||||
25. FAQ . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 35
|
||||
26. authors . . . . . . . . . . . . . . . . . . . . . . . . . . . 35
|
||||
27. IANA Considerations . . . . . . . . . . . . . . . . . . . . . 36
|
||||
28. Acknowledgments . . . . . . . . . . . . . . . . . . . . . . . 36
|
||||
29. Appendix: Definitions . . . . . . . . . . . . . . . . . . . . 36
|
||||
21.1. Two-button navigation . . . . . . . . . . . . . . . . . 34
|
||||
22. Security Considerations . . . . . . . . . . . . . . . . . . . 34
|
||||
23. FAQ . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 34
|
||||
24. authors . . . . . . . . . . . . . . . . . . . . . . . . . . . 35
|
||||
25. IANA Considerations . . . . . . . . . . . . . . . . . . . . . 35
|
||||
26. Acknowledgments . . . . . . . . . . . . . . . . . . . . . . . 35
|
||||
27. Appendix: Definitions . . . . . . . . . . . . . . . . . . . . 35
|
||||
|
||||
1. Introduction
|
||||
|
||||
|
@ -165,6 +163,8 @@ Internet-Draft XR Fragments July 2024
|
|||
|
||||
|
||||
|
||||
|
||||
|
||||
van Kammen Expires 13 January 2025 [Page 3]
|
||||
|
||||
Internet-Draft XR Fragments July 2024
|
||||
|
@ -1595,12 +1595,12 @@ Internet-Draft XR Fragments July 2024
|
|||
| | | author.com/article.txt |
|
||||
| index.gltf | +------------------------+
|
||||
| │ | | |
|
||||
| ├── ◻ article_canvas | | Hello friends. |
|
||||
| ├── ◻ article_canvas | | Hello #friends |
|
||||
| │ └ src: ://author.com/article.txt | | |
|
||||
| │ | | @book{greatgatsby |
|
||||
| └── ◻ note_canvas | | ... |
|
||||
| └ src:`data:welcome human\n@book{sunday...}` | | } |
|
||||
| | +------------------------+
|
||||
| │ | +------------------------+
|
||||
| └── ◻ note_canvas |
|
||||
| └ src:`data:welcome human\n@book{sunday...}` |
|
||||
| |
|
||||
| |
|
||||
+--------------------------------------------------------------+
|
||||
|
||||
|
@ -1634,46 +1634,46 @@ Internet-Draft XR Fragments July 2024
|
|||
1. export: if the 3D scene contains relative src/href values,
|
||||
rewrite them into absolute URL values.
|
||||
|
||||
19. Transclusion (broken link) resolution
|
||||
19. Reflection Mapping
|
||||
|
||||
In spirit of Ted Nelson's 'transclusion resolution', there's a soft-
|
||||
mechanism to harden links & minimize broken links in various ways:
|
||||
Environment mapping is crucial for creating realistic reflections and
|
||||
lighting effects on 3D objects. To apply environment mapping
|
||||
efficiently in a 3D scene, traverse the scene graph and assign each
|
||||
object's environment map based on the nearest ancestor's texture map.
|
||||
This ensures that objects inherit the correct environment mapping
|
||||
from their closest parent with a texture, enhancing the visual
|
||||
consistency and realism.
|
||||
|
||||
1. defining a different transport protocol (https vs ipfs or DAT) in
|
||||
src or href values can make a difference
|
||||
2. mirroring files on another protocol using (HTTP) errorcode tags
|
||||
in src or href properties
|
||||
3. in case of src: nesting a copy of the embedded object in the
|
||||
placeholder object (embeddedObject) will not be replaced when the
|
||||
request fails
|
||||
`````` +--------------------------------+
|
||||
| |
|
||||
| index.usdz |
|
||||
| │ |
|
||||
| └── ◻ sphere (texture:foo) | | └ ◻ cube (texture:bar) | envMap =
|
||||
foo | └ ◻ cylinder | envMap = bar +--------------------------------+
|
||||
|
||||
| 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.)
|
||||
Most 3D viewers apply one and the same environment map for various models, however this logic
|
||||
allows a more natural & automatic strategy for reflection mapping.
|
||||
|
||||
For example:
|
||||
# Transclusion (broken link) resolution
|
||||
|
||||
+────────────────────────────────────────────────────────+
|
||||
│ │
|
||||
│ index.gltf │
|
||||
│ │ │
|
||||
│ │ #: #-offlinetext │
|
||||
│ │ │
|
||||
│ ├── ◻ buttonA │
|
||||
│ │ └ href: http://foo.io/campagne.fbx │
|
||||
│ │ └ href@404: ipfs://foo.io/campagne.fbx │
|
||||
│ │ └ href@400: #clienterrortext │
|
||||
│ │ └ ◻ offlinetext │
|
||||
│ │ │
|
||||
│ └── ◻ embeddedObject <--------- the meshdata inside embeddedObject will (not)
|
||||
│ └ src: https://foo.io/bar.gltf │ be flushed when the request (does not) succeed.
|
||||
│ └ src@404: http://foo.io/bar.gltf │ So worstcase the 3D data (of the time of publishing index.gltf)
|
||||
│ └ src@400: https://archive.org/l2kj43.gltf │ will be displayed.
|
||||
│ │
|
||||
+────────────────────────────────────────────────────────+
|
||||
In spirit of Ted Nelson's 'transclusion resolution', there's a soft-mechanism to harden links & minimize broken links in various ways:
|
||||
|
||||
1. defining a different transport protocol (https vs ipfs or DAT) in `src` or `href` values can make a difference
|
||||
2. mirroring files on another protocol using (HTTP) errorcode tags in `src` or `href` properties
|
||||
3. in case of `src`: nesting a copy of the embedded object in the placeholder object (`embeddedObject`) will not be replaced when the request fails
|
||||
|
||||
> due to the popularity, maturity and extensiveness of HTTP codes for client/server communication, non-HTTP protocols easily map to HTTP codes (ipfs ERR_NOT_FOUND maps to 404 e.g.)
|
||||
|
||||
For example:
|
||||
|
||||
+────────────────────────────────────────────────────────+ │ │ │
|
||||
index.gltf │ │ │ │ │ │ #: #-offlinetext │ │ │ │ │ ├── ◻ buttonA │ │ │
|
||||
└ href: http://foo.io/campagne.fbx (http://foo.io/campagne.fbx) │ │ │
|
||||
└ href@404: ipfs://foo.io/campagne.fbx │ │ │ └ href@400:
|
||||
#clienterrortext │ │ │ └ ◻ offlinetext │ │ │ │ │ └── ◻ embeddedObject
|
||||
<--------- the meshdata inside embeddedObject will (not) │ └ src:
|
||||
https://foo.io/bar.gltf (https://foo.io/bar.gltf) │ be flushed when
|
||||
the request (does not) succeed. │ └ src@404: http://foo.io/bar.gltf
|
||||
|
||||
|
||||
|
||||
|
@ -1682,54 +1682,54 @@ van Kammen Expires 13 January 2025 [Page 30]
|
|||
Internet-Draft XR Fragments July 2024
|
||||
|
||||
|
||||
20. 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 filters:
|
||||
|
||||
* href: schoolA.edu/projects.gltf#math&-topics math
|
||||
* href: schoolB.edu/projects.gltf#math&-courses math
|
||||
* href: university.edu/projects.gltf#math&-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.
|
||||
|
||||
21. URI Templates (RFC6570)
|
||||
|
||||
XR Fragments adopts Level1 URI *Fragment* expansion to provide safe
|
||||
interactivity.
|
||||
The following demonstrates a simple video player:
|
||||
|
||||
|
||||
|
||||
(http://foo.io/bar.gltf) │ So worstcase the 3D data (of the time of
|
||||
publishing index.gltf) │ └ src@400: https://archive.org/l2kj43.gltf
|
||||
(https://archive.org/l2kj43.gltf) │ will be displayed. │ │
|
||||
+────────────────────────────────────────────────────────+
|
||||
|
||||
# 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.<br>
|
||||
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.<br>
|
||||
To filter out non-related objects one could take it a step further using filters:
|
||||
|
||||
* `href: schoolA.edu/projects.gltf#math&-topics math`
|
||||
* `href: schoolB.edu/projects.gltf#math&-courses math`
|
||||
* `href: university.edu/projects.gltf#math&-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.
|
||||
|
||||
# URI Templates (RFC6570)
|
||||
|
||||
XR Fragments adopts Level1 URI **Fragment** expansion to provide safe interactivity.<br>
|
||||
The following demonstrates a simple video player:
|
||||
|
||||
+─────────────────────────────────────────────+ │ │ │ foo.usdz │
|
||||
│ │ │
|
||||
│ │ │
|
||||
│ ├── ◻ stopbutton │ │ │ ├ #: #-stopbutton │ │ │ └ href:
|
||||
#player=stop&-stopbutton │ (stop and hide stop-button) │ │ │
|
||||
│ └── ◻ plane │ │ ├ play: #t=l:0,10 │ │ ├ stop: #t=0,0 │ │ ├ href:
|
||||
#player=play&stopbutton │ (play and show stop-button) │ └ src:
|
||||
cat.mp4#{player} │ │ │ │ │
|
||||
+─────────────────────────────────────────────+
|
||||
|
||||
```
|
||||
|
||||
20. Additional scene metadata
|
||||
|
||||
XR Fragments does not aim to redefine the metadata-space or
|
||||
accessibility-space by introducing its own cataloging-metadata
|
||||
fields. Instead, it encourages browsers to scan nodes for the
|
||||
following custom properties:
|
||||
|
||||
|
||||
|
||||
|
@ -1738,31 +1738,6 @@ van Kammen Expires 13 January 2025 [Page 31]
|
|||
Internet-Draft XR Fragments July 2024
|
||||
|
||||
|
||||
+─────────────────────────────────────────────+
|
||||
│ │
|
||||
│ foo.usdz │
|
||||
│ │ │
|
||||
│ │ │
|
||||
│ ├── ◻ stopbutton │
|
||||
│ │ ├ #: #-stopbutton │
|
||||
│ │ └ href: #player=stop&-stopbutton │ (stop and hide stop-button)
|
||||
│ │ │
|
||||
│ └── ◻ plane │
|
||||
│ ├ play: #t=l:0,10 │
|
||||
│ ├ stop: #t=0,0 │
|
||||
│ ├ href: #player=play&stopbutton │ (play and show stop-button)
|
||||
│ └ src: cat.mp4#{player} │
|
||||
│ │
|
||||
│ │
|
||||
+─────────────────────────────────────────────+
|
||||
|
||||
22. Additional scene metadata
|
||||
|
||||
XR Fragments does not aim to redefine the metadata-space or
|
||||
accessibility-space by introducing its own cataloging-metadata
|
||||
fields. Instead, it encourages browsers to scan nodes for the
|
||||
following custom properties:
|
||||
|
||||
* SPDX (https://spdx.dev/) license information
|
||||
* ARIA (https://www.w3.org/WAI/standards-guidelines/aria/)
|
||||
attributes (aria-*: .....)
|
||||
|
@ -1785,15 +1760,6 @@ Internet-Draft XR Fragments July 2024
|
|||
Individual nodes can be enriched with such metadata, but most
|
||||
importantly the scene node:
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
van Kammen Expires 13 January 2025 [Page 32]
|
||||
|
||||
Internet-Draft XR Fragments July 2024
|
||||
|
||||
|
||||
+================================+=========================+
|
||||
| metadata key | example value |
|
||||
+================================+=========================+
|
||||
|
@ -1821,13 +1787,20 @@ Internet-Draft XR Fragments July 2024
|
|||
|
||||
| * = these are interchangable (only one needs to be defined)
|
||||
|
||||
|
||||
|
||||
van Kammen Expires 13 January 2025 [Page 32]
|
||||
|
||||
Internet-Draft XR Fragments July 2024
|
||||
|
||||
|
||||
There's no silver bullet when it comes to metadata, so one should
|
||||
support where the metadata is/goes.
|
||||
|
||||
| These attributes can be scanned and presented during an href or
|
||||
| src eye/mouse-over.
|
||||
|
||||
23. Accessibility interface
|
||||
21. Accessibility interface
|
||||
|
||||
The addressibility of XR Fragments allows for unique 3D-to-text
|
||||
transcripts, as well as an textual interface to navigate 3D content.
|
||||
|
@ -1842,14 +1815,6 @@ Internet-Draft XR Fragments July 2024
|
|||
to read (via screenreader, screen, or TTS e.g.)
|
||||
4. the textlog contains aria-descriptions, and its narration
|
||||
(Screenreader e.g.) can be skipped (via 2-button navigation)
|
||||
|
||||
|
||||
|
||||
van Kammen Expires 13 January 2025 [Page 33]
|
||||
|
||||
Internet-Draft XR Fragments July 2024
|
||||
|
||||
|
||||
5. The back command should navigate back to the previous URL (alias
|
||||
for browser-backbutton)
|
||||
6. The forward command should navigate back to the next URL (alias
|
||||
|
@ -1877,7 +1842,15 @@ Internet-Draft XR Fragments July 2024
|
|||
https://.../... in case a 3D node exist with name abc and href
|
||||
value https://.../...
|
||||
|
||||
23.1. Two-button navigation
|
||||
|
||||
|
||||
|
||||
van Kammen Expires 13 January 2025 [Page 33]
|
||||
|
||||
Internet-Draft XR Fragments July 2024
|
||||
|
||||
|
||||
21.1. Two-button navigation
|
||||
|
||||
For specific user-profiles, gyroscope/mouse/keyboard/audio/visuals
|
||||
will not be available.
|
||||
|
@ -1891,22 +1864,7 @@ Internet-Draft XR Fragments July 2024
|
|||
3. the TTS reads the href-value (and/or aria-description if
|
||||
available)
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
van Kammen Expires 13 January 2025 [Page 34]
|
||||
|
||||
Internet-Draft XR Fragments July 2024
|
||||
|
||||
|
||||
24. Security Considerations
|
||||
22. Security Considerations
|
||||
|
||||
The only dynamic parts are W3C Media Fragments
|
||||
(https://www.w3.org/TR/media-frags/) and URI Templates (RFC6570)
|
||||
|
@ -1916,7 +1874,7 @@ Internet-Draft XR Fragments July 2024
|
|||
In fact, it is much safer than relying on a scripting language
|
||||
(javascript) which can change URN too.
|
||||
|
||||
25. FAQ
|
||||
23. FAQ
|
||||
|
||||
*Q:* Why is everything HTTP GET-based, what about POST/PUT/DELETE
|
||||
HATEOS
|
||||
|
@ -1940,6 +1898,14 @@ Internet-Draft XR Fragments July 2024
|
|||
scripting language.
|
||||
XR Fragments supports filtering objects in a scene only, because in
|
||||
the history of the javascript-powered web, showing/hiding document-
|
||||
|
||||
|
||||
|
||||
van Kammen Expires 13 January 2025 [Page 34]
|
||||
|
||||
Internet-Draft XR Fragments July 2024
|
||||
|
||||
|
||||
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
|
||||
|
@ -1949,24 +1915,16 @@ Internet-Draft XR Fragments July 2024
|
|||
place, to 'extend' experiences, in contrast to code/javascript inside
|
||||
hypermedia documents (this turned out as a hypermedia antipattern).
|
||||
|
||||
26. authors
|
||||
24. authors
|
||||
|
||||
* Leon van Kammen (@lvk@mastodon.online)
|
||||
* Jens Finkhäuser (@jens@social.finkhaeuser.de)
|
||||
|
||||
|
||||
|
||||
|
||||
van Kammen Expires 13 January 2025 [Page 35]
|
||||
|
||||
Internet-Draft XR Fragments July 2024
|
||||
|
||||
|
||||
27. IANA Considerations
|
||||
25. IANA Considerations
|
||||
|
||||
This document has no IANA actions.
|
||||
|
||||
28. Acknowledgments
|
||||
26. Acknowledgments
|
||||
|
||||
* NLNET (https://nlnet.nl)
|
||||
* Future of Text (https://futureoftext.org)
|
||||
|
@ -1981,7 +1939,7 @@ Internet-Draft XR Fragments July 2024
|
|||
* Brandel Zackernuk
|
||||
* Mark Anderson
|
||||
|
||||
29. Appendix: Definitions
|
||||
27. Appendix: Definitions
|
||||
|
||||
+=================+=============================================+
|
||||
| definition | explanation |
|
||||
|
@ -1996,6 +1954,14 @@ Internet-Draft XR Fragments July 2024
|
|||
| 3D object | an object inside a scene characterized by |
|
||||
| | vertex-, face- and customproperty data. |
|
||||
+-----------------+---------------------------------------------+
|
||||
|
||||
|
||||
|
||||
van Kammen Expires 13 January 2025 [Page 35]
|
||||
|
||||
Internet-Draft XR Fragments July 2024
|
||||
|
||||
|
||||
| URI | some resource at something somewhere via |
|
||||
| | someprotocol (http://me.com/foo.glb#foo or |
|
||||
| | e76f8efec8efce98e6f see interpeer.io |
|
||||
|
@ -2010,14 +1976,6 @@ Internet-Draft XR Fragments July 2024
|
|||
| | Object(nodes), relevant to machines and a |
|
||||
| | human minority (academics/developers) |
|
||||
+-----------------+---------------------------------------------+
|
||||
|
||||
|
||||
|
||||
van Kammen Expires 13 January 2025 [Page 36]
|
||||
|
||||
Internet-Draft XR Fragments July 2024
|
||||
|
||||
|
||||
| XR fragment | URI Fragment with spatial hints like |
|
||||
| | #pos=0,0,0&t=1,100 e.g. |
|
||||
+-----------------+---------------------------------------------+
|
||||
|
@ -2052,6 +2010,14 @@ Internet-Draft XR Fragments July 2024
|
|||
| | indirectly visible/editable in XR. |
|
||||
+-----------------+---------------------------------------------+
|
||||
| requestless | metadata which never spawns new requests |
|
||||
|
||||
|
||||
|
||||
van Kammen Expires 13 January 2025 [Page 36]
|
||||
|
||||
Internet-Draft XR Fragments July 2024
|
||||
|
||||
|
||||
| metadata | (unlike RDF/HTML, which can cause |
|
||||
| | framerate-dropping, hence not used a lot in |
|
||||
| | games) |
|
||||
|
@ -2066,14 +2032,6 @@ Internet-Draft XR Fragments July 2024
|
|||
| extrospective | outward sensemaking ("I'm fairly sure John |
|
||||
| | is a person who lives in oklahoma") |
|
||||
+-----------------+---------------------------------------------+
|
||||
|
||||
|
||||
|
||||
van Kammen Expires 13 January 2025 [Page 37]
|
||||
|
||||
Internet-Draft XR Fragments July 2024
|
||||
|
||||
|
||||
| ◻ | ascii representation of an 3D object/mesh |
|
||||
+-----------------+---------------------------------------------+
|
||||
| (un)obtrusive | obtrusive: wrapping human text/thought in |
|
||||
|
@ -2111,18 +2069,4 @@ Internet-Draft XR Fragments July 2024
|
|||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
van Kammen Expires 13 January 2025 [Page 38]
|
||||
van Kammen Expires 13 January 2025 [Page 37]
|
||||
|
|
|
@ -1105,12 +1105,12 @@ Some pointers for good UX (but not necessary to be XR Fragment compatible):</t>
|
|||
| | | author.com/article.txt |
|
||||
| index.gltf | +------------------------+
|
||||
| │ | | |
|
||||
| ├── ◻ article_canvas | | Hello friends. |
|
||||
| ├── ◻ article_canvas | | Hello #friends |
|
||||
| │ └ src: ://author.com/article.txt | | |
|
||||
| │ | | @book{greatgatsby |
|
||||
| └── ◻ note_canvas | | ... |
|
||||
| └ src:`data:welcome human\n@book{sunday...}` | | } |
|
||||
| | +------------------------+
|
||||
| │ | +------------------------+
|
||||
| └── ◻ note_canvas |
|
||||
| └ src:`data:welcome human\n@book{sunday...}` |
|
||||
| |
|
||||
| |
|
||||
+--------------------------------------------------------------+
|
||||
]]>
|
||||
|
@ -1131,90 +1131,102 @@ The XR Fragment-compatible browser can let the enduser access visual-meta(data)-
|
|||
</ol>
|
||||
</section>
|
||||
|
||||
<section anchor="transclusion-broken-link-resolution"><name>Transclusion (broken link) resolution</name>
|
||||
<t>In spirit of Ted Nelson's 'transclusion resolution', there's a soft-mechanism to harden links & minimize broken links in various ways:</t>
|
||||
<section anchor="reflection-mapping"><name>Reflection Mapping</name>
|
||||
<t>Environment mapping is crucial for creating realistic reflections and lighting effects on 3D objects.
|
||||
To apply environment mapping efficiently in a 3D scene, traverse the scene graph and assign each object's environment map based on the nearest ancestor's texture map. This ensures that objects inherit the correct environment mapping from their closest parent with a texture, enhancing the visual consistency and realism.</t>
|
||||
<t>``````
|
||||
+--------------------------------+<br />
|
||||
| |<br />
|
||||
| index.usdz |<br />
|
||||
| │ |<br />
|
||||
| └── ◻ sphere (texture:foo) |
|
||||
| └ ◻ cube (texture:bar) | envMap = foo
|
||||
| └ ◻ cylinder | envMap = bar
|
||||
+--------------------------------+</t>
|
||||
|
||||
<ol spacing="compact">
|
||||
<li>defining a different transport protocol (https vs ipfs or DAT) in <tt>src</tt> or <tt>href</tt> values can make a difference</li>
|
||||
<li>mirroring files on another protocol using (HTTP) errorcode tags in <tt>src</tt> or <tt>href</tt> properties</li>
|
||||
<li>in case of <tt>src</tt>: nesting a copy of the embedded object in the placeholder object (<tt>embeddedObject</tt>) will not be replaced when the request fails</li>
|
||||
</ol>
|
||||
<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><![CDATA[
|
||||
Most 3D viewers apply one and the same environment map for various models, however this logic
|
||||
allows a more natural & automatic strategy for reflection mapping.
|
||||
|
||||
<artwork><![CDATA[ +────────────────────────────────────────────────────────+
|
||||
# Transclusion (broken link) resolution
|
||||
|
||||
In spirit of Ted Nelson's 'transclusion resolution', there's a soft-mechanism to harden links & minimize broken links in various ways:
|
||||
|
||||
1. defining a different transport protocol (https vs ipfs or DAT) in `src` or `href` values can make a difference
|
||||
2. mirroring files on another protocol using (HTTP) errorcode tags in `src` or `href` properties
|
||||
3. in case of `src`: nesting a copy of the embedded object in the placeholder object (`embeddedObject`) will not be replaced when the request fails
|
||||
|
||||
> due to the popularity, maturity and extensiveness of HTTP codes for client/server communication, non-HTTP protocols easily map to HTTP codes (ipfs ERR_NOT_FOUND maps to 404 e.g.)
|
||||
|
||||
For example:
|
||||
|
||||
]]>
|
||||
</artwork>
|
||||
<t>+────────────────────────────────────────────────────────+
|
||||
│ │
|
||||
│ index.gltf │
|
||||
│ │ │
|
||||
│ │ #: #-offlinetext │
|
||||
│ │ │
|
||||
│ ├── ◻ buttonA │
|
||||
│ │ └ href: http://foo.io/campagne.fbx │
|
||||
│ │ └ href: <eref target="http://foo.io/campagne.fbx">http://foo.io/campagne.fbx</eref> │
|
||||
│ │ └ href@404: ipfs://foo.io/campagne.fbx │
|
||||
│ │ └ href@400: #clienterrortext │
|
||||
│ │ └ ◻ offlinetext │
|
||||
│ │ │
|
||||
│ └── ◻ embeddedObject <--------- the meshdata inside embeddedObject will (not)
|
||||
│ └ src: https://foo.io/bar.gltf │ be flushed when the request (does not) succeed.
|
||||
│ └ src@404: http://foo.io/bar.gltf │ So worstcase the 3D data (of the time of publishing index.gltf)
|
||||
│ └ src@400: https://archive.org/l2kj43.gltf │ will be displayed.
|
||||
│ └── ◻ embeddedObject <--------- the meshdata inside embeddedObject will (not)
|
||||
│ └ src: <eref target="https://foo.io/bar.gltf">https://foo.io/bar.gltf</eref> │ be flushed when the request (does not) succeed.
|
||||
│ └ src@404: <eref target="http://foo.io/bar.gltf">http://foo.io/bar.gltf</eref> │ So worstcase the 3D data (of the time of publishing index.gltf)
|
||||
│ └ src@400: <eref target="https://archive.org/l2kj43.gltf">https://archive.org/l2kj43.gltf</eref> │ will be displayed.
|
||||
│ │
|
||||
+────────────────────────────────────────────────────────+
|
||||
+────────────────────────────────────────────────────────+</t>
|
||||
|
||||
<artwork><![CDATA[
|
||||
# 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.<br>
|
||||
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.<br>
|
||||
To filter out non-related objects one could take it a step further using filters:
|
||||
|
||||
* `href: schoolA.edu/projects.gltf#math&-topics math`
|
||||
* `href: schoolB.edu/projects.gltf#math&-courses math`
|
||||
* `href: university.edu/projects.gltf#math&-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.
|
||||
|
||||
# URI Templates (RFC6570)
|
||||
|
||||
XR Fragments adopts Level1 URI **Fragment** expansion to provide safe interactivity.<br>
|
||||
The following demonstrates a simple video player:
|
||||
|
||||
]]>
|
||||
</artwork>
|
||||
</section>
|
||||
|
||||
<section anchor="topic-based-index-less-webrings"><name>Topic-based index-less Webrings</name>
|
||||
<t>As hashtags in URLs map to the XWRG, <tt>href</tt>-values can be used to promote topic-based index-less webrings.<br />
|
||||
|
||||
Consider 3D scenes linking to eachother using these <tt>href</tt> values:</t>
|
||||
|
||||
<ul spacing="compact">
|
||||
<li><tt>href: schoolA.edu/projects.gltf#math</tt></li>
|
||||
<li><tt>href: schoolB.edu/projects.gltf#math</tt></li>
|
||||
<li><tt>href: university.edu/projects.gltf#math</tt></li>
|
||||
</ul>
|
||||
<t>These links would all show visible links to math-tagged objects in the scene.<br />
|
||||
|
||||
To filter out non-related objects one could take it a step further using filters:</t>
|
||||
|
||||
<ul spacing="compact">
|
||||
<li><tt>href: schoolA.edu/projects.gltf#math&-topics math</tt></li>
|
||||
<li><tt>href: schoolB.edu/projects.gltf#math&-courses math</tt></li>
|
||||
<li><tt>href: university.edu/projects.gltf#math&-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="uri-templates-rfc6570"><name>URI Templates (RFC6570)</name>
|
||||
<t>XR Fragments adopts Level1 URI <strong>Fragment</strong> expansion to provide safe interactivity.<br />
|
||||
|
||||
The following demonstrates a simple video player:</t>
|
||||
|
||||
<artwork><![CDATA[
|
||||
+─────────────────────────────────────────────+
|
||||
<t>+─────────────────────────────────────────────+
|
||||
│ │
|
||||
│ foo.usdz │
|
||||
│ │ │
|
||||
│ │ │
|
||||
│ foo.usdz │<br />
|
||||
│ │ │<br />
|
||||
│ │ │<br />
|
||||
│ ├── ◻ stopbutton │
|
||||
│ │ ├ #: #-stopbutton │
|
||||
│ │ └ href: #player=stop&-stopbutton │ (stop and hide stop-button)
|
||||
│ │ │
|
||||
│ │ └ href: #player=stop&-stopbutton │ (stop and hide stop-button)
|
||||
│ │ │<br />
|
||||
│ └── ◻ plane │
|
||||
│ ├ play: #t=l:0,10 │
|
||||
│ ├ stop: #t=0,0 │
|
||||
│ ├ href: #player=play&stopbutton │ (play and show stop-button)
|
||||
│ ├ href: #player=play&stopbutton │ (play and show stop-button)
|
||||
│ └ src: cat.mp4#{player} │
|
||||
│ │
|
||||
│ │
|
||||
+─────────────────────────────────────────────+
|
||||
|
||||
|
||||
]]>
|
||||
</artwork>
|
||||
+─────────────────────────────────────────────+</t>
|
||||
<t>```</t>
|
||||
</section>
|
||||
|
||||
<section anchor="additional-scene-metadata"><name>Additional scene metadata</name>
|
||||
|
|
|
@ -17,7 +17,6 @@
|
|||
</head>
|
||||
<body>
|
||||
<a-scene xr-mode-ui="XRMode: xr"
|
||||
envmap="src: https://coderofsalvation.github.io/xrfragment.media/images/sky.jpg"
|
||||
renderer="colorManagement: false; antialias:true; highRefreshRate:true; foveationLevel: 0.5; toneMapping: ACESFilmic; exposure: 3.0"
|
||||
device-orientation-permission-ui
|
||||
light="defaultLightsEnabled: false">
|
||||
|
|
Binary file not shown.
|
@ -9,16 +9,16 @@
|
|||
<body style="overflow:hidden; padding:10%">
|
||||
|
||||
<h1><model-viewer> example</h1>
|
||||
<br><br>
|
||||
|
||||
<div style="width:90%; height:70vh">
|
||||
<model-viewer
|
||||
src="./../assets/index.glb"
|
||||
environment-image="https://cdn.glitch.global/8e507517-31ff-4aa5-80c1-10ea6de9483d/white_furnace.hdr"
|
||||
ar alt="XR Fragments demo scene" camera-controls touch-action="none" camera-orbit="-8.142746deg 68.967deg 0.6179899m" camera-target="-0.003m 0.0722m 0.0391m" field-of-view="45deg" min-field-of-view="25deg" max-field-of-view="45deg" interpolation-decay="200" min-camera-orbit="auto auto 5%"
|
||||
style="width:100%; height:100%; border-radius:5px; border:1px solid #CCC"
|
||||
>
|
||||
</model-viewer>
|
||||
</div>
|
||||
<model-viewer
|
||||
src="./../assets/index.glb"
|
||||
environment-image="https://cdn.glitch.global/8e507517-31ff-4aa5-80c1-10ea6de9483d/white_furnace.hdr"
|
||||
ar alt="XR Fragments demo scene" touch-action="none" disable-pan disable-zoom
|
||||
field-of-view="75deg" min-field-of-view="25deg" max-field-of-view="100deg"
|
||||
style="width:80%; height:50vh; border-radius:5px; border:1px solid #CCC"
|
||||
>
|
||||
</model-viewer>
|
||||
|
||||
<script type="importmap">
|
||||
{
|
||||
|
@ -36,8 +36,8 @@
|
|||
import { USDZLoader } from 'three/addons/loaders/USDZLoader.js';
|
||||
import { OBJLoader } from 'three/addons/loaders/OBJLoader.js';
|
||||
|
||||
const mv = document.querySelector("model-viewer");
|
||||
const $url = document.querySelector('#url')
|
||||
const mv = window.mv = document.querySelector("model-viewer");
|
||||
const $url = document.querySelector('#url')
|
||||
const orbitDefault = '50deg 90deg 1.0m'
|
||||
|
||||
function getSymbol(name) {
|
||||
|
@ -52,34 +52,6 @@
|
|||
} while ((obj = Object.getPrototypeOf(obj)));
|
||||
}
|
||||
|
||||
const setupCSS = (scene) => {
|
||||
if( document.querySelector('#viewbutton-css') ) return
|
||||
let style = document.createElement('style')
|
||||
style.type = 'text/css'
|
||||
style.innerHTML = `
|
||||
.view-button {
|
||||
background: #fff;
|
||||
border-radius: 4px;
|
||||
border: none;
|
||||
box-sizing: border-box;
|
||||
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.25);
|
||||
color: rgba(0, 0, 0, 0.8);
|
||||
display: block;
|
||||
font-family: Futura, Helvetica Neue, sans-serif;
|
||||
font-size: 12px;
|
||||
font-weight: 700;
|
||||
max-width: 128px;
|
||||
overflow-wrap: break-word;
|
||||
padding: 0.5em 1em;
|
||||
position: absolute;
|
||||
width: max-content;
|
||||
height: max-content;
|
||||
transform: translate3d(-50%, -50%, 0);
|
||||
}
|
||||
`
|
||||
document.body.appendChild(style)
|
||||
}
|
||||
|
||||
const createHotspot = (pos, n) => {
|
||||
//.name, `${n.userData['aria-description'] || n.name}` )
|
||||
const btn = document.createElement('button')
|
||||
|
@ -95,6 +67,10 @@
|
|||
btn.setAttribute('data-position',`${pos.x}m ${pos.y}m ${pos.z}m`)
|
||||
btn.setAttribute('data-target',`${pos.x}m ${pos.y}m ${pos.z}m`)
|
||||
btn.setAttribute('data-orbit', orbitDefault )
|
||||
// btn.style.opacity = 0.01
|
||||
btn.style.borderRadius = '50%'
|
||||
btn.style.padding = '30px'
|
||||
btn.style.cursor = 'pointer'
|
||||
mv.appendChild(btn)
|
||||
}
|
||||
|
||||
|
@ -106,21 +82,7 @@
|
|||
createHotspot(pos, n)
|
||||
}
|
||||
})
|
||||
|
||||
}
|
||||
|
||||
const setupDefaultProjection = () => {
|
||||
xrf.addEventListener('navigateLoaded', () => {
|
||||
let frag = xrf.URI.parse( xrf.scene.children[0].userData['#'] )
|
||||
if( frag.XRF.pos ){
|
||||
let obj = xrf.scene.getObjectByName( frag.XRF.pos.string )
|
||||
if( !obj ) return console.error('obj '+frag.XRF.pos.string+" not found")
|
||||
const pos = obj.position
|
||||
mv.cameraTarget = `${pos.x} ${pos.y} ${pos.z}`
|
||||
mv.cameraOrbit = orbitDefault;
|
||||
mv.fieldOfView = '45deg';
|
||||
}
|
||||
})
|
||||
setupClicks()
|
||||
}
|
||||
|
||||
const setupClicks = () => {
|
||||
|
@ -132,8 +94,9 @@
|
|||
mv.cameraOrbit = dataset.orbit;
|
||||
mv.fieldOfView = '45deg';
|
||||
console.dir(node)
|
||||
if( node && node.userData.XRF && node.userData.XRF.href ){
|
||||
node.userData.XRF.href.exec({type:'click'})
|
||||
if( node && node.userData.href ){
|
||||
// xrf.navigator.to( node.userData.href )
|
||||
//node.userData.XRF.href.exec({type:'click'})
|
||||
console.log("clicked!")
|
||||
}
|
||||
}
|
||||
|
@ -142,24 +105,49 @@
|
|||
});
|
||||
}
|
||||
|
||||
const clear = (obj) => {
|
||||
while(obj.children.length > 0){
|
||||
clear(obj.children[0]);
|
||||
obj.remove(obj.children[0]);
|
||||
const setupDefaultProjection = () => {
|
||||
let frag = xrf.URI.parse( xrf.scene.children[0].userData['#'] )
|
||||
if( frag.XRF.pos ){
|
||||
let obj = xrf.scene.getObjectByName( frag.XRF.pos.string )
|
||||
if( !obj ) return console.error('obj '+frag.XRF.pos.string+" not found")
|
||||
console.log("updating cam")
|
||||
const pos = new THREE.Vector3()
|
||||
obj.getWorldPosition(pos)
|
||||
obj.position.y += 1.6 // add person length
|
||||
mv.cameraTarget = `${pos.x} ${pos.y} ${pos.z}`
|
||||
console.log(`${pos.x} ${pos.y} ${pos.z}`)
|
||||
mv.cameraOrbit = orbitDefault;
|
||||
mv.fieldOfView = '45deg';
|
||||
}
|
||||
if(obj.geometry) obj.geometry.dispose();
|
||||
}
|
||||
|
||||
if(obj.material){
|
||||
//in case of map, bumpMap, normalMap, envMap ...
|
||||
Object.keys(obj.material).forEach(prop => {
|
||||
if(!obj.material[prop])
|
||||
return;
|
||||
if(obj.material[prop] !== null && typeof obj.material[prop].dispose === 'function')
|
||||
obj.material[prop].dispose();
|
||||
})
|
||||
obj.material.dispose();
|
||||
}
|
||||
}
|
||||
const setupCSS = (scene) => {
|
||||
//if( document.querySelector('#viewbutton-css') ) return
|
||||
//let style = document.createElement('style')
|
||||
//style.type = 'text/css'
|
||||
//style.innerHTML = `
|
||||
// .view-button {
|
||||
// background: #fff;
|
||||
// border-radius: 4px;
|
||||
// border: none;
|
||||
// box-sizing: border-box;
|
||||
// box-shadow: 0 2px 4px rgba(0, 0, 0, 0.25);
|
||||
// color: rgba(0, 0, 0, 0.8);
|
||||
// display: block;
|
||||
// font-family: Futura, Helvetica Neue, sans-serif;
|
||||
// font-size: 12px;
|
||||
// font-weight: 700;
|
||||
// max-width: 128px;
|
||||
// overflow-wrap: break-word;
|
||||
// padding: 0.5em 1em;
|
||||
// position: absolute;
|
||||
// width: max-content;
|
||||
// height: max-content;
|
||||
// transform: translate3d(-50%, -50%, 0);
|
||||
// }
|
||||
//`
|
||||
//document.body.appendChild(style)
|
||||
}
|
||||
|
||||
const opts = {
|
||||
xrf,
|
||||
|
@ -171,10 +159,9 @@
|
|||
const renderer = mv[getSymbol("renderer")].threeRenderer
|
||||
const controls = mv[getSymbol("controls")]
|
||||
const camera = mv[getSymbol("scene")].getCamera()
|
||||
|
||||
clear(scene);
|
||||
const url = mv.src
|
||||
|
||||
opts = {
|
||||
opts = window.opts = {
|
||||
...opts,
|
||||
scene,
|
||||
renderer,
|
||||
|
@ -185,34 +172,31 @@
|
|||
|
||||
window.opts = opts
|
||||
|
||||
if( camera.parent == null ) scene.add(camera) // xr fragments expects in-scene camera
|
||||
// mark current loaded scene for deletion by xrfragment library (except camera)
|
||||
//scene.traverse( (o) => o.isXRF = o.id != camera.id )
|
||||
|
||||
// enable XR fragments
|
||||
if( camera.parent == null ) scene.add(camera) // xr fragments expects in-scene camera
|
||||
let xrf = opts.xrf.init(opts)
|
||||
window.xrf = xrf
|
||||
//
|
||||
xrf.sceneRoot.children.map( (c) => (camera.id != c.id) && (c.visible = false) )
|
||||
|
||||
xrf.addEventListener('href', (opts) => {
|
||||
console.log("href!")
|
||||
console.dir(opts)
|
||||
})
|
||||
//
|
||||
let url = mv.src
|
||||
|
||||
setupDefaultProjection(xrf)
|
||||
// $url.value = url
|
||||
// mark current loaded scene for deletion by xrfragment library (except camera)
|
||||
|
||||
xrf.addEventListener('navigateLoaded', function(opts){
|
||||
|
||||
console.dir(xrf.scene)
|
||||
setupCSS()
|
||||
setupHotspots(scene)
|
||||
// setupDefaultProjection()
|
||||
console.log("ready")
|
||||
})
|
||||
|
||||
// now we re-insert the model via the XR Fragments lib (so it will parse the XRF metadata)
|
||||
xrf.navigator.URI = xrf.URI.parse(document.location.href)
|
||||
xrf.navigator.to(url)
|
||||
//if( xrf.URI.isRelative( xrf.URI.parse(url) ) ){
|
||||
// xrf.navigator.URI = xrf.URI.parse( xrf.navigator.URI.URN + url )
|
||||
//}
|
||||
//xrf.loadModel({...scene, scene},url,true)
|
||||
|
||||
//setupCSS()
|
||||
//setupHotspots(scene)
|
||||
//setupClicks()
|
||||
console.log("ready")
|
||||
}
|
||||
|
||||
mv.addEventListener("load", onLoad(opts) )
|
||||
|
|
|
@ -1,28 +0,0 @@
|
|||
// poor man's way to move forward using hand gesture pinch
|
||||
|
||||
window.AFRAME.registerComponent('envmap', {
|
||||
schema:{
|
||||
src: {type: "string"}
|
||||
},
|
||||
init: function(){
|
||||
const loader = new THREE.TextureLoader();
|
||||
const onLoad = (texture) => {
|
||||
texture.colorSpace = THREE.SRGBColorSpace;
|
||||
texture.mapping = THREE.EquirectangularReflectionMapping;
|
||||
texture.needsUpdate = true
|
||||
xrf.scene.environment = texture
|
||||
xrf.scene.texture = texture
|
||||
}
|
||||
new THREE.TextureLoader().load( this.data.src, onLoad, null, console.error );
|
||||
|
||||
xrf.addEventListener('navigateLoaded', () => {
|
||||
xrf.scene.traverse( (n) => {
|
||||
if( n.material && n.material.isMeshPhysicalMaterial){
|
||||
n.material.envMap = xrf.scene.environment
|
||||
n.material.needsUpdate = true
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
},
|
||||
})
|
|
@ -91,7 +91,6 @@ window.accessibility = (opts) => new Proxy({
|
|||
setupHrefCycling(){
|
||||
// speak arrow keys
|
||||
window.addEventListener('keydown', (e) => {
|
||||
console.log(e.key)
|
||||
if( e.key != "Tab" && e.key != "Enter" ) return
|
||||
let subScene = xrf.scene.getObjectByName( xrf.frag.pos.last )
|
||||
if( !subScene ) subScene = xrf.scene
|
||||
|
|
|
@ -53,7 +53,6 @@ xrf.loadModel = function(model,url,noadd){
|
|||
let {directory,file,fragment,fileExt} = URI;
|
||||
model.file = URI.file
|
||||
xrf.model = model
|
||||
xrf.scene = model.scene
|
||||
|
||||
if( !model.isXRF ) xrf.parseModel(model,url.replace(directory,"")) // this marks the model as an XRF model
|
||||
|
||||
|
@ -70,7 +69,7 @@ xrf.loadModel = function(model,url,noadd){
|
|||
const defaultFragment = xrf.frag.defaultPredefinedViews({model,scene:model.scene})
|
||||
// spec: predefined view(s) & objects-of-interest-in-XRWG from URI (https://xrfragment.org/#predefined_view)
|
||||
let frag = xrf.hashbus.pub( url, model) // and eval URI XR fragments
|
||||
|
||||
|
||||
if( !noadd ) xrf.add( model.scene )
|
||||
|
||||
// only change url when loading *another* file
|
||||
|
@ -124,6 +123,7 @@ xrf.reset = () => {
|
|||
}
|
||||
|
||||
xrf.add = (object) => {
|
||||
|
||||
object.isXRF = true // mark for easy deletion when replacing scene
|
||||
xrf.scene.add(object)
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue