Browse Source

Added marching cubes example.

Transplanted from ro.me repo, ported to use new lib version, modernized code.
alteredq 13 years ago
parent
commit
c1a5c069c0
2 changed files with 1052 additions and 0 deletions
  1. 331 0
      examples/js/ShaderToon.js
  2. 721 0
      examples/webgl_marching_cubes.html

+ 331 - 0
examples/js/ShaderToon.js

@@ -0,0 +1,331 @@
+/**
+ * @author mrdoob / http://mrdoob.com/
+ * @author alteredq / http://alteredqualia.com/
+ *
+ * ShaderToon currently contains:
+ *
+ *	toon1
+ *	toon2
+ *	hatching
+ *	dotted
+ */
+
+THREE.ShaderToon = {
+
+'toon1' : {
+
+	uniforms: {
+
+		"uDirLightPos":	{ type: "v3", value: new THREE.Vector3() },
+		"uDirLightColor": { type: "c", value: new THREE.Color( 0xeeeeee ) },
+
+		"uAmbientLightColor": { type: "c", value: new THREE.Color( 0x050505 ) },
+
+		"uBaseColor":  { type: "c", value: new THREE.Color( 0xffffff ) }
+
+	},
+
+	vertexShader: [
+
+		"varying vec3 vNormal;",
+		"varying vec3 vRefract;",
+
+		"void main() {",
+
+			"vec4 mPosition = objectMatrix * vec4( position, 1.0 );",
+			"vec4 mvPosition = modelViewMatrix * vec4( position, 1.0 );",
+			"vec3 nWorld = normalize ( mat3( objectMatrix[0].xyz, objectMatrix[1].xyz, objectMatrix[2].xyz ) * normal );",
+
+			"vNormal = normalize( normalMatrix * normal );",
+
+			"vec3 I = mPosition.xyz - cameraPosition;",
+			"vRefract = refract( normalize( I ), nWorld, 1.02 );",
+
+			"gl_Position = projectionMatrix * mvPosition;",
+
+		"}"
+
+	].join("\n"),
+
+	fragmentShader: [
+
+		"uniform vec3 uBaseColor;",
+
+		"uniform vec3 uDirLightPos;",
+		"uniform vec3 uDirLightColor;",
+
+		"uniform vec3 uAmbientLightColor;",
+
+		"varying vec3 vNormal;",
+
+		"varying vec3 vRefract;",
+
+		"void main() {",
+
+			"float directionalLightWeighting = max( dot( normalize( vNormal ), uDirLightPos ), 0.0);",
+			"vec3 lightWeighting = uAmbientLightColor + uDirLightColor * directionalLightWeighting;",
+
+			"float intensity = smoothstep( - 0.5, 1.0, pow( length(lightWeighting), 20.0 ) );",
+			"intensity += length(lightWeighting) * 0.2;",
+
+			"float cameraWeighting = dot( normalize( vNormal ), vRefract );",
+			"intensity += pow( 1.0 - length( cameraWeighting ), 6.0 );",
+			"intensity = intensity * 0.2 + 0.3;",
+
+			"if ( intensity < 0.50 ) {",
+
+				"gl_FragColor = vec4( 2.0 * intensity * uBaseColor, 1.0 );",
+
+			"} else {",
+
+				"gl_FragColor = vec4( 1.0 - 2.0 * ( 1.0 - intensity ) * ( 1.0 - uBaseColor ), 1.0 );",
+
+			"}",
+
+		"}"
+
+	].join("\n")
+
+},
+
+'toon2' : {
+
+	uniforms: {
+
+		"uDirLightPos":	{ type: "v3", value: new THREE.Vector3() },
+		"uDirLightColor": { type: "c", value: new THREE.Color( 0xeeeeee ) },
+
+		"uAmbientLightColor": { type: "c", value: new THREE.Color( 0x050505 ) },
+
+		"uBaseColor":  { type: "c", value: new THREE.Color( 0xeeeeee ) },
+		"uLineColor1": { type: "c", value: new THREE.Color( 0x808080 ) },
+		"uLineColor2": { type: "c", value: new THREE.Color( 0x000000 ) },
+		"uLineColor3": { type: "c", value: new THREE.Color( 0x000000 ) },
+		"uLineColor4": { type: "c", value: new THREE.Color( 0x000000 ) }
+
+	},
+
+	vertexShader: [
+
+		"varying vec3 vNormal;",
+
+		"void main() {",
+
+			"gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );",
+			"vNormal = normalize( normalMatrix * normal );",
+
+		"}"
+
+	].join("\n"),
+
+	fragmentShader: [
+
+		"uniform vec3 uBaseColor;",
+		"uniform vec3 uLineColor1;",
+		"uniform vec3 uLineColor2;",
+		"uniform vec3 uLineColor3;",
+		"uniform vec3 uLineColor4;",
+
+		"uniform vec3 uDirLightPos;",
+		"uniform vec3 uDirLightColor;",
+
+		"uniform vec3 uAmbientLightColor;",
+
+		"varying vec3 vNormal;",
+
+		"void main() {",
+
+			"float camera = max( dot( normalize( vNormal ), vec3( 0.0, 0.0, 1.0 ) ), 0.4);",
+			"float light = max( dot( normalize( vNormal ), uDirLightPos ), 0.0);",
+
+			"gl_FragColor = vec4( uBaseColor, 1.0 );",
+
+			"if ( length(uAmbientLightColor + uDirLightColor * light) < 1.00 ) {",
+
+				"gl_FragColor *= vec4( uLineColor1, 1.0 );",
+
+			"}",
+
+			"if ( length(uAmbientLightColor + uDirLightColor * camera) < 0.50 ) {",
+
+				"gl_FragColor *= vec4( uLineColor2, 1.0 );",
+
+			"}",
+
+		"}"
+
+	].join("\n")
+
+},
+
+'hatching' : {
+
+	uniforms: {
+
+		"uDirLightPos":	{ type: "v3", value: new THREE.Vector3() },
+		"uDirLightColor": { type: "c", value: new THREE.Color( 0xeeeeee ) },
+
+		"uAmbientLightColor": { type: "c", value: new THREE.Color( 0x050505 ) },
+
+		"uBaseColor":  { type: "c", value: new THREE.Color( 0xffffff ) },
+		"uLineColor1": { type: "c", value: new THREE.Color( 0x000000 ) },
+		"uLineColor2": { type: "c", value: new THREE.Color( 0x000000 ) },
+		"uLineColor3": { type: "c", value: new THREE.Color( 0x000000 ) },
+		"uLineColor4": { type: "c", value: new THREE.Color( 0x000000 ) }
+
+	},
+
+	vertexShader: [
+
+		"varying vec3 vNormal;",
+
+		"void main() {",
+
+			"gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );",
+			"vNormal = normalize( normalMatrix * normal );",
+
+		"}"
+
+	].join("\n"),
+
+	fragmentShader: [
+
+		"uniform vec3 uBaseColor;",
+		"uniform vec3 uLineColor1;",
+		"uniform vec3 uLineColor2;",
+		"uniform vec3 uLineColor3;",
+		"uniform vec3 uLineColor4;",
+
+		"uniform vec3 uDirLightPos;",
+		"uniform vec3 uDirLightColor;",
+
+		"uniform vec3 uAmbientLightColor;",
+
+		"varying vec3 vNormal;",
+
+		"void main() {",
+
+			"float directionalLightWeighting = max( dot( normalize(vNormal), uDirLightPos ), 0.0);",
+			"vec3 lightWeighting = uAmbientLightColor + uDirLightColor * directionalLightWeighting;",
+
+			"gl_FragColor = vec4( uBaseColor, 1.0 );",
+
+			"if ( length(lightWeighting) < 1.00 ) {",
+
+				"if ( mod(gl_FragCoord.x + gl_FragCoord.y, 10.0) == 0.0) {",
+
+					"gl_FragColor = vec4( uLineColor1, 1.0 );",
+
+				"}",
+
+			"}",
+
+			"if ( length(lightWeighting) < 0.75 ) {",
+
+				"if (mod(gl_FragCoord.x - gl_FragCoord.y, 10.0) == 0.0) {",
+
+					"gl_FragColor = vec4( uLineColor2, 1.0 );",
+
+				"}",
+			"}",
+
+			"if ( length(lightWeighting) < 0.50 ) {",
+
+				"if (mod(gl_FragCoord.x + gl_FragCoord.y - 5.0, 10.0) == 0.0) {",
+
+					"gl_FragColor = vec4( uLineColor3, 1.0 );",
+
+				"}",
+			"}",
+
+			"if ( length(lightWeighting) < 0.3465 ) {",
+
+				"if (mod(gl_FragCoord.x - gl_FragCoord.y - 5.0, 10.0) == 0.0) {",
+
+					"gl_FragColor = vec4( uLineColor4, 1.0 );",
+
+				"}",
+			"}",
+
+		"}"
+
+	].join("\n")
+
+},
+
+'dotted' : {
+
+	uniforms: {
+
+		"uDirLightPos":	{ type: "v3", value: new THREE.Vector3() },
+		"uDirLightColor": { type: "c", value: new THREE.Color( 0xeeeeee ) },
+
+		"uAmbientLightColor": { type: "c", value: new THREE.Color( 0x050505 ) },
+
+		"uBaseColor":  { type: "c", value: new THREE.Color( 0xffffff ) },
+		"uLineColor1": { type: "c", value: new THREE.Color( 0x000000 ) }
+
+	},
+
+	vertexShader: [
+
+		"varying vec3 vNormal;",
+
+		"void main() {",
+
+			"gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );",
+			"vNormal = normalize( normalMatrix * normal );",
+
+		"}"
+
+	].join("\n"),
+
+	fragmentShader: [
+
+		"uniform vec3 uBaseColor;",
+		"uniform vec3 uLineColor1;",
+		"uniform vec3 uLineColor2;",
+		"uniform vec3 uLineColor3;",
+		"uniform vec3 uLineColor4;",
+
+		"uniform vec3 uDirLightPos;",
+		"uniform vec3 uDirLightColor;",
+
+		"uniform vec3 uAmbientLightColor;",
+
+		"varying vec3 vNormal;",
+
+		"void main() {",
+
+			"float directionalLightWeighting = max( dot( normalize(vNormal), uDirLightPos ), 0.0);",
+			"vec3 lightWeighting = uAmbientLightColor + uDirLightColor * directionalLightWeighting;",
+
+			"gl_FragColor = vec4( uBaseColor, 1.0 );",
+
+			"if ( length(lightWeighting) < 1.00 ) {",
+
+				"if ( ( mod(gl_FragCoord.x, 4.001) + mod(gl_FragCoord.y, 4.0) ) > 6.00 ) {",
+
+					"gl_FragColor = vec4( uLineColor1, 1.0 );",
+
+				"}",
+
+			"}",
+
+			"if ( length(lightWeighting) < 0.50 ) {",
+
+				"if ( ( mod(gl_FragCoord.x + 2.0, 4.001) + mod(gl_FragCoord.y + 2.0, 4.0) ) > 6.00 ) {",
+
+					"gl_FragColor = vec4( uLineColor1, 1.0 );",
+
+				"}",
+
+			"}",
+
+		"}"
+
+	].join("\n")
+
+}
+
+};

+ 721 - 0
examples/webgl_marching_cubes.html

@@ -0,0 +1,721 @@
+<!DOCTYPE HTML>
+<html lang="en">
+<head>
+	<title>three.js webgl - marching cubes</title>
+	<meta charset="utf-8">
+	<style>
+		body {
+		  color: #fff;
+		  font-family: Monospace;
+		  font-size: 13px;
+		  text-align: center;
+
+		  background-color: #000;
+		  margin: 0px;
+		  overflow: hidden;
+		}
+
+		#info {
+		  color: #ffffff;
+		  position: absolute;
+		  top: 0px;
+		  width: 100%;
+		  padding: 5px;
+		}
+
+		a {
+		  color: gold;
+		}
+
+		#oldie {
+		  font-family: monospace;
+		  font-size: 13px;
+
+		  text-align: center;
+		  background: rgb(0, 0, 50);
+		  color: #fff;
+		  padding: 1em;
+
+		  width: 475px;
+		  margin: 5em auto 0;
+
+		  display: none;
+		}
+
+	</style>
+</head>
+
+<body>
+
+	<div id="container"></div>
+	<div id="info">
+		<a href="http://github.com/mrdoob/three.js" target="_blank">three.js</a> -
+		marching cubes -
+		[based on greggman's <a href="http://webglsamples.googlecode.com/hg/blob/blob.html">blob</a>, original code by Henrik Rydgård]
+	</div>
+
+	<script src="../build/Three.js"></script>
+
+	<script src="js/ShaderExtras.js"></script>
+	<script src="js/ShaderToon.js"></script>
+
+	<script src="js/ShaderExtras.js"></script>
+
+	<script src="js/postprocessing/EffectComposer.js"></script>
+	<script src="js/postprocessing/RenderPass.js"></script>
+	<script src="js/postprocessing/BloomPass.js"></script>
+	<script src="js/postprocessing/ShaderPass.js"></script>
+	<script src="js/postprocessing/MaskPass.js"></script>
+	<script src="js/postprocessing/SavePass.js"></script>
+
+
+	<script src="js/Detector.js"></script>
+	<script src="js/Stats.js"></script>
+	<script src="js/DAT.GUI.min.js"></script>
+
+
+	<script>
+		if ( ! Detector.webgl ) Detector.addGetWebGLMessage();
+
+		var MARGIN = 0;
+
+		var SCREEN_WIDTH = window.innerWidth;
+		var SCREEN_HEIGHT = window.innerHeight - 2 * MARGIN;
+
+		var container, stats;
+
+		var camera, scene, renderer;
+
+		var mesh, texture, geometry, materials, material, current_material;
+
+		var light, pointLight, ambientLight;
+
+		var effect, resolution, numBlobs;
+
+		var composer, effectFXAA, hblur, vblur;
+
+		var effectController;
+
+		var time = 0;
+		var clock = new THREE.Clock();
+
+		init();
+		animate();
+
+		function init() {
+
+			container = document.getElementById( 'container' );
+
+			// SCENE
+
+			scene = new THREE.Scene();
+
+			// CAMERA
+
+			camera = new THREE.PerspectiveCamera( 45, SCREEN_WIDTH / SCREEN_HEIGHT, 1, 10000 );
+			camera.position.set( -500, 500, 1500 );
+
+			scene.add( camera );
+
+			// CONTROLS
+
+			controls = new THREE.TrackballControls( camera );
+
+			// LIGHTS
+
+			light = new THREE.DirectionalLight( 0xffffff );
+			light.position.set( 0.5, 0.5, 1 );
+			scene.add( light );
+
+			pointLight = new THREE.PointLight( 0xff3300 );
+			pointLight.position.set( 0, 0, 100 );
+			scene.add( pointLight );
+
+			ambientLight = new THREE.AmbientLight( 0x080808 );
+			scene.add( ambientLight );
+
+			// MATERIALS
+
+			materials = generateMaterials();
+			current_material = "shiny";
+
+			// MARCHING CUBES
+
+			resolution = 28;
+			numBlobs = 10;
+
+			effect = new THREE.MarchingCubes( resolution, materials[ current_material ].m );
+			effect.position.set( 0, 0, 0 );
+			effect.scale.set( 700, 700, 700 );
+			scene.add( effect );
+
+			// RENDERER
+
+			renderer = new THREE.WebGLRenderer( { clearColor: 0x050505, clearAlpha: 1, alpha: false } );
+			renderer.setSize( SCREEN_WIDTH, SCREEN_HEIGHT );
+
+			renderer.domElement.style.position = "absolute";
+			renderer.domElement.style.top = MARGIN + "px";
+			renderer.domElement.style.left = "0px";
+
+			container.appendChild( renderer.domElement );
+			//
+
+			renderer.gammaInput = true;
+			renderer.gammaOutput = true;
+			renderer.physicallyBasedShading = true;
+
+			// STATS
+
+			stats = new Stats();
+			stats.domElement.style.position = 'absolute';
+			stats.domElement.style.top = '0px';
+			container.appendChild( stats.domElement );
+
+			stats.domElement.children[ 0 ].children[ 0 ].style.color = "#888";
+			stats.domElement.children[ 0 ].style.background = "transparent";
+			stats.domElement.children[ 0 ].children[ 1 ].style.display = "none";
+
+			// COMPOSER
+
+			renderer.autoClear = false;
+
+			renderTargetParameters = { minFilter: THREE.LinearFilter, magFilter: THREE.LinearFilter, format: THREE.RGBFormat, stencilBuffer: false };
+			renderTarget = new THREE.WebGLRenderTarget( SCREEN_WIDTH, SCREEN_HEIGHT, renderTargetParameters );
+
+			effectFXAA = new THREE.ShaderPass( THREE.ShaderExtras[ "fxaa" ] );
+
+			hblur = new THREE.ShaderPass( THREE.ShaderExtras[ "horizontalTiltShift" ] );
+			vblur = new THREE.ShaderPass( THREE.ShaderExtras[ "verticalTiltShift" ] );
+
+			var bluriness = 8;
+
+			hblur.uniforms[ 'h' ].value = bluriness / SCREEN_WIDTH;
+			vblur.uniforms[ 'v' ].value = bluriness / SCREEN_HEIGHT;
+
+			hblur.uniforms[ 'r' ].value = vblur.uniforms[ 'r' ].value = 0.5;
+
+			effectFXAA.uniforms[ 'resolution' ].value.set( 1 / SCREEN_WIDTH, 1 / SCREEN_HEIGHT );
+
+			composer = new THREE.EffectComposer( renderer, renderTarget );
+
+			var renderModel = new THREE.RenderPass( scene, camera );
+
+			vblur.renderToScreen = true;
+			//effectFXAA.renderToScreen = true;
+
+			composer = new THREE.EffectComposer( renderer, renderTarget );
+
+			composer.addPass( renderModel );
+
+			composer.addPass( effectFXAA );
+
+			composer.addPass( hblur );
+			composer.addPass( vblur );
+
+			// GUI
+
+			setupGui();
+
+			// EVENTS
+
+			window.addEventListener( 'resize', onWindowResize, false );
+
+		}
+
+		//
+
+		function onWindowResize( event ) {
+
+			SCREEN_WIDTH = window.innerWidth;
+			SCREEN_HEIGHT = window.innerHeight - 2 * MARGIN;
+
+			renderer.setSize( SCREEN_WIDTH, SCREEN_HEIGHT );
+
+			camera.aspect = SCREEN_WIDTH / SCREEN_HEIGHT;
+			camera.updateProjectionMatrix();
+
+			renderTarget = new THREE.WebGLRenderTarget( SCREEN_WIDTH, SCREEN_HEIGHT, renderTargetParameters );
+
+			composer.reset( renderTarget );
+
+			hblur.uniforms[ 'h' ].value = 4 / SCREEN_WIDTH;
+			vblur.uniforms[ 'v' ].value = 4 / SCREEN_HEIGHT;
+
+			effectFXAA.uniforms[ 'resolution' ].value.set( 1 / SCREEN_WIDTH, 1 / SCREEN_HEIGHT );
+
+		}
+
+		function generateMaterials() {
+
+			// environment map
+
+			var path = "textures/cube/SwedishRoyalCastle/";
+			var format = '.jpg';
+			var urls = [
+				path + 'px' + format, path + 'nx' + format,
+				path + 'py' + format, path + 'ny' + format,
+				path + 'pz' + format, path + 'nz' + format
+			];
+
+			var reflectionCube = THREE.ImageUtils.loadTextureCube( urls );
+			reflectionCube.format = THREE.RGBFormat;
+
+			var refractionCube = new THREE.Texture( reflectionCube.image, new THREE.CubeRefractionMapping() );
+			reflectionCube.format = THREE.RGBFormat;
+
+			// toons
+
+			var toonMaterial1 = createShaderMaterial( "toon1", light, ambientLight ),
+			toonMaterial2 = createShaderMaterial( "toon2", light, ambientLight ),
+			hatchingMaterial = createShaderMaterial( "hatching", light, ambientLight ),
+			hatchingMaterial2 = createShaderMaterial( "hatching", light, ambientLight ),
+			dottedMaterial = createShaderMaterial( "dotted", light, ambientLight ),
+			dottedMaterial2 = createShaderMaterial( "dotted", light, ambientLight );
+
+			hatchingMaterial2.uniforms.uBaseColor.value.setRGB( 0, 0, 0 );
+			hatchingMaterial2.uniforms.uLineColor1.value.setHSV( 0, 0.9, 0.9 );
+			hatchingMaterial2.uniforms.uLineColor2.value.setHSV( 0, 0.9, 0.9 );
+			hatchingMaterial2.uniforms.uLineColor3.value.setHSV( 0, 0.9, 0.9 );
+			hatchingMaterial2.uniforms.uLineColor4.value.setHSV( 0.1, 0.9, 0.9 );
+
+			dottedMaterial2.uniforms.uBaseColor.value.setRGB( 0, 0, 0 );
+			dottedMaterial2.uniforms.uLineColor1.value.setHSV( 0.05, 1.0, 1.0 );
+
+			var materials = {
+
+			"chrome" :
+			{
+				m: new THREE.MeshLambertMaterial( { color: 0xffffff, envMap: reflectionCube } ),
+				h: 0, s: 0, v: 1
+			},
+
+			"liquid" :
+			{
+				m: new THREE.MeshLambertMaterial( { color: 0xffffff, envMap: refractionCube, refractionRatio: 0.85 } ),
+				h: 0, s: 0, v: 1
+			},
+
+			"shiny"  :
+			{
+				m: new THREE.MeshPhongMaterial( { color: 0x550000, specular: 0x440000, envMap: reflectionCube, combine: THREE.MixOperation, reflectivity: 0.3, perPixel: true, metal: true } ),
+				h: 0, s: 0.9, v: 0.3
+			},
+
+			"matte" :
+			{
+				m: new THREE.MeshPhongMaterial( { color: 0x000000, specular: 0x111111, shininess: 1, perPixel: true } ),
+				h: 0, s: 0, v: 1
+			},
+
+			"plastic" :
+			{
+				m: new THREE.MeshPhongMaterial( { color: 0x000000, specular: 0x888888, ambient: 0x000000, shininess: 250, perPixel: true } ),
+				h: 0.6, s: 0.9, v: 0.2
+			},
+
+			"toon1"  :
+			{
+				m: toonMaterial1,
+				h: 0.2, s: 0.5, v: 1
+			},
+
+			"toon2" :
+			{
+				m: toonMaterial2,
+				h: 0.4, s: 0.5, v: 1
+			},
+
+			"hatching" :
+			{
+				m: hatchingMaterial,
+				h: 0.2, s: 0.2, v: 1
+			},
+
+			"hatching2" :
+			{
+				m: hatchingMaterial2,
+				h: 0.0, s: 0.9, v: 0.9
+			},
+
+			"dotted" :
+			{
+				m: dottedMaterial,
+				h: 0.2, s: 0.2, v: 1
+			},
+
+			"dotted2" :
+			{
+				m: dottedMaterial2,
+				h: 0.1, s: 1.0, v: 1
+			}
+
+			};
+
+			return materials;
+
+		}
+
+		function createShaderMaterial( id, light, ambientLight ) {
+
+			var shader = THREE.ShaderToon[ id ];
+
+			var u = THREE.UniformsUtils.clone( shader.uniforms );
+
+			var vs = shader.vertexShader;
+			var fs = shader.fragmentShader;
+
+			var material = new THREE.ShaderMaterial( { uniforms: u, vertexShader: vs, fragmentShader: fs } );
+
+			material.uniforms.uDirLightPos.value = light.position;
+			material.uniforms.uDirLightColor.value = light.color;
+
+			material.uniforms.uAmbientLightColor.value = ambientLight.color;
+
+			return material;
+
+		}
+
+		//
+
+		function setupGui() {
+
+			var createHandler = function( id ) {
+
+				return function() {
+
+					var mat_old = materials[ current_material ];
+					mat_old.h = m_h.getValue();
+					mat_old.s = m_s.getValue();
+					mat_old.v = m_v.getValue();
+
+					current_material = id;
+
+					var mat = materials[ id ];
+					effect.material = mat.m;
+
+					m_h.setValue( mat.h );
+					m_s.setValue( mat.s );
+					m_v.setValue( mat.v );
+
+					mm.setValue( current_material );
+
+				};
+
+			};
+
+			function toggle( e ) {
+
+				if ( e.style.display === "block" )
+					e.style.display = "none";
+				else
+					e.style.display = "block";
+
+			}
+
+			effectController = {
+
+			material:   "shiny",
+
+			speed :   1.0,
+			numBlobs:   10,
+			resolution: 28,
+			isolation:  80,
+
+			floor: true,
+			wallx: false,
+			wallz: false,
+
+			hue:    0.0,
+			saturation: 0.9,
+			value:    0.3,
+
+			lhue:     0.04,
+			lsaturation: 1.0,
+			lvalue:     1.0,
+
+			lx: 0.5,
+			ly: 0.5,
+			lz: 1.0,
+
+			postprocessing: false,
+
+			h_m:  function() {
+			  for (var i = 0; i < g_m.length; i++)  toggle(g_m[ i ].domElement);
+			},
+			h_c:  function() {
+			  for (var i = 0; i < g_c.length; i++)  toggle(g_c[ i ].domElement);
+			},
+			h_pc: function() {
+			  for (var i = 0; i < g_pc.length; i++) toggle(g_pc[ i ].domElement);
+			},
+			h_do: function() {
+			  for (var i = 0; i < g_do.length; i++) toggle(g_do[ i ].domElement);
+			},
+			h_s:  function() {
+			  for (var i = 0; i < g_s.length; i++)  toggle(g_s[ i ].domElement);
+			},
+			h_r:  function() {
+			  for (var i = 0; i < g_r.length; i++)  toggle(g_r[ i ].domElement);
+			},
+
+			dummy: function() {
+			}
+
+			};
+
+			var e1, e2, e3, e4, e5, e6, h, m_h, m_s, m_v,
+			g_m = [], g_c, g_pc, g_do, g_s, g_r, mm,
+			gui = new DAT.GUI();
+
+			// material (type)
+
+			mm = gui.add( effectController, "material" );
+			mm.domElement.style.display = "none";
+
+			h = gui.add( effectController, "h_m" ).name( "Materials" );
+			setGuiHeaderStyle(h, 0, 65, 50);
+
+			for ( var m in materials ) {
+
+				effectController[ m ] = createHandler( m );
+
+				e1 = gui.add( effectController, m ).name( m );
+				setGuiElementStyle( [ e1 ], 0, 65, 50, "block" );
+				g_m.push( e1 );
+
+			}
+
+			// material (color)
+
+			h = gui.add( effectController, "h_c" ).name( "Material color" );
+
+			m_h = gui.add( effectController, "hue", 0.0, 1.0, 0.025 );
+			m_s = gui.add( effectController, "saturation", 0.0, 1.0, 0.025 );
+			m_v = gui.add( effectController, "value", 0.0, 1.0, 0.025 );
+
+			g_c = [ m_h, m_s, m_v ];
+
+			setGuiHeaderStyle( h, 20, 65, 50 );
+			setGuiElementStyle( g_c, 20, 65, 50, "block" );
+
+			// light (point)
+
+			h = gui.add(effectController, "h_pc").name("Point light color");
+
+			e1 = gui.add(effectController, "lhue", 0.0, 1.0, 0.025).name("hue");
+			e2 = gui.add(effectController, "lsaturation", 0.0, 1.0, 0.025).name("saturation");
+			e3 = gui.add(effectController, "lvalue", 0.0, 1.0, 0.025).name("value");
+
+			g_pc = [ e1, e2, e3 ];
+
+			setGuiHeaderStyle(h, 50, 65, 50);
+			setGuiElementStyle(g_pc, 50, 65, 50);
+
+			// light (directional)
+
+			h = gui.add(effectController, "h_do").name("Directional light orientation");
+
+			e1 = gui.add(effectController, "lx", -1.0, 1.0, 0.025).name("x");
+			e2 = gui.add(effectController, "ly", -1.0, 1.0, 0.025).name("y");
+			e3 = gui.add(effectController, "lz", -1.0, 1.0, 0.025).name("z");
+
+			g_do = [ e1, e2, e3 ];
+
+			setGuiHeaderStyle(h, 80, 65, 50);
+			setGuiElementStyle(g_do, 80, 65, 50);
+
+			// simulation
+
+			h = gui.add(effectController, "h_s").name("Simulation");
+
+			e1 = gui.add(effectController, "speed", 0.1, 8.0, 0.05);
+			e2 = gui.add(effectController, "numBlobs", 1, 50, 1);
+			e3 = gui.add(effectController, "resolution", 14, 40, 1);
+			e4 = gui.add(effectController, "isolation", 10, 300, 1);
+
+			e5 = gui.add(effectController, "floor");
+			e6 = gui.add(effectController, "wallx");
+			e7 = gui.add(effectController, "wallz");
+
+			e5.updateDisplay();
+			e6.updateDisplay();
+			e7.updateDisplay();
+
+			g_s = [ e1, e2, e3, e4, e5, e6, e7 ];
+
+			setGuiHeaderStyle(h, 200, 65, 50);
+			setGuiElementStyle(g_s, 200, 65, 50, "block");
+
+			// rendering
+
+			h = gui.add(effectController, "h_r").name("Rendering");
+			e1 = gui.add(effectController, "postprocessing");
+
+			g_r = [ e1 ];
+
+			setGuiHeaderStyle(h, 225, 65, 50);
+			setGuiElementStyle(g_r, 225, 65, 50, "block");
+
+			// save
+
+			//e1 = gui.add(GUI, "saveURL").name("Save to URL");
+			//setGuiHeaderStyle(e1, 250, 65, 50, "block");
+
+			gui.domElement.style.backgroundColor = "#222";
+
+			// restore material from URL
+
+			id = mm.getValue()
+			current_material = id;
+			var mat = materials[ id ];
+			effect.material = mat.m;
+
+		}
+
+
+		function setGuiHeaderStyle( g, h, s, v ) {
+
+			var color = "hsl(" + h + "," + s + "%, " + v + "%)";
+
+			g.domElement.style.borderLeft = "solid 5px " + color;
+			g.domElement.style.background = color;
+			g.domElement.style.fontWeight = "bold";
+
+		}
+
+		function setGuiElementStyle( a, h, s, v, display ) {
+
+			var s, color = "hsl(" + h + "," + s + "%, " + v + "%)";
+
+			for ( i = 0; i < a.length; i ++ ) {
+
+				s = a[ i ].domElement.style;
+				s.borderLeft = "solid 5px " + color;
+				s.display = display ? display : "none";
+
+			}
+
+		}
+
+		// this controls content of marching cubes voxel field
+
+		function updateCubes( object, time, numblobs, floor, wallx, wallz ) {
+
+			object.reset();
+
+			// fill the field with some metaballs
+
+			var i, ballx, bally, ballz, subtract, strength;
+
+			subtract = 12;
+			strength = 1.2 / ( ( Math.sqrt( numblobs ) - 1 ) / 4 + 1 );
+
+			for ( i = 0; i < numblobs; i ++ ) {
+
+				ballx = Math.sin( i + 1.26 * time * ( 1.03 + 0.5 * Math.cos( 0.21 * i ) ) ) * 0.27 + 0.5;
+				bally = Math.abs( Math.cos( i + 1.12 * time * Math.cos( 1.22 + 0.1424 * i ) ) ) * 0.77; // dip into the floor
+				ballz = Math.cos( i + 1.32 * time * 0.1 * Math.sin( ( 0.92 + 0.53 * i ) ) ) * 0.27 + 0.5;
+
+				object.addBall(ballx, bally, ballz, strength, subtract);
+
+			}
+
+			if ( floor ) object.addPlaneY( 2, 12 );
+			if ( wallz ) object.addPlaneZ( 2, 12 );
+			if ( wallx ) object.addPlaneX( 2, 12 );
+
+		}
+
+		//
+
+
+		function animate() {
+
+			requestAnimationFrame( animate );
+
+			render();
+			stats.update();
+
+		}
+
+		function render() {
+
+			var delta = clock.getDelta();
+
+			time += delta * effectController.speed * 0.5;
+
+			controls.update( delta );
+
+			// marching cubes
+
+			if ( effectController.resolution !== resolution ) {
+
+				resolution = effectController.resolution;
+				effect.init( resolution );
+
+			}
+
+			if ( effectController.isolation !== effect.isolation ) {
+
+				effect.isolation = effectController.isolation;
+
+			}
+
+			updateCubes( effect, time, effectController.numBlobs, effectController.floor, effectController.wallx, effectController.wallz );
+
+			// materials
+
+			if ( effect.material instanceof THREE.ShaderMaterial ) {
+
+				if ( current_material === "dotted2" ) {
+
+					effect.material.uniforms.uLineColor1.value.setHSV( effectController.hue, effectController.saturation, effectController.value );
+
+				} else if ( current_material === "hatching2" ) {
+
+					u = effect.material.uniforms;
+
+					u.uLineColor1.value.setHSV( effectController.hue, effectController.saturation, effectController.value );
+					u.uLineColor2.value.setHSV( effectController.hue, effectController.saturation, effectController.value );
+					u.uLineColor3.value.setHSV( effectController.hue, effectController.saturation, effectController.value );
+					u.uLineColor4.value.setHSV( ( effectController.hue + 0.2 % 1.0 ), effectController.saturation, effectController.value );
+
+				} else {
+
+					effect.material.uniforms.uBaseColor.value.setHSV( effectController.hue, effectController.saturation, effectController.value );
+
+				}
+
+			} else {
+
+				effect.material.color.setHSV( effectController.hue, effectController.saturation, effectController.value );
+
+			}
+
+			// lights
+
+			light.position.set( effectController.lx, effectController.ly, effectController.lz );
+			light.position.normalize();
+
+			pointLight.color.setHSV( effectController.lhue, effectController.lsaturation, effectController.lvalue );
+
+			// render
+
+			if ( effectController.postprocessing ) {
+
+				composer.render( delta );
+
+			} else {
+
+				renderer.clear();
+				renderer.render( scene, camera );
+
+			}
+
+		}
+
+</script>
+
+</body>
+</html>