Skip to content

Instantly share code, notes, and snippets.

@ofedo
Created November 8, 2020 21:56
Show Gist options
  • Save ofedo/c8c971de706ea140e10790b503c9b4d0 to your computer and use it in GitHub Desktop.
Save ofedo/c8c971de706ea140e10790b503c9b4d0 to your computer and use it in GitHub Desktop.
A-FRAME AR-refraction-shader
// works with
<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>
// based on
// https://github.com/stemkoski/AR-Examples/blob/master/refraction.html
// https://stemkoski.github.io/AR-Examples/refraction.html
<script>
AFRAME.registerComponent('refraction-shader', {
init: function() {
window.addEventListener('arjs-video-loaded', (e) => this.doShaderMaterial(e));
},
doShaderMaterial: function(e) {
const vertexShader = `
uniform float refractionRatio;
varying vec3 vRefract;
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 fragmentShader = `
uniform sampler2D texture;
varying vec3 vRefract;
uniform float distance;
uniform float opacity;
uniform vec3 tint;
void main()
{
vec2 p = vec2( vRefract.x * distance + 0.5, vRefract.y * distance + 0.5 );
p = vec2(1.0, 1.0) - p;
vec3 color = texture2D( texture, p ).rgb;
gl_FragColor = vec4( color, opacity ) * vec4( tint, 1.0 );
}
`
var videoTexture = new THREE.VideoTexture(e.detail.component);
videoTexture.minFilter = THREE.LinearFilter;
this.material = new THREE.ShaderMaterial({
uniforms: {
texture: {
value: videoTexture
},
refractionRatio: {
value: 0.75
},
distance: {
value: 1.0
},
opacity: {
value: 0.8
},
tint: {
value: new THREE.Vector3(0.8, 0.8, 1.0)
}
},
vertexShader: vertexShader,
fragmentShader: fragmentShader,
transparent: true
});
this.setToMesh();
this.el.addEventListener('model-loaded', () => this.setToMesh());
},
setToMesh: function() {
const mesh = this.el.getObject3D('mesh');
if (mesh) {
mesh.material = this.material;
mesh.traverse((node) => {
if (node.isMesh) {
node.material = mesh.material;
}
});
}
}
});
</script>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment