href portal wip

This commit is contained in:
Leon van Kammen 2023-05-10 19:12:15 +02:00
parent 2953be9cd6
commit 21ffc80e07
8 changed files with 482 additions and 213 deletions

View file

@ -605,9 +605,18 @@ xrfragment.init = function(opts){
for ( let i in xrfragment.XRF ) xrfragment.XRF[i] // shortcuts to constants (NAVIGATOR e.g.) for ( let i in xrfragment.XRF ) xrfragment.XRF[i] // shortcuts to constants (NAVIGATOR e.g.)
xrfragment.Parser.debug = xrfragment.debug xrfragment.Parser.debug = xrfragment.debug
if( opts.loaders ) opts.loaders.map( xrfragment.patchLoader ) if( opts.loaders ) opts.loaders.map( xrfragment.patchLoader )
xrfragment.patchRenderer(opts.renderer)
return xrfragment return xrfragment
} }
xrfragment.patchRenderer = function(renderer){
renderer.render = ((render) => function(scene,camera){
if( xrfragment.getLastModel() && xrfragment.getLastModel().render )
xrfragment.getLastModel().render(scene,camera)
render(scene,camera)
})(renderer.render.bind(renderer))
}
xrfragment.patchLoader = function(loader){ xrfragment.patchLoader = function(loader){
loader.prototype.load = ((load) => function(url, onLoad, onProgress, onError){ loader.prototype.load = ((load) => function(url, onLoad, onProgress, onError){
load.call( this, load.call( this,
@ -678,60 +687,53 @@ xrfragment.xrf.env = function(v, opts){
} }
xrfragment.xrf.href = function(v, opts){ xrfragment.xrf.href = function(v, opts){
let { mesh, model, camera, scene, renderer, THREE} = opts let { mesh, model, camera, scene, renderer, THREE} = opts
return
// Create a shader material that treats the texture as an equirectangular map let size = 5
mesh.texture = mesh.material.map // backup texture let texture = mesh.material.map
const equirectShader = THREE.ShaderLib[ 'equirect' ];
const equirectMaterial = new THREE.ShaderMaterial( {
uniforms: THREE.UniformsUtils.merge([
THREE.UniformsLib.equirect,
equirectShader.uniforms,
]),
vertexShader: equirectShader.vertexShader,
fragmentShader: equirectShader.fragmentShader,
side: THREE.DoubleSide //THREE.FrontSide //THREE.DoubleSide //THREE.BackSide
} );
equirectMaterial.uniforms[ 'tEquirect' ].value = mesh.texture
// Define the tEquirectInvProjection uniform
equirectMaterial.uniforms.tEquirectInvProjection = {
value: new THREE.Matrix4(),
};
// Assign the new material to the mesh
mesh.material = equirectMaterial;
console.dir(mesh.material)
mesh.texture.wrapS = THREE.RepeatWrapping;
// patch custom model renderloop /*
model.render = ((render) => (scene,camera) => { texture.wrapS = texture.wrapT = THREE.ClampToEdgeWrapping;
mesh.material = new THREE.MeshStandardMaterial( {
envMap: texture,
roughness: 0.0,
metalness: 1,
side: THREE.DoubleSide,
})
*/
// Store the original projection matrix of the camera mesh.material = new THREE.ShaderMaterial( {
const originalProjectionMatrix = camera.projectionMatrix.clone(); side: THREE.DoubleSide,
// Calculate the current camera view matrix uniforms: {
const aspectRatio = mesh.texture.image.width / mesh.texture.image.height; pano: { value: texture }
camera.projectionMatrix.makePerspective(camera.fov, aspectRatio, camera.near, camera.far); },
vertexShader: `
const viewMatrix = camera.matrixWorldInverse; vec3 portalPosition;
const worldMatrix = mesh.matrixWorld; varying vec3 vWorldPosition;
varying float vDistanceToCenter;
const equirectInvProjection = new THREE.Matrix4(); varying float vDistance;
equirectInvProjection.copy(camera.projectionMatrix).multiply(viewMatrix).invert(); void main() {
vDistanceToCenter = clamp(length(position - vec3(0.0, 0.0, 0.0)), 0.0, 1.0);
// Update the equirectangular material's tEquirect uniform portalPosition = (modelMatrix * vec4(0.0, 0.0, 0.0, 1.0)).xyz;
equirectMaterial.uniforms.tEquirect.value = mesh.texture; vDistance = length(portalPosition - cameraPosition);
equirectMaterial.uniforms.tEquirectInvProjection.value.copy( vWorldPosition = (modelMatrix * vec4(position, 1.0)).xyz;
equirectInvProjection gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
); }
`,
// Reset the camera projection matrix fragmentShader: `
camera.projectionMatrix.copy(originalProjectionMatrix); #define RECIPROCAL_PI2 0.15915494
uniform sampler2D pano;
varying float vDistanceToCenter;
render(scene,camera) varying float vDistance;
varying vec3 vWorldPosition;
})(model.render) void main() {
vec3 direction = normalize(vWorldPosition - cameraPosition);
console.dir(mesh) vec2 sampleUV;
sampleUV.y = -clamp(direction.y * 0.5 + 0.5, 0.0, 1.0);
sampleUV.x = atan(direction.z, -direction.x) * -RECIPROCAL_PI2 + 0.5;
gl_FragColor = texture2D(pano, sampleUV);
}
`
});
} }
xrfragment.xrf.pos = function(v, opts){ xrfragment.xrf.pos = function(v, opts){
let { frag, mesh, model, camera, scene, renderer, THREE} = opts let { frag, mesh, model, camera, scene, renderer, THREE} = opts
@ -818,3 +820,36 @@ window.AFRAME.registerComponent('xrf', {
} }
}); });
AFRAME.registerComponent('gltf-to-entity', {
schema: {
from: {default: '', type: 'selector'},
name: {default: ''},
duplicate: {type:'boolean'}
},
init: function () {
var el = this.el;
var data = this.data;
data.from.addEventListener('model-loaded', evt => {
var model;
var subset;
model = evt.detail.model;
console.dir(this.data.from)
subset = model.getObjectByName(data.name);
if (!subset){
console.error("Sub-object", data.name, "not found in #"+data.from.id);
return;
}
if( !this.data.duplicate ) subset.parent.remove(subset)
let clone = subset.clone()
////subset.updateMatrixWorld();
el.object3D.position.setFromMatrixPosition(data.from.object3D.matrixWorld);
el.object3D.quaternion.setFromRotationMatrix(data.from.object3D.matrixWorld);
el.setObject3D('mesh', clone );
el.emit('model-loaded', el.getObject3D('mesh'));
});
}
});

View file

@ -605,9 +605,18 @@ xrfragment.init = function(opts){
for ( let i in xrfragment.XRF ) xrfragment.XRF[i] // shortcuts to constants (NAVIGATOR e.g.) for ( let i in xrfragment.XRF ) xrfragment.XRF[i] // shortcuts to constants (NAVIGATOR e.g.)
xrfragment.Parser.debug = xrfragment.debug xrfragment.Parser.debug = xrfragment.debug
if( opts.loaders ) opts.loaders.map( xrfragment.patchLoader ) if( opts.loaders ) opts.loaders.map( xrfragment.patchLoader )
xrfragment.patchRenderer(opts.renderer)
return xrfragment return xrfragment
} }
xrfragment.patchRenderer = function(renderer){
renderer.render = ((render) => function(scene,camera){
if( xrfragment.getLastModel() && xrfragment.getLastModel().render )
xrfragment.getLastModel().render(scene,camera)
render(scene,camera)
})(renderer.render.bind(renderer))
}
xrfragment.patchLoader = function(loader){ xrfragment.patchLoader = function(loader){
loader.prototype.load = ((load) => function(url, onLoad, onProgress, onError){ loader.prototype.load = ((load) => function(url, onLoad, onProgress, onError){
load.call( this, load.call( this,
@ -678,60 +687,53 @@ xrfragment.xrf.env = function(v, opts){
} }
xrfragment.xrf.href = function(v, opts){ xrfragment.xrf.href = function(v, opts){
let { mesh, model, camera, scene, renderer, THREE} = opts let { mesh, model, camera, scene, renderer, THREE} = opts
return
// Create a shader material that treats the texture as an equirectangular map let size = 5
mesh.texture = mesh.material.map // backup texture let texture = mesh.material.map
const equirectShader = THREE.ShaderLib[ 'equirect' ];
const equirectMaterial = new THREE.ShaderMaterial( {
uniforms: THREE.UniformsUtils.merge([
THREE.UniformsLib.equirect,
equirectShader.uniforms,
]),
vertexShader: equirectShader.vertexShader,
fragmentShader: equirectShader.fragmentShader,
side: THREE.DoubleSide //THREE.FrontSide //THREE.DoubleSide //THREE.BackSide
} );
equirectMaterial.uniforms[ 'tEquirect' ].value = mesh.texture
// Define the tEquirectInvProjection uniform
equirectMaterial.uniforms.tEquirectInvProjection = {
value: new THREE.Matrix4(),
};
// Assign the new material to the mesh
mesh.material = equirectMaterial;
console.dir(mesh.material)
mesh.texture.wrapS = THREE.RepeatWrapping;
// patch custom model renderloop /*
model.render = ((render) => (scene,camera) => { texture.wrapS = texture.wrapT = THREE.ClampToEdgeWrapping;
mesh.material = new THREE.MeshStandardMaterial( {
envMap: texture,
roughness: 0.0,
metalness: 1,
side: THREE.DoubleSide,
})
*/
// Store the original projection matrix of the camera mesh.material = new THREE.ShaderMaterial( {
const originalProjectionMatrix = camera.projectionMatrix.clone(); side: THREE.DoubleSide,
// Calculate the current camera view matrix uniforms: {
const aspectRatio = mesh.texture.image.width / mesh.texture.image.height; pano: { value: texture }
camera.projectionMatrix.makePerspective(camera.fov, aspectRatio, camera.near, camera.far); },
vertexShader: `
const viewMatrix = camera.matrixWorldInverse; vec3 portalPosition;
const worldMatrix = mesh.matrixWorld; varying vec3 vWorldPosition;
varying float vDistanceToCenter;
const equirectInvProjection = new THREE.Matrix4(); varying float vDistance;
equirectInvProjection.copy(camera.projectionMatrix).multiply(viewMatrix).invert(); void main() {
vDistanceToCenter = clamp(length(position - vec3(0.0, 0.0, 0.0)), 0.0, 1.0);
// Update the equirectangular material's tEquirect uniform portalPosition = (modelMatrix * vec4(0.0, 0.0, 0.0, 1.0)).xyz;
equirectMaterial.uniforms.tEquirect.value = mesh.texture; vDistance = length(portalPosition - cameraPosition);
equirectMaterial.uniforms.tEquirectInvProjection.value.copy( vWorldPosition = (modelMatrix * vec4(position, 1.0)).xyz;
equirectInvProjection gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
); }
`,
// Reset the camera projection matrix fragmentShader: `
camera.projectionMatrix.copy(originalProjectionMatrix); #define RECIPROCAL_PI2 0.15915494
uniform sampler2D pano;
varying float vDistanceToCenter;
render(scene,camera) varying float vDistance;
varying vec3 vWorldPosition;
})(model.render) void main() {
vec3 direction = normalize(vWorldPosition - cameraPosition);
console.dir(mesh) vec2 sampleUV;
sampleUV.y = -clamp(direction.y * 0.5 + 0.5, 0.0, 1.0);
sampleUV.x = atan(direction.z, -direction.x) * -RECIPROCAL_PI2 + 0.5;
gl_FragColor = texture2D(pano, sampleUV);
}
`
});
} }
xrfragment.xrf.pos = function(v, opts){ xrfragment.xrf.pos = function(v, opts){
let { frag, mesh, model, camera, scene, renderer, THREE} = opts let { frag, mesh, model, camera, scene, renderer, THREE} = opts

View file

@ -9,13 +9,14 @@
<link type="text/css" rel="stylesheet" href="./../../assets/style.css"/> <link type="text/css" rel="stylesheet" href="./../../assets/style.css"/>
<script async src="./../../assets/alpine.min.js"></script> <script async src="./../../assets/alpine.min.js"></script>
<script src="https://aframe.io/releases/1.4.0/aframe.min.js"></script> <script src="https://aframe.io/releases/1.4.0/aframe.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/aframe-blink-controls/dist/aframe-blink-controls.min.js"></script>
<script src="./../../../dist/xrfragment.aframe.js"></script> <script src="./../../../dist/xrfragment.aframe.js"></script>
</head> </head>
<body> <body>
<div id="overlay" x-data="{ urls: ['#pos=0,4,15&rot=0,360,0'] }"> <div id="overlay" x-data="{ urls: ['#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 asset"></input>
<input type="text" id="uri" list="urls" value="#pos=0,4,15&rot=0,360,0" x-on:change="document.location.hash = $('#uri').value"/> <input type="text" id="uri" list="urls" value="#pos=0,1.6,15&rot=0,360,0" x-on:change="document.location.hash = $('#uri').value"/>
<datalist id="urls" > <datalist id="urls" >
<template x-for="url in urls"> <template x-for="url in urls">
<option x-bind:value="url" selected></option> <option x-bind:value="url" selected></option>
@ -26,10 +27,15 @@
<a id="model" target="_blank" href="">⬇️ model</a> <a id="model" target="_blank" href="">⬇️ model</a>
<textarea style="display:none"></textarea> <textarea style="display:none"></textarea>
<a-scene> <a-scene>
<a-entity xrf gltf-model="./../../assets/example3.gltf"/> <a-entity id="model" xrf gltf-model="./../../assets/example3.gltf" />
<a-entity xrf position="0 4 15"> <a-entity id="floor" gltf-to-entity="from: #model; name: floor" />
<a-entity camera look-controls wasd-controls></a-entity>
<a-entity xrf id="player">
<a-entity camera position="0 1.6 15" look-controls wasd-controls></a-entity>
<a-entity id="left-hand" oculus-touch-controls="hand: left" blink-controls="cameraRig:#player; teleportOrigin: #camera; collisionEntities: #floor"></a-entity>
<a-entity id="right-hand" oculus-touch-controls="hand: right" blink-controls="cameraRig:#player; teleportOrigin: #camera; collisionEntities: #floor"></a-entity>
</a-entity> </a-entity>
</a-scene> </a-scene>
<script type="module"> <script type="module">

File diff suppressed because one or more lines are too long

View file

@ -9,10 +9,10 @@
<link type="text/css" rel="stylesheet" href="./../../assets/style.css"/> <link type="text/css" rel="stylesheet" href="./../../assets/style.css"/>
</head> </head>
<body> <body>
<div id="overlay" x-data="{ urls: ['#pos=0,4,15','#pos=0,4,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 asset"></input>
<input type="text" id="uri" list="urls" value="#pos=0,4,15&rot=0,360,0" x-on:change="document.location.hash = $('#uri').value"/> <input type="text" id="uri" list="urls" value="#pos=0,1.6,15&rot=0,360,0" x-on:change="document.location.hash = $('#uri').value"/>
<datalist id="urls" > <datalist id="urls" >
<template x-for="url in urls"> <template x-for="url in urls">
<option x-bind:value="url" selected></option> <option x-bind:value="url" selected></option>
@ -268,8 +268,6 @@
//torus.rotation.x = time * 0.4; //torus.rotation.x = time * 0.4;
//torus.rotation.y = time; //torus.rotation.y = time;
if( XRF.getLastModel() ) XRF.getLastModel().render(scene,camera)
//controls.update() //controls.update()
renderer.render( scene, camera ); renderer.render( scene, camera );
stats.update(); stats.update();

View file

@ -40,3 +40,36 @@ window.AFRAME.registerComponent('xrf', {
} }
}); });
AFRAME.registerComponent('gltf-to-entity', {
schema: {
from: {default: '', type: 'selector'},
name: {default: ''},
duplicate: {type:'boolean'}
},
init: function () {
var el = this.el;
var data = this.data;
data.from.addEventListener('model-loaded', evt => {
var model;
var subset;
model = evt.detail.model;
console.dir(this.data.from)
subset = model.getObjectByName(data.name);
if (!subset){
console.error("Sub-object", data.name, "not found in #"+data.from.id);
return;
}
if( !this.data.duplicate ) subset.parent.remove(subset)
let clone = subset.clone()
////subset.updateMatrixWorld();
el.object3D.position.setFromMatrixPosition(data.from.object3D.matrixWorld);
el.object3D.quaternion.setFromRotationMatrix(data.from.object3D.matrixWorld);
el.setObject3D('mesh', clone );
el.emit('model-loaded', el.getObject3D('mesh'));
});
}
});

View file

@ -10,9 +10,18 @@ xrfragment.init = function(opts){
for ( let i in xrfragment.XRF ) xrfragment.XRF[i] // shortcuts to constants (NAVIGATOR e.g.) for ( let i in xrfragment.XRF ) xrfragment.XRF[i] // shortcuts to constants (NAVIGATOR e.g.)
xrfragment.Parser.debug = xrfragment.debug xrfragment.Parser.debug = xrfragment.debug
if( opts.loaders ) opts.loaders.map( xrfragment.patchLoader ) if( opts.loaders ) opts.loaders.map( xrfragment.patchLoader )
xrfragment.patchRenderer(opts.renderer)
return xrfragment return xrfragment
} }
xrfragment.patchRenderer = function(renderer){
renderer.render = ((render) => function(scene,camera){
if( xrfragment.getLastModel() && xrfragment.getLastModel().render )
xrfragment.getLastModel().render(scene,camera)
render(scene,camera)
})(renderer.render.bind(renderer))
}
xrfragment.patchLoader = function(loader){ xrfragment.patchLoader = function(loader){
loader.prototype.load = ((load) => function(url, onLoad, onProgress, onError){ loader.prototype.load = ((load) => function(url, onLoad, onProgress, onError){
load.call( this, load.call( this,

View file

@ -1,57 +1,50 @@
xrfragment.xrf.href = function(v, opts){ xrfragment.xrf.href = function(v, opts){
let { mesh, model, camera, scene, renderer, THREE} = opts let { mesh, model, camera, scene, renderer, THREE} = opts
return
// Create a shader material that treats the texture as an equirectangular map let size = 5
mesh.texture = mesh.material.map // backup texture let texture = mesh.material.map
const equirectShader = THREE.ShaderLib[ 'equirect' ];
const equirectMaterial = new THREE.ShaderMaterial( {
uniforms: THREE.UniformsUtils.merge([
THREE.UniformsLib.equirect,
equirectShader.uniforms,
]),
vertexShader: equirectShader.vertexShader,
fragmentShader: equirectShader.fragmentShader,
side: THREE.DoubleSide //THREE.FrontSide //THREE.DoubleSide //THREE.BackSide
} );
equirectMaterial.uniforms[ 'tEquirect' ].value = mesh.texture
// Define the tEquirectInvProjection uniform
equirectMaterial.uniforms.tEquirectInvProjection = {
value: new THREE.Matrix4(),
};
// Assign the new material to the mesh
mesh.material = equirectMaterial;
console.dir(mesh.material)
mesh.texture.wrapS = THREE.RepeatWrapping;
// patch custom model renderloop /*
model.render = ((render) => (scene,camera) => { texture.wrapS = texture.wrapT = THREE.ClampToEdgeWrapping;
mesh.material = new THREE.MeshStandardMaterial( {
envMap: texture,
roughness: 0.0,
metalness: 1,
side: THREE.DoubleSide,
})
*/
// Store the original projection matrix of the camera mesh.material = new THREE.ShaderMaterial( {
const originalProjectionMatrix = camera.projectionMatrix.clone(); side: THREE.DoubleSide,
// Calculate the current camera view matrix uniforms: {
const aspectRatio = mesh.texture.image.width / mesh.texture.image.height; pano: { value: texture }
camera.projectionMatrix.makePerspective(camera.fov, aspectRatio, camera.near, camera.far); },
vertexShader: `
const viewMatrix = camera.matrixWorldInverse; vec3 portalPosition;
const worldMatrix = mesh.matrixWorld; varying vec3 vWorldPosition;
varying float vDistanceToCenter;
const equirectInvProjection = new THREE.Matrix4(); varying float vDistance;
equirectInvProjection.copy(camera.projectionMatrix).multiply(viewMatrix).invert(); void main() {
vDistanceToCenter = clamp(length(position - vec3(0.0, 0.0, 0.0)), 0.0, 1.0);
// Update the equirectangular material's tEquirect uniform portalPosition = (modelMatrix * vec4(0.0, 0.0, 0.0, 1.0)).xyz;
equirectMaterial.uniforms.tEquirect.value = mesh.texture; vDistance = length(portalPosition - cameraPosition);
equirectMaterial.uniforms.tEquirectInvProjection.value.copy( vWorldPosition = (modelMatrix * vec4(position, 1.0)).xyz;
equirectInvProjection gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
); }
`,
// Reset the camera projection matrix fragmentShader: `
camera.projectionMatrix.copy(originalProjectionMatrix); #define RECIPROCAL_PI2 0.15915494
uniform sampler2D pano;
varying float vDistanceToCenter;
render(scene,camera) varying float vDistance;
varying vec3 vWorldPosition;
})(model.render) void main() {
vec3 direction = normalize(vWorldPosition - cameraPosition);
console.dir(mesh) vec2 sampleUV;
sampleUV.y = -clamp(direction.y * 0.5 + 0.5, 0.0, 1.0);
sampleUV.x = atan(direction.z, -direction.x) * -RECIPROCAL_PI2 + 0.5;
gl_FragColor = texture2D(pano, sampleUV);
}
`
});
} }