Skip to content

Instantly share code, notes, and snippets.

@Efetivos
Last active February 24, 2021 05:31
Show Gist options
  • Select an option

  • Save Efetivos/46abca8a702545aade334f33e93dac0c to your computer and use it in GitHub Desktop.

Select an option

Save Efetivos/46abca8a702545aade334f33e93dac0c to your computer and use it in GitHub Desktop.
DDD Transition
<!DOCTYPE html>
<html lang="en" >
<head>
<meta charset="UTF-8">
<title>[DDD] WebGL Transiton</title>
<link rel="stylesheet" href="./style.css">
</head>
<body>
<!-- partial:index.partial.html -->
<button class="play">PLAY</button>
<script type="x-shader/x-vertex" id="vertex">
attribute vec3 position;
attribute vec3 normal;
attribute vec2 uv;
uniform mat4 modelViewMatrix;
uniform mat4 projectionMatrix;
uniform mat3 normalMatrix;
varying vec3 vNormal;
varying vec2 vUv;
void main() {
vNormal = normalize(normalMatrix * normal);
vUv = uv;
gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
}
</script>
<script type="x-shader/x-fragment" id="fragment">
precision highp float;
// 2D Random
float random (in vec2 st) { return fract(sin(dot(st.xy, vec2(12.9898,78.233))) * 43758.5453123); }
// 2D Noise based on Morgan McGuire @morgan3d
// https://www.shadertoy.com/view/4dS3Wd
float noise (in vec2 st) {
vec2 i = floor(st);
vec2 f = fract(st);
// Four corners in 2D of a tile
float a = random(i);
float b = random(i + vec2(1.0, 0.0));
float c = random(i + vec2(0.0, 1.0));
float d = random(i + vec2(1.0, 1.0));
// Smooth Interpolation
// Cubic Hermine Curve. Same as SmoothStep()
vec2 u = f*f*(3.0-2.0*f);
// u = smoothstep(0.,1.,f);
// Mix 4 coorners percentages
return mix(a, b, u.x) + (c - a)* u.y * (1.0 - u.x) + (d - b) * u.x * u.y;
}
// Comes from the Pixel Spirit Deck by Patricio Gonzalez Vivo
float stroke(float x, float s, float w) {
float d = step(s, x + w * .5) - step(s, x - w * .5);
return clamp(d, 0., 1.);
}
// https://github.com/msfeldstein/glsl-map/blob/master/index.glsl#L1
float map(float value, float inMin, float inMax, float outMin, float outMax) {
return outMin + (outMax - outMin) * (value - inMin) / (inMax - inMin);
}
uniform float uProgress;
uniform float uNoiseAmp;
uniform float uNoiseFreq;
uniform sampler2D uTexture;
varying vec2 vUv;
varying vec2 v_texCoords;
uniform sampler2D u_texture;
void main() {
vec3 color1 = vec3(1, 1, 1);
vec3 color2 = vec3(1, 0.5, 0.5);
//vec3 color2;
float noisyX = vUv.x + noise(vUv * vec2(uNoiseFreq)) * uNoiseAmp;
// Now that we added noise, we want to remap progress to take into account the noise amplitude
// to ensure that our transition runs all the way through
float progress = map(uProgress, 0., 1., 0. - uNoiseAmp, 1. + uNoiseAmp);
// https://thebookofshaders.com/glossary/?search=step
// Basically, returns 0 if progress > vUv.x, returns 1 otherwise.
float weight = step(noisyX, progress);
// https://thebookofshaders.com/glossary/?search=mix
// The mix method will perform a linear interpolation between color1 and color2, based on the weight parameter.
// In this specific case, since we're using step to compute the weight value (and step only returns 0 or 1), it will either be fully color1 or fully color2.
vec3 tex = texture2D(uTexture, vUv).rgb;
vec3 color = mix(color1, tex, weight);
gl_FragColor = vec4(color, 1.);
}
</script>
<!-- partial -->
<script src='https://unpkg.co/gsap@3/dist/gsap.min.js'></script>
<script src='https://cdnjs.cloudflare.com/ajax/libs/jquery/3.5.1/jquery.min.js'></script><script type="module" src="./script.js"></script>
</body>
</html>
//Using OGL (very light WebGL Lib
// https://oframe.github.io/ogl/
import {
Renderer,
Program,
Mesh,
Camera,
Transform,
Plane,
TextureLoader,
Texture,
} from "https://cdn.skypack.dev/ogl@0.0.65";
import Tweakpane from "https://cdn.skypack.dev/tweakpane@1.5.9";
const PARAMS = {
//progress: 0.5,
progress: 0,
noiseAmp: 1.5,
//noiseFreq: 1,
noiseFreq: .956,
}
const vertex = document.getElementById("vertex").textContent;
const fragment = document.getElementById("fragment").textContent;
// Classic OGL setup, nothing fancy here...
// This is not related to the transition logic
const renderer = new Renderer({
alpha: true,
antialias: true,
});
const gl = renderer.gl;
document.body.appendChild(gl.canvas);
const camera = new Camera(gl, { fov: 35 });
camera.position.set(0, 0, 10);
const scene = new Transform();
const texture = new Texture(gl);
// update image value with source once loaded
const img = new Image();
img.crossOrigin = "anonymous";
img.src = 'https://raw.githubusercontent.com/Efetivos/gallery/master/houses/house2.jpg';
img.onload = () => (texture.image = img);
const program = new Program(gl, {
alpha: true,
vertex,
fragment,
uniforms: {
uProgress: { value: PARAMS.progress },
uNoiseAmp: { value: PARAMS.noiseAmp },
uNoiseFreq: { value: PARAMS.noiseFreq },
uTexture: { value: texture }
},
});
console.log(program)
// Here we're computing the dimensions of the viewport in OGL units.
// We do so in order to create a plane covers exactly the size of the screen.
let aspect = window.innerWidth / window.innerHeight;
let vFov = (camera.fov * Math.PI) / 180;
let height = 2 * Math.tan(vFov / 2) * camera.position.z;
let width = height * aspect;
let geometry = new Plane(gl, { width, height });
let plane = new Mesh(gl, {
geometry,
program,
});
plane.position.set(0, 0, 0);
plane.setParent(scene);
renderer.setSize(window.innerWidth, window.innerHeight);
camera.perspective({
aspect: gl.canvas.width / gl.canvas.height,
});
//
// onClick
//____________________________
let animating = false
document.querySelector('.play').addEventListener("click", function() {
let time = 3
if(!animating) {
let puuv = program.uniforms.uNoiseAmp.value
animating = true
gsap.fromTo(program.uniforms.uNoiseAmp, { value: 1.5 }, {delay: time * 0.5, value: 0, duration: time * 0.5 , ease: 'expo.out'})
gsap.fromTo(program.uniforms.uProgress, { value: .374 }, { value: 1, duration: time , ease: 'expo.inOut', onUpdate: ()=>{
renderer.render({ scene, camera })
}, onComplete: ()=> { animating = false } })
}
}, false)
//
// resize
//____________________________
window.addEventListener("resize", onResize, false)
function onResize() {
aspect = window.innerWidth / window.innerHeight;
renderer.setSize(window.innerWidth, window.innerHeight);
camera.perspective({
aspect: gl.canvas.width / gl.canvas.height,
});
}
//
// Control GUI
//____________________________
const gui = new Tweakpane();
gui.addInput(PARAMS, 'progress', {
label: 'Progress',
min: 0,
max: 1,
step: 0.001,
})
.on("change", (value) => {
program.uniforms.uProgress.value = value;
renderer.render({ scene, camera });
});
gui.addInput(PARAMS, 'noiseAmp', {
label: 'Noise amplitude',
min: 0,
max: 1.5,
step: 0.0001,
})
.on("change", (value) => {
program.uniforms.uNoiseAmp.value = value;
renderer.render({ scene, camera });
});
gui.addInput(PARAMS, 'noiseFreq', {
label: 'Noise frequency',
min: 0,
max: 5,
step: 0.001,
})
.on("change", (value) => {
program.uniforms.uNoiseFreq.value = value;
renderer.render({ scene, camera });
});
renderer.render({ scene, camera });
//
// rAF
//____________________________
function update() {
requestAnimationFrame(update);
renderer.render({ scene, camera })
}
//requestAnimationFrame(update)
body {
font-family: 'Cardo', serif;
background: #fff;
}
canvas {
position: fixed;
top: 0;
left: 0;
}
.play {
position: absolute;
z-index: 1;
left: 2vw;
bottom: 2vw;
padding: 10px 15px;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment