Created
September 28, 2018 14:43
-
-
Save valex/2324d10a6cf436ab4c96bc112a9b8770 to your computer and use it in GitHub Desktop.
BleachBypassShader + EdgeShader + FXAAShader + FocusShader
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* @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" ) | |
}; |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<!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