<div class="world"></div>
<div id="credits">
<p> <a href="https://codepen.io/Yakudoo/" target="blank">my other codepens</a> | <a href="https://www.epic.net" target="blank">epic.net</a></p>
</div>
<script type="x-shader/x-fragment" id="fragmentShader">
precision highp float;
varying vec2 vUv;
uniform sampler2D textureImage;
uniform sampler2D textureDepth;
uniform sampler2D textureNormal;
uniform sampler2D textureNoise;
uniform vec2 mousePosition;
uniform float time;
float PI = 3.141592;
void main () {
vec4 texDepth = texture2D(textureDepth, vUv);
vec4 texNoise = texture2D(textureNoise, vUv + time*.05);
vec4 texNoise2 = texture2D(textureNoise, vUv*.1 + time*.1);
float depthVal = texDepth.r - .7;
float noiseVal = texNoise.r - .5;
float noiseVal2 = texNoise2.r - .5;
float distToCenter = pow( distance(vUv, vec2(.5,.5)), 4.0 );
float distToMouse = 1.0 - smoothstep(0.0, 0.25, distance(mousePosition + vec2(.5, .5), vUv));
vec2 dispDepth = vUv + mousePosition * depthVal * .1;
vec2 dispWaves = vec2(noiseVal * distToCenter);
vec2 dispMouse = vec2(noiseVal2 * .10 * distToMouse);
vec4 texImage = texture2D(textureImage, dispDepth + dispWaves + dispMouse );
vec4 texNormal = texture2D(textureNormal, dispDepth + dispWaves + dispMouse);
// PARTICLES
vec4 particles = texture2D(textureNoise, dispWaves + vec2( vUv.x - sin(time * .5), vUv.y - sin(time) ));
float thr1 = .05 + sin(time*4.0)*.05;
texImage.rgb *= smoothstep(thr1,thr1+.03, particles.r);
// FOG RED
vec4 displacedDepth = texture2D(textureDepth, dispDepth + dispWaves + dispMouse );
vec4 smokeNoise1 = texture2D(textureNoise, dispDepth - vec2(time * .3));
texImage.r *= 1. + (displacedDepth.b * (40.0 + smokeNoise1.r ) * pow(1.0 - vUv.y, 6.0) * (1.0 + sin(time*1.0)) *.1 ) ;
// FOG BLUE
vec4 smokeNoise2 = texture2D(textureNoise, dispDepth - vec2(time * .1, time * .5) );
texImage.b *= 1. + (displacedDepth.g * (6.0 + sin(time * 5.0) ) * (.5 + smokeNoise2.r * ( 1.0 + sin(time) * .5 ) ) * vUv.y) ;
// LIGHTENING
float lighteningValue = texture2D(textureNoise, vec2(time*.1)).r;
lighteningValue = 1. - smoothstep(.6,.65, lighteningValue) * .3;
texImage.rg *= lighteningValue;
// MOUSE LIGHT
vec3 lightDirection = normalize(vec3(mousePosition.x, mousePosition.y, .3));
vec3 pixDirection = normalize(vec3(texNormal.r * 2.0 - 1.0, texNormal.b * 2.0 - 1.0, -texNormal.g * 2.0 + 1.0));
float lightVal = dot(pixDirection, lightDirection);
texImage.rgb *= .9 + ( distToMouse * lightVal * (1.0 - displacedDepth.g)) * (2.0 + sin(time)*.5);
gl_FragColor = vec4(texImage);
}
</script>
<script type="x-shader/x-vertex" id="vertexShader">
attribute vec3 position;
attribute vec2 uv;
uniform mat4 projectionMatrix;
uniform mat4 modelViewMatrix;
uniform mat3 normalMatrix;
varying vec2 vUv;
void main() {
vUv = uv;
gl_Position = projectionMatrix * modelViewMatrix * vec4 ( position, 1.0);
}
</script>
@import url('https://fonts.googleapis.com/css?family=Voltaire');
body{
overflow: hidden;
user-select: none;
cursor: default;
}
canvas {
display: block;
}
.world{
position: absolute;
width:100%;
height:100%;
background: #000;
}
#credits{
position:absolute;
width:100%;
margin: auto;
bottom:0;
margin-bottom:20px;
font-family:"Voltaire", sans-serif;
color:#d45e59;
font-size:1.0em;
text-transform: uppercase;
text-align : center;
}
#credits a {
color:#b92721;
text-decoration: none;
}
View Compiled
class World {
constructor(width, height) {
this.renderer = new THREE.WebGLRenderer({
alpha: true,
antialias: true
});
this.renderer.setPixelRatio(window.devicePixelRatio);
this.renderer.setSize(width, height);
this.container = document.getElementsByClassName("world")[0];
this.scene = new THREE.Scene();
this.width = width;
this.height = height;
this.aspectRatio = width / height;
this.fieldOfView = 50;
this.nLoadedImages = 0;
this.targetX = 0;
this.targetY = 0;
var nearPlane = .1;
var farPlane = 20000;
this.camera = new THREE.PerspectiveCamera(this.fieldOfView, this.aspectRatio, nearPlane, farPlane);
this.camera.position.z = 260;
this.container.appendChild(this.renderer.domElement);
this.timer = 0;
this.loadTextures();
}
loadTextures() {
const loader = new THREE.TextureLoader();
loader.crossOrigin = '';
this.textureImage = loader.load('https://s3-us-west-2.amazonaws.com/s.cdpn.io/264161/halloween.jpg', this.imageLoaded.bind(this));
this.textureImage.minFilter = THREE.LinearFilter;
this.textureDepth = loader.load('https://s3-us-west-2.amazonaws.com/s.cdpn.io/264161/halloween-depth.jpg', this.imageLoaded.bind(this));
this.textureDepth.magFilter = this.textureDepth.minFilter = THREE.LinearFilter;
this.textureNormal = loader.load('https://s3-us-west-2.amazonaws.com/s.cdpn.io/264161/halloween-normal.jpg', this.imageLoaded.bind(this));
this.textureNormal.magFilter = this.textureNormal.minFilter = THREE.LinearFilter;
this.textureNoise = loader.load('https://s3-us-west-2.amazonaws.com/s.cdpn.io/264161/noiseTexture.jpg', this.imageLoaded.bind(this));
this.textureNoise.magFilter = this.textureDepth.minFilter = THREE.LinearFilter;
this.textureNoise.wrapT = this.textureNoise.wrapS = THREE.RepeatWrapping;
}
imageLoaded(){
this.nLoadedImages++;
if ( this.nLoadedImages > 3 ) {
this.createPlane();
this.loop();
}
}
createPlane(){
this.material = new THREE.RawShaderMaterial({
vertexShader: document.getElementById( 'vertexShader' ).textContent,
fragmentShader: document.getElementById('fragmentShader').textContent,
uniforms: {
time: { type: 'f', value: 5 },
textureImage: { type: 't', value: this.textureImage },
textureDepth: { type: 't', value: this.textureDepth },
textureNormal: { type: 't', value: this.textureNormal },
textureNoise: { type: 't', value: this.textureNoise },
mousePosition: {type: 'v2', value: new THREE.Vector2( 0.5, 0.5 ) }
}
});
this.shapeGeometry = new THREE.PlaneGeometry(200, 200, 256, 256);
this.shape = new THREE.Mesh(this.shapeGeometry, this.material);
this.scene.add(this.shape);
}
render() {
this.timer+=.01;
this.shape.material.uniforms.time.value = this.timer;
this.targetX += (mousePos.px - this.targetX) * .07;
this.targetY += (mousePos.py - this.targetY) * .07;
this.shape.material.uniforms.mousePosition.value = new THREE.Vector2(this.targetX, -this.targetY);
this.renderer.render(this.scene, this.camera);
}
loop() {
this.render();
requestAnimationFrame(this.loop.bind(this));
}
updateSize(w, h) {
this.renderer.setSize(w, h);
this.camera.aspect = w / h;
this.camera.updateProjectionMatrix();
}
mouseMove(mousePos) {
}
};
document.addEventListener("DOMContentLoaded", domIsReady);
let mousePos = {x:0, y:0, px:0, py:0};
let PI = Math.PI;
let world;
function domIsReady() {
world = new World(this.container, this.renderer, window.innerWidth, window.innerHeight);
window.addEventListener('resize', handleWindowResize, false);
document.addEventListener("mousemove", handleMouseMove, false);
document.addEventListener("touchmove", handleMouseMove, false);
handleWindowResize();
}
function handleWindowResize() {
world.updateSize(window.innerWidth, window.innerHeight);
}
function handleMouseMove(e) {
if ((e.clientX)&&(e.clientY)) {
mousePos.x = e.clientX;
mousePos.y = e.clientY;
mousePos.px = mousePos.x / window.innerWidth * 2 - 1;
mousePos.py = mousePos.y / window.innerHeight * 2 - 1;
}else if (e.targetTouches) {
mousePos.x = e.targetTouches[0].clientX;
mousePos.y = e.targetTouches[0].clientY;
mousePos.px = mousePos.x / window.innerWidth * 2 - 1;
mousePos.py = mousePos.y / window.innerHeight * 2 - 1;
mousePos.px *= 1.5;
mousePos.py *= 1.5;
e.preventDefault();
}
world.mouseMove(mousePos);
}
This Pen doesn't use any external CSS resources.