2
0
Эх сурвалжийг харах

Merge pull request #11932 from Mugen87/sobel

Examples: Added Sobel Edge Detection
Mr.doob 8 жил өмнө
parent
commit
bc7c499e5d

+ 1 - 0
examples/files.js

@@ -214,6 +214,7 @@ var files = {
 		"webgl_postprocessing_crossfade",
 		"webgl_postprocessing_dof",
 		"webgl_postprocessing_dof2",
+		"webgl_postprocessing_edgedetection",
 		"webgl_postprocessing_glitch",
 		"webgl_postprocessing_godrays",
 		"webgl_postprocessing_masking",

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

@@ -1,73 +0,0 @@
-/**
- * @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": { 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[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" )
-
-};

+ 1 - 1
examples/js/shaders/EdgeShader.js → examples/js/shaders/FreiChenShader.js

@@ -7,7 +7,7 @@
  * aspect: vec2 of (1/width, 1/height)
  */
 
-THREE.EdgeShader = {
+THREE.FreiChenShader = {
 
 	uniforms: {
 

+ 90 - 0
examples/js/shaders/SobelOperatorShader.js

@@ -0,0 +1,90 @@
+/**
+ * @author Mugen87 / https://github.com/Mugen87
+ *
+ * Sobel Edge Detection (see https://youtu.be/uihBwtPIBxM)
+ *
+ * As mentioned in the video the Sobel operator expects a grayscale image as input.
+ *
+ */
+
+THREE.SobelOperatorShader = {
+
+	uniforms: {
+
+		"tDiffuse": { value: null },
+		"resolution": { value: new THREE.Vector2() }
+
+	},
+
+	vertexShader: [
+
+		"varying vec2 vUv;",
+
+		"void main() {",
+
+			"vUv = uv;",
+
+			"gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );",
+
+		"}"
+
+	].join( "\n" ),
+
+	fragmentShader: [
+
+		"uniform sampler2D tDiffuse;",
+		"uniform vec2 resolution;",
+		"varying vec2 vUv;",
+
+		"void main() {",
+
+			"vec2 texel = vec2( 1.0 / resolution.x, 1.0 / resolution.y );",
+
+			// kernel definition (in glsl matrices are filled in column-major order)
+
+			"const mat3 Gx = mat3( -1, -2, -1, 0, 0, 0, 1, 2, 1 );", // x direction kernel
+			"const mat3 Gy = mat3( -1, 0, 1, -2, 0, 2, -1, 0, 1 );", // y direction kernel
+
+			// fetch the 3x3 neighbourhood of a fragment
+
+			// first column
+
+			"float tx0y0 = texture2D( tDiffuse, vUv + texel * vec2( -1, -1 ) ).r;",
+			"float tx0y1 = texture2D( tDiffuse, vUv + texel * vec2( -1,  0 ) ).r;",
+			"float tx0y2 = texture2D( tDiffuse, vUv + texel * vec2( -1,  1 ) ).r;",
+
+			// second column
+
+			"float tx1y0 = texture2D( tDiffuse, vUv + texel * vec2(  0, -1 ) ).r;",
+			"float tx1y1 = texture2D( tDiffuse, vUv + texel * vec2(  0,  0 ) ).r;",
+			"float tx1y2 = texture2D( tDiffuse, vUv + texel * vec2(  0,  1 ) ).r;",
+
+			// third column
+
+			"float tx2y0 = texture2D( tDiffuse, vUv + texel * vec2(  1, -1 ) ).r;",
+			"float tx2y1 = texture2D( tDiffuse, vUv + texel * vec2(  1,  0 ) ).r;",
+			"float tx2y2 = texture2D( tDiffuse, vUv + texel * vec2(  1,  1 ) ).r;",
+
+			// gradient value in x direction
+
+			"float valueGx = Gx[0][0] * tx0y0 + Gx[1][0] * tx1y0 + Gx[2][0] * tx2y0 + ",
+				"Gx[0][1] * tx0y1 + Gx[1][1] * tx1y1 + Gx[2][1] * tx2y1 + ",
+				"Gx[0][2] * tx0y2 + Gx[1][2] * tx1y2 + Gx[2][2] * tx2y2; ",
+
+			// gradient value in y direction
+
+			"float valueGy = Gy[0][0] * tx0y0 + Gy[1][0] * tx1y0 + Gy[2][0] * tx2y0 + ",
+				"Gy[0][1] * tx0y1 + Gy[1][1] * tx1y1 + Gy[2][1] * tx2y1 + ",
+				"Gy[0][2] * tx0y2 + Gy[1][2] * tx1y2 + Gy[2][2] * tx2y2; ",
+
+			// magnitute of the total gradient
+
+			"float G = sqrt( ( valueGx * valueGx ) + ( valueGy * valueGy ) );",
+
+			"gl_FragColor = vec4( vec3( G ), 1 );",
+
+		"}"
+
+	].join( "\n" )
+
+};

+ 169 - 0
examples/webgl_postprocessing_edgedetection.html

@@ -0,0 +1,169 @@
+<!DOCTYPE html>
+<html lang="en">
+	<head>
+		<title>three.js webgl - postprocessing - edge detection (Sobel)</title>
+		<meta charset="utf-8">
+		<meta name="viewport" content="width=device-width, user-scalable=no, minimum-scale=1.0, maximum-scale=1.0">
+		<style>
+			body {
+				background:#777;
+				padding:0;
+				margin:0;
+				font-weight: bold;
+				overflow:hidden;
+			}
+
+			#info {
+				position: absolute;
+				top: 0px;
+				width: 100%;
+				color: #ffffff;
+				padding: 5px;
+				font-family:Monospace;
+				font-size:13px;
+				text-align:center;
+			}
+
+			a {
+				color: #ffffff;
+			}
+		</style>
+	</head>
+	<body>
+
+		<script src="../build/three.js"></script>
+		<script src="js/controls/OrbitControls.js"></script>
+		<script src="js/Detector.js"></script>
+		<script src="js/libs/dat.gui.min.js"></script>
+
+		<script src="js/shaders/CopyShader.js"></script>
+		<script src="js/shaders/LuminosityShader.js"></script>
+		<script src="js/shaders/SobelOperatorShader.js"></script>
+
+		<script src="js/postprocessing/EffectComposer.js"></script>
+		<script src="js/postprocessing/RenderPass.js"></script>
+		<script src="js/postprocessing/ShaderPass.js"></script>
+
+		<div id="info">
+			<a href="https://threejs.org" target="_blank">three.js</a> - webgl - postprocessing - edge detection (Sobel)
+		</div>
+
+		<script>
+
+			if ( ! Detector.webgl ) Detector.addGetWebGLMessage();
+
+			var camera, scene, renderer, composer;
+
+			var effectSobel;
+
+			var params = {
+				enable: true
+			};
+
+			init();
+			animate();
+
+			function init() {
+
+				//
+
+				scene = new THREE.Scene();
+
+				camera = new THREE.PerspectiveCamera( 70, window.innerWidth / window.innerHeight, 1, 1000 );
+				camera.position.set( 0, 10, 20 );
+				camera.lookAt( scene.position );
+
+				//
+
+				var geometry = new THREE.IcosahedronGeometry( 8 );
+				var material = new THREE.MeshPhongMaterial( { color: 0xffff00 } );
+
+				var mesh = new THREE.Mesh( geometry, material );
+				scene.add( mesh );
+
+				//
+
+				var ambientLight = new THREE.AmbientLight( 0xcccccc, 0.4 );
+				scene.add( ambientLight );
+
+				var pointLight = new THREE.PointLight( 0xffffff, 0.8 );
+				camera.add( pointLight );
+				scene.add( camera );
+
+				//
+
+				renderer = new THREE.WebGLRenderer();
+				renderer.setPixelRatio( window.devicePixelRatio );
+				renderer.setSize( window.innerWidth, window.innerHeight );
+				document.body.appendChild( renderer.domElement );
+
+				// postprocessing
+
+				composer = new THREE.EffectComposer( renderer );
+				var renderPass = new THREE.RenderPass( scene, camera );
+				composer.addPass( renderPass );
+
+				// color to grayscale conversion
+
+				var effectGrayScale = new THREE.ShaderPass( THREE.LuminosityShader );
+				composer.addPass( effectGrayScale );
+
+				// you might want to use a gaussian blur filter before
+				// the next pass to improve the result of the Sobel operator
+
+				// Sobel operator
+
+				effectSobel = new THREE.ShaderPass( THREE.SobelOperatorShader );
+				effectSobel.renderToScreen = true;
+				effectSobel.uniforms.resolution.value.x = window.innerWidth;
+				effectSobel.uniforms.resolution.value.y = window.innerHeight;
+				composer.addPass( effectSobel );
+
+				var controls = new THREE.OrbitControls( camera );
+
+				//
+
+				var gui = new dat.GUI();
+
+				gui.add( params, 'enable' );
+				gui.open();
+
+				//
+
+				window.addEventListener( 'resize', onWindowResize, false );
+
+			}
+
+			function onWindowResize() {
+
+				camera.aspect =  window.innerWidth / window.innerHeight;
+				camera.updateProjectionMatrix();
+
+				renderer.setSize( window.innerWidth, window.innerHeight );
+				composer.setSize( window.innerWidth, window.innerHeight );
+
+				effectSobel.uniforms.resolution.value.x = window.innerWidth;
+				effectSobel.uniforms.resolution.value.y = window.innerHeight;
+
+			}
+
+			function animate() {
+
+				requestAnimationFrame( animate );
+
+				if ( params.enable === true ) {
+
+					composer.render();
+
+				} else {
+
+					renderer.render( scene, camera );
+
+				}
+
+			}
+
+		</script>
+
+	</body>
+</html>