Browse Source

Add Edge Detection Shaders (Frei-Chen & Sobel filters) to examples

zz85 12 years ago
parent
commit
9edf3c06cb

+ 93 - 0
examples/js/shaders/EdgeShader.js

@@ -0,0 +1,93 @@
+/**
+ * @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": { type: "t", value: null },
+		"aspect":    { type: "v2", 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")
+};

+ 73 - 0
examples/js/shaders/EdgeShader2.js

@@ -0,0 +1,73 @@
+/**
+ * @author zz85 / https://github.com/zz85 | https://www.lab4games.net/zz85/blog
+ *
+ * Edge Detection Shader using Sobel filter
+ * Based on http://rastergrid.com/blog/2011/01/frei-chen-edge-detector
+ *
+ * aspect: vec2 of (1/width, 1/height)
+ */
+
+THREE.EdgeShader2 = {
+
+	uniforms: {
+
+		"tDiffuse": { type: "t", value: null },
+		"aspect":    { type: "v2", 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[2];",
+
+		"const mat3 g0 = mat3( 1.0, 2.0, 1.0, 0.0, 0.0, 0.0, -1.0, -2.0, -1.0 );",
+		"const mat3 g1 = mat3( 1.0, 0.0, -1.0, 2.0, 0.0, -2.0, 1.0, 0.0, -1.0 );",
+
+
+		"void main(void)",
+		"{",
+			"mat3 I;",
+			"float cnv[2];",
+			"vec3 sample;",
+
+			"G[0] = g0;",
+			"G[1] = g1;",
+
+			/* 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<2; 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; ",
+			"}",
+
+			"gl_FragColor = vec4(0.5 * sqrt(cnv[0]*cnv[0]+cnv[1]*cnv[1]));",
+		"} ",
+
+	].join("\n")
+
+};

+ 177 - 0
examples/webgl_postprocessing2.html

@@ -0,0 +1,177 @@
+<!DOCTYPE html>
+<html lang="en">
+	<head>
+		<title>three.js webgl - postprocessing</title>
+		<meta charset="utf-8">
+		<style>
+			body {
+				margin: 0px;
+				background-color: #000000;
+				overflow: hidden;
+			}
+
+			div {
+				position: absolute;
+				z-index: 10;
+				color: #fff;
+				font-family: monospace;
+				text-align: center;
+				margin: 10px;
+				width: 100%;
+			}
+
+			label, input {
+				cursor: pointer;
+			}
+		</style>
+	</head>
+	<body>
+
+		<script src="../build/three.min.js"></script>
+
+		<script src="js/shaders/CopyShader.js"></script>
+		<script src="js/shaders/DotScreenShader.js"></script>
+		<script src="js/shaders/RGBShiftShader.js"></script>
+		<script src="js/shaders/EdgeShader.js"></script>
+		<script src="js/shaders/EdgeShader2.js"></script>
+
+		<script src="js/postprocessing/EffectComposer.js"></script>
+		<script src="js/postprocessing/RenderPass.js"></script>
+		<script src="js/postprocessing/MaskPass.js"></script>
+		<script src="js/postprocessing/ShaderPass.js"></script>
+
+		<div>
+			<label for="dotScreen">Dot Screen:</label><input id="dotScreen" type="checkbox" onchange="updateOptions()"/><br />
+			<label for="rgbShift">RGB Shift:</label><input id="rgbShift" type="checkbox" onchange="updateOptions()" /><br />
+			<label for="edge">Edge Detection (Frei-Chen Filter):</label><input id="edge" type="checkbox" checked onchange="updateOptions()" /><br />
+			<label for="edge2">Edge Detection (Sobel Filter):</label><input id="edge2" type="checkbox" onchange="updateOptions()" /><br />
+
+		</div>
+
+		<script>
+
+			var camera, scene, renderer, composer;
+			var object, light;
+
+			var dotScreenEffect, rgbShiftEffect, edgeEffect, edgeEffect2;
+
+			init();
+			animate();
+
+			function updateOptions() {
+				var dotScreen = document.getElementById('dotScreen');
+				var rgbShift = document.getElementById('rgbShift');
+				var edge = document.getElementById('edge');
+				var edge2 = document.getElementById('edge2');
+
+				dotScreenEffect.enabled = dotScreen.checked;
+				rgbShiftEffect.enabled = rgbShift.checked;
+				edgeEffect.enabled = edge.checked;
+				edgeEffect2.enabled = edge2.checked;
+
+			}
+
+			function init() {
+
+				renderer = new THREE.WebGLRenderer();
+				renderer.setSize( window.innerWidth, window.innerHeight );
+				document.body.appendChild( renderer.domElement );
+
+				//
+
+				camera = new THREE.PerspectiveCamera( 70, window.innerWidth / window.innerHeight, 1, 1000 );
+				camera.position.z = 400;
+
+				scene = new THREE.Scene();
+				scene.fog = new THREE.Fog( 0x000000, 1, 1000 );
+
+				object = new THREE.Object3D();
+				scene.add( object );
+
+				var geometry = new THREE.SphereGeometry( 1, 4, 4 );
+				var material = new THREE.MeshPhongMaterial( { color: 0xffffff, shading: THREE.FlatShading } );
+
+				for ( var i = 0; i < 100; i ++ ) {
+					material = new THREE.MeshPhongMaterial( { color: 0xffffff * Math.random(), shading: THREE.FlatShading } );
+
+					var mesh = new THREE.Mesh( geometry, material );
+					mesh.position.set( Math.random() - 0.5, Math.random() - 0.5, Math.random() - 0.5 ).normalize();
+					mesh.position.multiplyScalar( Math.random() * 400 );
+					mesh.rotation.set( Math.random() * 2, Math.random() * 2, Math.random() * 2 );
+					mesh.scale.x = mesh.scale.y = mesh.scale.z = Math.random() * 50;
+					object.add( mesh );
+
+				}
+
+				scene.add( new THREE.AmbientLight( 0x222222 ) );
+
+				light = new THREE.DirectionalLight( 0xffffff );
+				light.position.set( 1, 1, 1 );
+				scene.add( light );
+
+				// postprocessing
+
+				composer = new THREE.EffectComposer( renderer );
+				composer.addPass( new THREE.RenderPass( scene, camera ) );
+
+				dotScreenEffect = new THREE.ShaderPass( THREE.DotScreenShader );
+				dotScreenEffect.uniforms[ 'scale' ].value = 4;
+				composer.addPass( dotScreenEffect );
+
+				rgbShiftEffect = new THREE.ShaderPass( THREE.RGBShiftShader );
+				rgbShiftEffect.uniforms[ 'amount' ].value = 0.0015;
+				composer.addPass( rgbShiftEffect );
+
+				edgeEffect = new THREE.ShaderPass( THREE.EdgeShader );
+				edgeEffect.uniforms[ 'aspect' ].value.x = window.innerWidth;
+				edgeEffect.uniforms[ 'aspect' ].value.y = window.innerHeight;
+				composer.addPass( edgeEffect );
+
+				edgeEffect2 = new THREE.ShaderPass( THREE.EdgeShader2 );
+				edgeEffect2.uniforms[ 'aspect' ].value.x = window.innerWidth;
+				edgeEffect2.uniforms[ 'aspect' ].value.y = window.innerHeight;
+				composer.addPass( edgeEffect2 );
+
+				var effect = new THREE.ShaderPass( THREE.CopyShader);
+				effect.renderToScreen = true;
+				composer.addPass( effect );
+
+				//
+
+				window.addEventListener( 'resize', onWindowResize, false );
+
+				updateOptions();
+
+			}
+
+			function onWindowResize() {
+
+				camera.aspect = window.innerWidth / window.innerHeight;
+				camera.updateProjectionMatrix();
+
+				renderer.setSize( window.innerWidth, window.innerHeight );
+
+				edgeEffect.uniforms[ 'aspect' ].value.x = window.innerWidth;
+				edgeEffect.uniforms[ 'aspect' ].value.y = window.innerHeight;
+				edgeEffect2.uniforms[ 'aspect' ].value.x = window.innerWidth;
+				edgeEffect2.uniforms[ 'aspect' ].value.y = window.innerHeight;
+
+			}
+
+			function animate() {
+
+				requestAnimationFrame( animate );
+
+				var time = Date.now();
+
+				object.rotation.x += 0.005;
+				object.rotation.y += 0.01;
+
+				composer.render();
+				// renderer.render(scene, camera);
+
+			}
+
+		</script>
+	</body>
+</html>