karagaki
4/29/2020 - 4:35 PM

Displacement Scroll

Displacement Scroll

<script id="vertexShader" type="x-shader/x-vertex">
			precision mediump float;
			precision mediump int;
			attribute vec4 color;
			varying vec3 vPosition;
			varying vec4 vColor;
      varying vec2 vUv;
			void main()	{
        vUv = uv;
				vPosition = position;
				vColor = color;
				gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1);
			}
</script>
<script id="fragmentShader" type="x-shader/x-vertex">
			precision mediump float;
			precision mediump int;
      uniform float time;
			uniform float blend;
			varying vec3 vPosition;
			varying vec4 vColor;
  
      uniform sampler2D tex1;
      uniform sampler2D tex2;
      varying vec2 vUv;
  
      float length = 10.;
  
      mat2 scale(vec2 _scale){
        return mat2(_scale.x,0.0,
                    0.0,_scale.y);
      }
  
      mat3 k = mat3(
               -0.3, 0., 1.,
               -0.4, 0., 1.,
              2., 0., 1.
              );

			float displaceAmount = 0.3;
  
			void main()	{
				// invert blend;
        float blend2 = 1.-blend;
				vec4 image1 = texture2D(tex1, vUv);
        vec4 image2 = texture2D(tex2, vUv);
      
        float t1 = ((image2.r*displaceAmount)*blend)*2.;
        float t2 = ((image1.r*displaceAmount)*blend2)*2.;
        
        vec4 imageA = texture2D(tex2, vec2(vUv.x, vUv.y-t1))*blend2;
        vec4 imageB = texture2D(tex1, vec2(vUv.x, vUv.y+t2))*blend;
        
				gl_FragColor = imageA.bbra * blend + imageA * blend2 +
				imageB.bbra * blend2 + imageB * blend;

				//gl_FragColor = image3;
				
			}
</script>

<div id="loading" class="loading"></div>
// ARTWORK BY THOMAS DENMARK
// https://www.artstation.com/thomden
//
// I had used it in this codepen just for testing purposes.

const MOUSE_WHEEL_EVENT = "wheel";
const TOUCH_MOVE = "touchmove";
const TOUCH_END = "touchend";
const MOUSE_DOWN = "mousedown";
const MOUSE_UP = "mouseup";
const MOUSE_MOVE = "mousemove";
class ScrollPos {
	constructor() {
		this.acceleration = 0;
		this.maxAcceleration = 5;
		this.maxSpeed = 20;
		this.velocity = 0;
		this.dampen = 0.97;
		this.speed = 8;
		this.touchSpeed = 8;
		this.scrollPos = 0;
		this.velocityThreshold = 1;
		this.snapToTarget = false;
		this.mouseDown = false;
		this.lastDelta = 0;
		
		document.addEventListener(
			"touchstart",
			function(event) {
				event.preventDefault();
			},
			{ passive: false }
		);
		
		window.addEventListener(MOUSE_WHEEL_EVENT, event => {
			event.preventDefault();
			this.accelerate(Math.sign(event.deltaY) * this.speed);
		});
		
		window.addEventListener(TOUCH_MOVE, event => {
			//event.preventDefault();
			let delta = this.lastDelta-event.targetTouches[0].clientY;
			this.accelerate(Math.sign(delta) * this.touchSpeed);
			this.lastDelta = event.targetTouches[0].clientY;
		})
		
		window.addEventListener(TOUCH_END, event =>{
			this.lastDelta = 0;
		})
		
		window.addEventListener(MOUSE_DOWN, event=>{
			this.mouseDown = true;
		})
		
		window.addEventListener(MOUSE_MOVE, event=>{
			if(this.mouseDown){
				let delta = this.lastDelta-event.clientY;
				this.accelerate(Math.sign(delta) * this.touchSpeed*0.4);
				this.lastDelta = event.clientY;
			}
		})
		
		window.addEventListener(MOUSE_UP, event=>{
			this.lastDelta = 0;
			this.mouseDown = false;
		})

	}
	accelerate(amount) {
		if (this.acceleration < this.maxAcceleration) {
			this.acceleration += amount;
		}
	}
	update() {
		this.velocity += this.acceleration;
		if (Math.abs(this.velocity) > this.velocityThreshold) {
			this.velocity *= this.dampen;
			this.scrollPos += this.velocity;
		} else {
			this.velocity = 0;
		}
		if (Math.abs(this.velocity) > this.maxSpeed) {
			this.velocity = Math.sign(this.velocity) * this.maxSpeed;
		}
		this.acceleration = 0;
	}
	snap (snapTarget, dampenThreshold = 100, velocityThresholdOffset = 1.5) {
		if(Math.abs(snapTarget - this.scrollPos) < dampenThreshold) {
			this.velocity *= this.dampen;
		}
		if (Math.abs(this.velocity) < this.velocityThreshold+velocityThresholdOffset) {
			this.scrollPos += (snapTarget - this.scrollPos) * 0.1;
		}
	}
	project(steps = 1) {
		if(steps === 1)	return this.scrollPos + this.velocity * this.dampen
		var scrollPos = this.scrollPos;
		var velocity = this.velocity;

		for(var i = 0; i < steps; i++) {
				velocity *= this.dampen;
				scrollPos += velocity;
		}
		return scrollPos;
	}
}

var mouseWheel = new ScrollPos();
const scrollPerImage = 500;

const KEYBOARD_ACCELERATION = 25;

window.addEventListener("keydown", (e)=>{
	switch(e.keyCode) {
		case 33:
		case 38:
			// UP
			mouseWheel.acceleration -= KEYBOARD_ACCELERATION;
			mouseWheel.update()
			break;
		case 34:
		case 40:
			// DOWN
			mouseWheel.acceleration += KEYBOARD_ACCELERATION;
			mouseWheel.update()
			break;
	}
})


const folder = "Ragnar";
const root = `https://mwmwmw.github.io/files/${folder}`;
const files = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
const ext = "jpg";
const IMAGE_SIZE = 512;

let imageContainer = document.getElementById("images");
let canvas = document.createElement("canvas");
		canvas.width = IMAGE_SIZE;
		canvas.height = IMAGE_SIZE;
let ctx = canvas.getContext("2d");

function resizeImage(image, size = IMAGE_SIZE) {
	let newImage = image;
	let {width, height} = image;
	let newWidth = size/width;
	let newHeight = size/height;
	
	ctx.drawImage(image, 0, 0, width, height, 0,0, size, size); 
	
	return ctx.getImageData(0,0,size,size);
}

function makeThreeTexture(image) {
	let tex = new THREE.Texture(image);
					tex.needsUpdate = true;
	return tex
}

function loadImages() {
	let promises = [];
	for (var i = 0; i < files.length; i++) {
		promises.push(
			new Promise((resolve, reject) => {
				let img = document.createElement("img");
				img.crossOrigin = "anonymous";
				img.src = `${root}/${files[i]}.${ext}`;
				img.onload = image => {
					return resolve(image.target);
				};
			}).then(resizeImage)
				.then(makeThreeTexture)
		);
	}
	return Promise.all(promises);
}

loadImages().then((images) => {
	document.getElementById("loading").style = "display: none;";
	init(images);
});

const renderer = new THREE.WebGLRenderer({ antialias: false });
document.body.appendChild(renderer.domElement);
 
function init(textures) {
	let scene = new THREE.Scene();
	let camera = new THREE.PerspectiveCamera(
		45,
		window.innerWidth / window.innerHeight,
		0.1,
		2000
	);
	camera.position.set(0, 0, 10);

	scene.add(camera);

	let geometry = new THREE.PlaneGeometry(4.75, 7, 4, 4);

	let material = new THREE.ShaderMaterial({
		uniforms: {
			time: { value: 1.0 },
			blend: { value: 0.0 },
			tex1: { type: "t", value: textures[1] },
			tex2: { type: "t", value: textures[0] }
		},
		vertexShader: document.getElementById("vertexShader").textContent,
		fragmentShader: document.getElementById("fragmentShader").textContent,
	});

	let mesh = new THREE.Mesh(geometry, material);

	scene.add(mesh);

	var tex1 = textures[1];
	var tex2 = textures[0];
	
	function updateTexture(pos) {
		if(tex2 != textures[Math.floor(pos / scrollPerImage)]) {
			tex2 = textures[Math.floor(pos / scrollPerImage)]
			material.uniforms.tex2.value = tex2;
		}
		if(tex1 != textures[Math.floor(pos / scrollPerImage) + 1]) {
			tex1 = textures[Math.floor(pos / scrollPerImage) + 1]
			material.uniforms.tex1.value = tex1;
		}
	}
	
	
	
	function draw() {
		requestAnimationFrame(draw);
		mouseWheel.update();
		let scrollTarget = (Math.floor((mouseWheel.scrollPos+scrollPerImage*0.5) / scrollPerImage)) * scrollPerImage;
		mouseWheel.snap(scrollTarget);
		
		let { scrollPos, velocity } = mouseWheel;
		
		if (scrollPos < 0) {
			scrollPos = 0;
		}
		if (scrollPos > scrollPerImage * textures.length - 1) {
			scrollPos = scrollPerImage * textures.length - 1;
		}
		
		if (scrollPos > 0 && scrollPos < scrollPerImage * textures.length - 1) {
			updateTexture(scrollPos);
			material.uniforms.blend.value =
				(scrollPos % scrollPerImage) / scrollPerImage;
		}
		
		mouseWheel.scrollPos = scrollPos;

		material.uniforms.time.value += 0.1;

		renderer.render(scene, camera);
	}

	function resize() {
		camera.aspect = window.innerWidth / window.innerHeight;
		camera.updateProjectionMatrix();
		renderer.setPixelRatio(window.devicePixelRatio);
		renderer.setSize(window.innerWidth, window.innerHeight);
	}

 	window.addEventListener("resize", resize);
	
 	resize();
	draw();
	
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/95/three.min.js"></script>
body {
  margin:0;
  overflow:hidden;
	background: black;
}

img {
  display:none;
}

.loading {
	margin: -50px -50px;
	border:0.2em dashed white;
	position:absolute;
	width: 100px;
	height: 100px;
	border-radius: 100px;
	animation: load 5s linear infinite;
}

@keyframes load {
	0% {
		transform: translateX(50vw) translateY(50vh) rotateZ(0deg);
	}
	100% {
		transform: translateX(50vw) translateY(50vh) rotateZ(360deg);
	}
}