Skip to content

Instantly share code, notes, and snippets.

@cwervo
Created August 1, 2017 00:02
Show Gist options
  • Save cwervo/b4cfdbc46fe056832d822871522ae3bb to your computer and use it in GitHub Desktop.
Save cwervo/b4cfdbc46fe056832d822871522ae3bb to your computer and use it in GitHub Desktop.
A little refraction shader made for A-Frame + AR.js
// 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;
}
})
@jeromeetienne
Copy link

Very nice! thanks for doing this :)

btw uniforms.time seems useless.

@skrichten
Copy link

How can I get this to work on an imported model? I tried using a .obj with no material, but that didn't work.

@skrichten
Copy link

skrichten commented Apr 5, 2018

applyToMesh: function () { const object = this.el.getObject3D('mesh'); if (object) { object.traverse((node) => { if (node.isMesh) { node.material = this.material; } }); } },

@Mizuki07
Copy link

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.

@tommensink
Copy link

@patowens86
Copy link

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.

@ofedo
Copy link

ofedo commented Nov 8, 2020

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

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment