-
-
Save cwervo/b4cfdbc46fe056832d822871522ae3bb to your computer and use it in GitHub Desktop.
// Note: requires https://rawgit.com/jeromeetienne/ar.js/master/aframe/build/aframe-ar.js | |
// or A-Frame.js + AR.js + THREEx + some other bindings, | |
// basically, just use Jerome Etienne's A-Frame AR lib ¯\_(ツ)_/¯ | |
// This is all based off Jerome Etienne's work, and he originally linked to | |
// these two sources, so I'll do the same here: | |
// http://http.developer.nvidia.com/CgTutorial/cg_tutorial_chapter07.html | |
// https://www.clicktorelease.com/code/streetViewReflectionMapping/#51.50700703827454,-0.12791916931155356 | |
AFRAME.registerComponent('refraction-shader', { | |
init: function () { | |
const data = this.data; | |
const vertexShader = `varying vec3 vRefract; | |
uniform float refractionRatio; | |
void main() { | |
vec4 mPosition = modelMatrix * vec4( position, 1.0 ); | |
vec3 nWorld = normalize( mat3( modelMatrix[0].xyz, modelMatrix[1].xyz, modelMatrix[2].xyz ) * normal ); | |
vRefract = normalize( refract( normalize( mPosition.xyz - cameraPosition ), nWorld, refractionRatio ) ); | |
gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 ); | |
}` | |
const fragShader = `uniform sampler2D texture; | |
varying vec3 vRefract; | |
// experiment with distance to the video plane. should do real ray-plane-intersection! | |
uniform float distance; | |
void main(void) { | |
vec2 p = vec2(vRefract.x*distance + 0.5, vRefract.y*distance + 0.5); | |
vec3 color = texture2D( texture, p ).rgb; | |
gl_FragColor = vec4( color, 1.0 ); | |
}` | |
var texture = new THREE.VideoTexture(this.el.sceneEl.systems.arjs.arToolkitSource.domElement) | |
texture.minFilter = THREE.NearestFilter | |
this.material = new THREE.ShaderMaterial({ | |
uniforms: { | |
time: { value: 0.0 }, | |
texture: { type: 't', value: texture }, | |
// pull to see the throshold: 0.7-ish solid glass/water ("upsidevdown"), 0.8+ thinner glass ("magnifying glass") | |
refractionRatio: { type: 'f', value: 0.9 }, | |
// experiment to adjust offset to video-plane. set to 1 for no effect | |
distance: { type: 'f', value: 1 } | |
}, | |
// Note, idk why exactly, but it appears that you NEED to explicitly | |
// name the vertexShader & fragmentShader arguments and not just as: | |
// vertexShader, | |
// fragShader | |
// | |
// Will expore this some other time ¯\_(ツ)_/¯ | |
vertexShader : vertexShader, | |
fragmentShader : fragShader | |
}); | |
this.material.uniforms.texture.value.wrapS = this.material.uniforms.texture.value.wrapT = THREE.ClampToEdgeWrapping; | |
this.applyToMesh(); | |
this.el.addEventListener('model-loaded', () => this.applyToMesh()); | |
}, | |
/** | |
* Apply the material to the current entity. | |
*/ | |
applyToMesh: function() { | |
const mesh = this.el.getObject3D('mesh'); | |
if (mesh) { | |
mesh.material = this.material; | |
} | |
}, | |
/** | |
* On each frame, update the 'time' uniform in the shaders. | |
*/ | |
tick: function (t) { | |
this.material.uniforms.time.value = t / 1000; | |
} | |
}) |
How can I get this to work on an imported model? I tried using a .obj with no material, but that didn't work.
applyToMesh: function () { const object = this.el.getObject3D('mesh'); if (object) { object.traverse((node) => { if (node.isMesh) { node.material = this.material; } }); } },
It would be grateful if you could give me a solutions about following issue or give a HTML sample that use this component and ar-aframe.js.
I get an error "TypeError: Cannot read property 'domElement' of undefined".
It seems "this.el.sceneEl.systems.arjs.arToolkitSource" is undefined.
Does anyone have an up-to-date version of this? I'm getting the same error as Mizuo07 and the link that @tommensink posted doesn't actually do any refraction for me.
Here it is working with latest
<script src="https://aframe.io/releases/1.0.4/aframe.min.js"></script>
<script src="https://raw.githack.com/AR-js-org/AR.js/master/aframe/build/aframe-ar.js"></script>
https://gist.github.com/ofedo/c8c971de706ea140e10790b503c9b4d0
Very nice! thanks for doing this :)
btw uniforms.time seems useless.