Skip to content

Instantly share code, notes, and snippets.

@valex
Created September 28, 2018 14:43
Show Gist options
  • Save valex/2324d10a6cf436ab4c96bc112a9b8770 to your computer and use it in GitHub Desktop.
Save valex/2324d10a6cf436ab4c96bc112a9b8770 to your computer and use it in GitHub Desktop.
BleachBypassShader + EdgeShader + FXAAShader + FocusShader
/**
* @author zz85 / https://github.com/zz85 | https://www.lab4games.net/zz85/blog
*
* Edge Detection Shader using Frei-Chen filter
* Based on http://rastergrid.com/blog/2011/01/frei-chen-edge-detector
*
* aspect: vec2 of (1/width, 1/height)
*/
THREE.EdgeShader = {
uniforms: {
"tDiffuse": { value: null },
"aspect": { value: new THREE.Vector2( 512, 512 ) }
},
vertexShader: [
"varying vec2 vUv;",
"void main() {",
"vUv = uv;",
"gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );",
"}"
].join( "\n" ),
fragmentShader: [
"uniform sampler2D tDiffuse;",
"varying vec2 vUv;",
"uniform vec2 aspect;",
"vec2 texel = vec2(1.0 / aspect.x, 1.0 / aspect.y);",
"mat3 G[9];",
// hard coded matrix values!!!! as suggested in https://github.com/neilmendoza/ofxPostProcessing/blob/master/src/EdgePass.cpp#L45
"const mat3 g0 = mat3( 0.3535533845424652, 0, -0.3535533845424652, 0.5, 0, -0.5, 0.3535533845424652, 0, -0.3535533845424652 );",
"const mat3 g1 = mat3( 0.3535533845424652, 0.5, 0.3535533845424652, 0, 0, 0, -0.3535533845424652, -0.5, -0.3535533845424652 );",
"const mat3 g2 = mat3( 0, 0.3535533845424652, -0.5, -0.3535533845424652, 0, 0.3535533845424652, 0.5, -0.3535533845424652, 0 );",
"const mat3 g3 = mat3( 0.5, -0.3535533845424652, 0, -0.3535533845424652, 0, 0.3535533845424652, 0, 0.3535533845424652, -0.5 );",
"const mat3 g4 = mat3( 0, -0.5, 0, 0.5, 0, 0.5, 0, -0.5, 0 );",
"const mat3 g5 = mat3( -0.5, 0, 0.5, 0, 0, 0, 0.5, 0, -0.5 );",
"const mat3 g6 = mat3( 0.1666666716337204, -0.3333333432674408, 0.1666666716337204, -0.3333333432674408, 0.6666666865348816, -0.3333333432674408, 0.1666666716337204, -0.3333333432674408, 0.1666666716337204 );",
"const mat3 g7 = mat3( -0.3333333432674408, 0.1666666716337204, -0.3333333432674408, 0.1666666716337204, 0.6666666865348816, 0.1666666716337204, -0.3333333432674408, 0.1666666716337204, -0.3333333432674408 );",
"const mat3 g8 = mat3( 0.3333333432674408, 0.3333333432674408, 0.3333333432674408, 0.3333333432674408, 0.3333333432674408, 0.3333333432674408, 0.3333333432674408, 0.3333333432674408, 0.3333333432674408 );",
"void main(void)",
"{",
"G[0] = g0,",
"G[1] = g1,",
"G[2] = g2,",
"G[3] = g3,",
"G[4] = g4,",
"G[5] = g5,",
"G[6] = g6,",
"G[7] = g7,",
"G[8] = g8;",
"mat3 I;",
"float cnv[9];",
"vec3 sample;",
/* fetch the 3x3 neighbourhood and use the RGB vector's length as intensity value */
"for (float i=0.0; i<3.0; i++) {",
"for (float j=0.0; j<3.0; j++) {",
"sample = texture2D(tDiffuse, vUv + texel * vec2(i-1.0,j-1.0) ).rgb;",
"I[int(i)][int(j)] = length(sample);",
"}",
"}",
/* calculate the convolution values for all the masks */
"for (int i=0; i<9; i++) {",
"float dp3 = dot(G[i][0], I[0]) + dot(G[i][1], I[1]) + dot(G[i][2], I[2]);",
"cnv[i] = dp3 * dp3;",
"}",
"float M = (cnv[0] + cnv[1]) + (cnv[2] + cnv[3]);",
"float S = (cnv[4] + cnv[5]) + (cnv[6] + cnv[7]) + (cnv[8] + M);",
"gl_FragColor = vec4(vec3(sqrt(M/S)), 1.0);",
"}"
].join( "\n" )
};
<!DOCTYPE html>
<html>
<head>
<title>Example 11.06 - Advanced</title>
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/three.js/96/three.min.js"></script>
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/stats.js/r16/Stats.min.js"></script>
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/dat-gui/0.7.2/dat.gui.min.js"></script>
<!-- https://github.com/gka/chroma.js/ -->
<script type="text/javascript" src="../libs96/chroma.min.js"></script>
<!-- https://github.com/mrdoob/three.js/tree/master/examples/js/postprocessing -->
<script type="text/javascript" src="../libs96/postprocessing/EffectComposer.js"></script>
<script type="text/javascript" src="../libs96/postprocessing/ShaderPass.js"></script>
<script type="text/javascript" src="../libs96/postprocessing/RenderPass.js"></script>
<script type="text/javascript" src="../libs96/postprocessing/MaskPass.js"></script>
<!-- https://github.com/mrdoob/three.js/tree/master/examples/js/shaders -->
<script type="text/javascript" src="../libs96/shaders/CopyShader.js"></script>
<script type="text/javascript" src="../libs96/shaders/BleachBypassShader.js"></script>
<script type="text/javascript" src="../libs96/shaders/EdgeShader.js"></script>
<script type="text/javascript" src="../libs96/shaders/FXAAShader.js"></script>
<script type="text/javascript" src="../libs96/shaders/FocusShader.js"></script>
<style>
body {
/* set margin to 0 and overflow to hidden, to go fullscreen */
margin: 0;
overflow: hidden;
}
</style>
</head>
<body>
<div id="Stats-output">
</div>
<!-- Div which will hold the Output -->
<div id="WebGL-output">
</div>
<!-- Javascript code that runs our Three.js examples -->
<script type="text/javascript">
// once everything is loaded, we run our Three.js stuff.
function init() {
var scale = chroma.scale(['white', 'blue']);
var stats = initStats();
// create a scene, that will hold all our elements such as objects, cameras and lights.
var scene = new THREE.Scene();
// create a camera, which defines where we're looking at.
var camera = new THREE.PerspectiveCamera(45, window.innerWidth / window.innerHeight, 0.1, 1000);
// create a render and set the size
var webGLRenderer = new THREE.WebGLRenderer();
webGLRenderer.setClearColor(new THREE.Color(0xaaaaff));
webGLRenderer.setSize(window.innerWidth, window.innerHeight);
webGLRenderer.shadowMap.enabled = true;
webGLRenderer.shadowMap.type = THREE.PCFSoftShadowMap; // default THREE.PCFShadowMap
webGLRenderer.antialias = false;
// // position and point the camera to the center of the scene
camera.position.x = 30;
camera.position.y = 30;
camera.position.z = 30;
camera.lookAt(new THREE.Vector3(0, 0, 0));
var dirLight = new THREE.DirectionalLight(0xffffff);
dirLight.position.set(30, 30, 30);
dirLight.intensity = 0.8;
scene.add(dirLight);
// add spotlight for the shadows
var spotLight = new THREE.SpotLight(0xffffff);
spotLight.castShadow = true;
spotLight.position.set(-30, 30, -100);
spotLight.target.position.x = -10;
spotLight.target.position.z = -10;
spotLight.intensity = 0.6;
spotLight.shadow.mapSize.width = 4096;
spotLight.shadow.mapSize.height = 4096;
spotLight.shadow.camera.fov = 120;
spotLight.shadow.camera.near = 1;
spotLight.shadow.camera.far = 200;
scene.add(spotLight);
var plane = new THREE.BoxGeometry(1600, 1600, 0.1, 40, 40);
var cube = new THREE.Mesh(plane, new THREE.MeshPhongMaterial(
{
color: 0xffffff,
map: new THREE.TextureLoader().load("../assets96/textures/general/floor-wood.jpg"),
normalScale: new THREE.Vector2(0.6, 0.6)
}));
cube.material.map.wrapS = THREE.RepeatWrapping;
cube.material.map.wrapT = THREE.RepeatWrapping;
cube.rotation.x = Math.PI / 2;
cube.material.map.repeat.set(80, 80);
cube.receiveShadow = true;
cube.position.z = -150;
cube.position.x = -150;
scene.add(cube);
var range = 3;
var stepX = 8;
var stepZ = 8;
for (var i = -25; i < 5; i++) {
for (var j = -15; j < 15; j++) {
var cube = new THREE.Mesh(new THREE.BoxGeometry(3, 4, 3),
new THREE.MeshPhongMaterial(
{
color: scale(Math.random()).hex(),
opacity: 0.8,
transparent: true
}));
cube.position.x = i * stepX + (Math.random() - 0.5) * range;
cube.position.z = j * stepZ + (Math.random() - 0.5) * range;
cube.position.y = (Math.random() - 0.5) * 2;
cube.castShadow = true;
scene.add(cube)
}
}
// add the output of the renderer to the html element
document.getElementById("WebGL-output").appendChild(webGLRenderer.domElement);
// create the shaders
// overlay of black and white
var bleachFilter = new THREE.ShaderPass(THREE.BleachBypassShader);
bleachFilter.enabled = false;
var edgeShader = new THREE.ShaderPass(THREE.EdgeShader);
edgeShader.enabled = false;
var FXAAShader = new THREE.ShaderPass(THREE.FXAAShader);
FXAAShader.enabled = false;
var focusShader = new THREE.ShaderPass(THREE.FocusShader);
focusShader.enabled = false;
var renderPass = new THREE.RenderPass(scene, camera);
var effectCopy = new THREE.ShaderPass(THREE.CopyShader);
effectCopy.renderToScreen = true;
var composer = new THREE.EffectComposer(webGLRenderer);
composer.addPass(renderPass);
composer.addPass(bleachFilter);
composer.addPass(edgeShader);
composer.addPass(FXAAShader);
composer.addPass(focusShader);
composer.addPass(effectCopy);
var controls = new function () {
this.bleachOpacity = 1;
this.bleach = false;
this.edgeDetect = false;
this.edgeAspect = 512;
this.FXAA = false;
this.focus = false;
this.sampleDistance = 0.94;
this.waveFactor = 0.00125;
this.screenWidth = window.innerWidth;
this.screenHeight = window.innerHeight;
this.onChange = function () {
bleachFilter.enabled = controls.bleach;
bleachFilter.uniforms.opacity.value = controls.bleachOpacity;
edgeShader.enabled = controls.edgeDetect;
edgeShader.uniforms.aspect.value = new THREE.Vector2(controls.edgeAspect, controls.edgeAspect);
FXAAShader.enabled = controls.FXAA;
FXAAShader.uniforms.resolution.value = new THREE.Vector2(1 / window.innerWidth, 1 / window.innerHeight);
focusShader.enabled = controls.focus;
focusShader.uniforms.screenWidth.value = controls.screenWidth;
focusShader.uniforms.screenHeight.value = controls.screenHeight;
focusShader.uniforms.waveFactor.value = controls.waveFactor;
focusShader.uniforms.sampleDistance.value = controls.sampleDistance;
}
};
var gui = new dat.GUI();
gui.add(controls, 'bleach').onChange(controls.onChange);
gui.add(controls, 'bleachOpacity', 0, 2).onChange(controls.onChange);
gui.add(controls, 'edgeDetect').onChange(controls.onChange);
gui.add(controls, 'edgeAspect', 128, 2048).step(128).onChange(controls.onChange);
gui.add(controls, 'FXAA').onChange(controls.onChange);
gui.add(controls, 'focus').onChange(controls.onChange);
gui.add(controls, 'sampleDistance', 0, 2).step(0.01).onChange(controls.onChange);
gui.add(controls, 'waveFactor', 0, 0.005).step(0.0001).onChange(controls.onChange);
render();
function render() {
stats.update();
//
//
requestAnimationFrame(render);
// webGLRenderer.render(scene, camera);
composer.render();
}
function initStats() {
var stats = new Stats();
stats.setMode(0); // 0: fps, 1: ms
// Align top-left
stats.domElement.style.position = 'absolute';
stats.domElement.style.left = '0px';
stats.domElement.style.top = '0px';
document.getElementById("Stats-output").appendChild(stats.domElement);
return stats;
}
}
window.onload = init;
</script>
</body>
</html>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment