Переглянути джерело

Merge remote-tracking branch 'remotes/zz85/experimental' into dev

alteredq 14 роки тому
батько
коміт
414d91420c

+ 1 - 1
examples/canvas_particles_shapes.html

@@ -1,7 +1,7 @@
 <!DOCTYPE HTML>
 <html lang="en">
 	<head>
-		<title>three.js canvas/webgl - geometry - text</title>
+		<title>three.js canvas - particles with shapes</title>
 		<meta charset="utf-8">
 		<meta name="viewport" content="width=device-width; initial-scale=1.0; maximum-scale=1.0; user-scalable=0;"/>
 		<style type="text/css">

+ 63 - 1
examples/js/ShaderExtras.js

@@ -12,7 +12,8 @@
  *	vignette
  *  bleachbypass
  *	basic
- *
+ *  dofmipmap
+ *  focus
  */
 
 THREE.ShaderExtras = {
@@ -734,6 +735,67 @@ THREE.ShaderExtras = {
 
 		].join("\n")
 	},
+	
+	/* -------------------------------------------------------------------------
+	//	Triangle Blur shader
+	//  - based on glfx.js triangle blur shader
+	// A basic blur filter, which convolves the image with a
+	// pyramid filter. The pyramid filter is separable and is applied as two
+	// radius The radius of the pyramid convolved with the image.
+	//		https://github.com/evanw/glfx.js
+	 ------------------------------------------------------------------------- */
+	'triangleBlur': {
+		
+		
+		uniforms : {
+
+			"texture": 		{ type: "t", value: 0, texture: null },
+			"delta": 		{ type: "v2", value:new THREE.Vector2( 1, 1 )  }
+		
+
+		},
+
+		vertexShader: [
+			 
+			"varying vec2 texCoord;",
+
+			"void main() {",
+
+				"texCoord = vec2( uv.x, 1.0 - uv.y );",
+				"gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );",
+
+			"}"
+
+		].join("\n"),
+
+		fragmentShader:[
+		"#define ITERATIONS 30.0\n" + 
+		'uniform sampler2D texture;\
+		        uniform vec2 delta;\
+		        varying vec2 texCoord;\
+		\
+		    float random(vec3 scale, float seed) {\
+		        /* use the fragment position for a different seed per-pixel */\
+		        return fract(sin(dot(gl_FragCoord.xyz + seed, scale)) * 43758.5453 + seed);\
+		    }\
+		 void main() {\
+		            vec4 color = vec4(0.0);\
+		            float total = 0.0;\
+		            \
+		            /* randomize the lookup values to hide the fixed number of samples */\
+		            float offset = random(vec3(12.9898, 78.233, 151.7182), 0.0);\
+		            \
+		            for (float t = -ITERATIONS; t <= ITERATIONS; t++) {\
+		                float percent = (t + offset - 0.5) / ITERATIONS;\
+		                float weight = 1.0 - abs(percent);\
+		                color += texture2D(texture, texCoord + delta * percent) * weight;\
+		                total += weight;\
+		            }\
+		            gl_FragColor = color / total;\
+		        }\
+		'
+		]
+	},
 
 	/* -------------------------------------------------------------------------
 	//	Simple test shader

+ 585 - 0
examples/webgl_particles_shapes.html

@@ -0,0 +1,585 @@
+<!DOCTYPE HTML>
+<html lang="en">
+	<head>
+		<title>three.js canvas/webgl - geometry - text</title>
+		<meta charset="utf-8">
+		<meta name="viewport" content="width=device-width; initial-scale=1.0; maximum-scale=1.0; user-scalable=0;"/>
+		<style type="text/css">
+			body {
+				font-family: Monospace;
+				background-color: #f0f0f0;
+				margin: 0px;
+				overflow: hidden;
+			}
+		</style>
+	</head>
+	<body>
+
+
+		<script type="text/javascript" src="../build/Three.js"></script>
+
+		<script type="text/javascript" src="js/RequestAnimationFrame.js"></script>
+		<script type="text/javascript" src="js/Stats.js"></script>
+		<script type="text/javascript" src="js/Tween.js"></script>
+		<script type="text/javascript" src="js/Sparks.js"></script>
+		
+		<script type="text/javascript" src="js/ShaderExtras.js"></script> 
+		<script type="text/javascript" src="js/postprocessing/EffectComposer.js"></script> 
+		<script type="text/javascript" src="js/postprocessing/RenderPass.js"></script> 
+		<script type="text/javascript" src="js/postprocessing/ShaderPass.js"></script> 
+		<script type="text/javascript" src="js/postprocessing/MaskPass.js"></script> 
+		<script type="text/javascript" src="js/postprocessing/BloomPass.js"></script>
+					
+		<!-- load the font file from canvas-text -->
+
+	
+		<script type="text/javascript" src="fonts/helvetiker_regular.typeface.js"></script>
+
+			<script type="x-shader/x-vertex" id="vertexshader"> 
+
+				attribute float size;
+				attribute vec4 ca;
+
+				varying vec4 vColor;
+
+				void main() {
+
+					vColor = ca;
+
+					vec4 mvPosition = modelViewMatrix * vec4( position, 1.0 );
+
+					gl_PointSize = size * ( 150.0 / length( mvPosition.xyz ) );
+
+					gl_Position = projectionMatrix * mvPosition;
+
+				}
+
+			</script> 
+
+			<script type="x-shader/x-fragment" id="fragmentshader"> 
+
+				uniform vec3 color;
+				uniform sampler2D texture;
+
+				varying vec4 vColor;
+
+
+				uniform float radius;
+
+				uniform vec2 delta;
+
+				varying vec2 texCoord;
+
+
+				void main() {
+
+					vec4 outColor = texture2D( texture, gl_PointCoord );
+
+					if ( outColor.a < 0.5 ) discard;
+
+					gl_FragColor = outColor * vec4( color * vColor.xyz, 1.0 );
+
+					//float depth = gl_FragCoord.z / gl_FragCoord.w;
+					///const vec3 fogColor = vec3( 0.0 );
+
+					//float fogFactor = smoothstep( 200.0, 600.0, depth );
+					//gl_FragColor = mix( gl_FragColor, vec4( fogColor, gl_FragColor.w ), fogFactor );
+
+				}
+
+			</script>
+
+		<script type="text/javascript">
+
+			var container, stats;
+
+			var camera, scene, renderer;
+
+			var text, plane;
+
+			var targetRotation = 0;
+			var targetRotationOnMouseDown = 0;
+
+			var mouseX = 0;
+			var mouseXOnMouseDown = 0;
+
+			var windowHalfX = window.innerWidth / 2;
+			var windowHalfY = window.innerHeight / 2;
+
+
+			var heartShape, particleCloud, sparksEmitter, emitterPos;
+			var _rotation = 0;
+			var timeOnShapePath = 0;
+
+			init();
+			animate();
+
+			function init() {
+
+				container = document.createElement( 'div' );
+				document.body.appendChild( container );
+
+				var info = document.createElement( 'div' );
+				info.style.position = 'absolute';
+				info.style.top = '10px';
+				info.style.width = '100%';
+				info.style.textAlign = 'center';
+				info.innerHTML = 'Three.js with WebGL Love. Simple Particle Systems with Shapes by <a href="http://www.lab4games.net/zz85/blog">zz85</a><br/>Move your mouse. Click to pause/resume.';
+				container.appendChild( info );
+
+				camera = new THREE.Camera( 50, window.innerWidth / window.innerHeight, 1, 1000 );
+				camera.position.y = 150;
+				camera.position.z = 700;
+				camera.target.position.y = 150;
+
+				scene = new THREE.Scene();
+
+				// Get text from hash
+
+				var theText = "THREE.JS";
+
+				var hash = document.location.hash.substr( 1 );
+
+				if ( hash.length !== 0 ) {
+
+					theText = hash;
+
+				}
+
+				var text3d = new THREE.TextGeometry( theText, {
+
+					size: 80,
+					height: 20,
+					curveSegments: 2,
+					font: "helvetiker"
+
+				});
+
+				text3d.computeBoundingBox();
+				var centerOffset = -0.5 * ( text3d.boundingBox.x[ 1 ] - text3d.boundingBox.x[ 0 ] );
+
+                var textMaterial = new THREE.MeshBasicMaterial( { color: Math.random() * 0xffffff, wireframe: false } );
+
+				text = new THREE.Mesh( text3d, textMaterial );
+				// Potentially, we can extract the vertices or faces of the text to generate particles too.
+				// Geo > Vertices > Position
+
+                text.doubleSided = false;
+
+                text.position.x = centerOffset;
+                text.position.y = 100;
+                text.position.z = 0;
+
+                text.rotation.x = 0;
+                text.rotation.y = Math.PI * 2;
+				text.overdraw = true;
+
+				parent = new THREE.Object3D();
+                parent.addChild( text );
+				scene.addObject( parent );
+
+				///// Create particle objects for Three.js
+
+
+				var particleslength = 50000;
+
+				var particles = new THREE.Geometry();
+
+				function newpos(x, y, z) {
+							return new THREE.Vertex(
+				            new THREE.Vector3(x, y, z)
+				        );
+				}
+
+
+				var Pool = {
+					__pools: [],
+
+					// Get a new Vector
+					get: function() {
+						if (this.__pools.length>0) {
+							return this.__pools.pop();
+						}
+
+						console.log("pool ran out!")
+						return null;
+
+					},
+
+					// Release a vector back into the pool
+					add: function(v) {
+						this.__pools.push(v);
+					},
+
+
+				};
+
+
+				for ( i = 0; i < particleslength; i++ ) {
+						particles.vertices.push(newpos(Math.random() *200 - 100, Math.random() *100+150, Math.random() *50));
+						Pool.add(i);
+				}
+
+
+
+
+				// Create pools of vectors
+
+				attributes = {
+
+					size: {	type: 'f', value: [] },
+					ca: { type: 'c', value: [] } //ca //customColor
+
+				};
+
+				var sprite = generateSprite() ;
+				textu = new THREE.Texture ( sprite );
+				textu.needsUpdate = true;
+
+				uniforms = {
+
+					amplitude: { type: "f", value: 1.0 },
+					color:     { type: "c", value: new THREE.Color( 0xffffff ) },
+					texture:   { type: "t", value: 0, texture:textu} //
+					// 
+
+
+				};
+
+				// PARAMS. 
+				// Steadycounter
+				// Life
+				// Opacity 
+				// Hue Speed
+				// Movement Speed
+
+				function generateSprite() {
+
+					var canvas = document.createElement( 'canvas' );
+					canvas.width = 128;
+					canvas.height = 128;
+
+					var context = canvas.getContext( '2d' );
+
+
+					// Just a square, doesnt work too bad with blur pp.			
+					// context.fillStyle = "white";
+					// context.strokeStyle = "white";				
+					// context.fillRect(0, 0, 63, 63) ;
+
+					// Heart Shapes are not too pretty here
+					// var x = 4, y = 0;
+					// context.save();
+					// context.scale(8, 8); // Scale so canvas render can redraw within bounds
+					// context.beginPath();
+					// context.bezierCurveTo( x + 2.5, y + 2.5, x + 2.0, y, x, y );
+					// context.bezierCurveTo( x - 3.0, y, x - 3.0, y + 3.5,x - 3.0,y + 3.5 );
+					// context.bezierCurveTo( x - 3.0, y + 5.5, x - 1.0, y + 7.7, x + 2.5, y + 9.5 );
+					// context.bezierCurveTo( x + 6.0, y + 7.7, x + 8.0, y + 5.5, x + 8.0, y + 3.5 );
+					// context.bezierCurveTo( x + 8.0, y + 3.5, x + 8.0, y, x + 5.0, y );
+					// context.bezierCurveTo( x + 3.5, y, x + 2.5, y + 2.5, x + 2.5, y + 2.5 );
+					// context.closePath();
+
+					context.beginPath();
+					context.arc(64, 64, 60, 0, Math.PI*2, false);
+					context.closePath();
+
+					context.lineWidth = 0.5; //0.05
+					context.stroke();
+					context.restore();
+					var gradient = context.createRadialGradient( canvas.width /2, canvas.height /2, 0, canvas.width /2, canvas.height /2, canvas.width /2 );
+
+					gradient.addColorStop( 0, 'rgba(255,255,255,1)' );
+					gradient.addColorStop( 0.2, 'rgba(255,255,255,1)' );
+					//gradient.addColorStop( 0.6, 'rgba(200,200,200,1)' );
+					gradient.addColorStop( 0.4, 'rgba(128,128,128,1)' );
+					gradient.addColorStop( 1, 'rgba(0,0,0,1)' );
+
+
+					context.fillStyle = gradient;
+
+					context.fill();
+
+
+					//var idata =context.getImageData(0, 0, canvas.width, canvas.height);
+					//document.body.appendChild(canvas);
+					return canvas;
+
+				}
+
+
+				var shaderMaterial = new THREE.MeshShaderMaterial( {
+
+					uniforms: 		uniforms,
+					attributes:     attributes,
+
+					vertexShader:   document.getElementById( 'vertexshader' ).textContent,
+					fragmentShader: document.getElementById( 'fragmentshader' ).textContent
+					,
+					blending: 		THREE.AdditiveBlending,
+					depthTest: 		false,
+					transparent:	true
+
+				});
+
+				particleCloud = new THREE.ParticleSystem( particles, shaderMaterial );
+
+				particleCloud.dynamic = true;
+				//particleCloud.sortParticles = true;
+
+				var vertices = particleCloud.geometry.vertices;
+				var values_size = attributes.size.value;
+				var values_color = attributes.ca.value;
+
+				for( var v = 0; v < vertices.length; v++ ) {
+
+					values_size[ v ] = 50;
+					values_color[ v ] = new THREE.Color( 0xaaff00 );
+					values_color[ v ].setHSV( 0, 0, 0 );
+					particles.vertices[v].position.set(Number.POSITIVE_INFINITY,Number.POSITIVE_INFINITY, Number.POSITIVE_INFINITY);
+
+				}
+
+				parent.addChild( particleCloud );
+				//scene.addObject( particleCloud );
+				particleCloud.y = 800;
+
+
+
+				// Create Particle Systems
+				// EMITTER STUFF
+
+				// Heart
+
+				var x = 0, y = 0;
+
+				heartShape = new THREE.Shape();
+
+				heartShape.moveTo( x + 25, y + 25 );
+				heartShape.bezierCurveTo( x + 25, y + 25, x + 20, y, x, y );
+				heartShape.bezierCurveTo( x - 30, y, x - 30, y + 35,x - 30,y + 35 );
+				heartShape.bezierCurveTo( x - 30, y + 55, x - 10, y + 77, x + 25, y + 95 );
+				heartShape.bezierCurveTo( x + 60, y + 77, x + 80, y + 55, x + 80, y + 35 );
+				heartShape.bezierCurveTo( x + 80, y + 35, x + 80, y, x + 50, y );
+				heartShape.bezierCurveTo( x + 35, y, x + 25, y + 25, x + 25, y + 25 );
+
+
+				var hue = 0;
+
+				var setTargetParticle = function() {
+
+					var target = Pool.get();
+					values_size[target] = Math.random() * 200 + 100;
+
+					return target;
+
+				};
+
+				var onParticleCreated = function(p) {
+					var position = p.position;
+					p.target.position = position;
+
+					var target = p.target;
+					if (target) {
+						//console.log(target,particles.vertices[target]);
+						//values_size[target]
+						//values_color[target]
+
+						hue += 0.0006;
+						if (hue>1) hue-=1;
+
+						// TODO Create a PointOnShape Action/Zone in the particle engine
+						timeOnShapePath += 0.002;
+						if (timeOnShapePath > 1) timeOnShapePath -= 1;
+						var pointOnShape = heartShape.getPointAt(timeOnShapePath);
+
+						emitterpos.x = pointOnShape.x * 5 - 100;
+						emitterpos.y = -pointOnShape.y * 5 + 400;
+
+						particles.vertices[target].position = p.position;
+
+						values_color[target].setHSV(hue, 0.8, 0.15);
+
+					}; 
+
+				};
+
+				var onParticleDead = function(particle) {
+						var target = particle.target;
+						if (target) {
+							// Hide the particle
+							values_color[target].setHSV(0, 0, 0);
+							particles.vertices[target].position.set(Number.POSITIVE_INFINITY,Number.POSITIVE_INFINITY, Number.POSITIVE_INFINITY);
+
+							// Mark particle system as available by returning to pool
+							Pool.add(particle.target);
+						}
+
+				};
+
+				var engineLoopUpdate = function() {
+
+				};
+
+
+				sparksEmitter = new SPARKS.Emitter(new SPARKS.SteadyCounter(600));
+
+				emitterpos = new THREE.Vector3(0,0,0);
+
+				sparksEmitter.addInitializer(new SPARKS.Position( new SPARKS.PointZone( emitterpos ) ) );
+				sparksEmitter.addInitializer(new SPARKS.Lifetime(1,4));
+				sparksEmitter.addInitializer(new SPARKS.Target(null, setTargetParticle));
+
+
+				sparksEmitter.addInitializer(new SPARKS.Velocity(new SPARKS.PointZone(new THREE.Vector3(0,-50,10))));
+				// TOTRY Set velocity to move away from centroid
+
+				sparksEmitter.addAction(new SPARKS.Age());
+				sparksEmitter.addAction(new SPARKS.Accelerate(0,0,50));
+				sparksEmitter.addAction(new SPARKS.Move()); 
+				sparksEmitter.addAction(new SPARKS.RandomDrift(50,50,2000));
+
+
+				sparksEmitter.addCallback("created", onParticleCreated);
+				sparksEmitter.addCallback("dead", onParticleDead);
+				sparksEmitter.start();
+
+				//sparksEmitter.addCallback("loopUpdated", engineLoopUpdate);
+
+				//sparksEmitter.addCallback("updated", function(p) {
+					// var target = particle.target;
+					// 					if (target) {
+					// 						// update energy properties
+					// 						//values_size[target] = Math.random()*100;
+					// 					}
+				//});
+				// 			
+				// End Particles
+
+
+				renderer = new THREE.WebGLRenderer();
+                renderer.setSize( window.innerWidth, window.innerHeight );
+
+				container.appendChild( renderer.domElement );
+
+				stats = new Stats();
+				stats.domElement.style.position = 'absolute';
+				stats.domElement.style.top = '0px';
+				container.appendChild( stats.domElement );
+
+				// POST PROCESSING
+					var shaderFocus = THREE.ShaderExtras[ "focus" ];
+					var effectFocus = new THREE.ShaderPass( shaderFocus );
+
+					var shaderBlur = THREE.ShaderExtras[ "triangleBlur" ];
+					var effectBlur = new THREE.ShaderPass( shaderBlur, 'texture' );; //
+					var blurAmount = 0.0020;
+					effectBlur.uniforms['delta'].value = new THREE.Vector2(blurAmount,blurAmount);
+					effectFocus.uniforms['sampleDistance'].value = 0.99; //0.94 
+					effectFocus.uniforms['waveFactor'].value = 0.002;  //0.00125
+
+					var renderScene = new THREE.RenderPass( scene, camera );
+
+					composer = new THREE.EffectComposer( renderer );
+					composer.addPass( renderScene );
+					composer.addPass( effectBlur ); // effectBlur  effectFocus
+
+					effectBlur.renderToScreen = true;
+					effectFocus.renderToScreen = true;
+
+				document.addEventListener( 'mousedown', onDocumentMouseDown, false );
+				document.addEventListener( 'touchstart', onDocumentTouchStart, false );
+				document.addEventListener( 'touchmove', onDocumentTouchMove, false );
+
+			}
+
+			//
+
+			document.addEventListener( 'mousemove', onDocumentMouseMove, false );
+
+
+			function onDocumentMouseDown( event ) {
+
+				event.preventDefault();
+
+				mouseXOnMouseDown = event.clientX - windowHalfX;
+				targetRotationOnMouseDown = targetRotation;
+
+				if (sparksEmitter.isRunning()) {
+					sparksEmitter.stop();
+				} else {
+					sparksEmitter.start();
+				}
+
+			}
+
+			function onDocumentMouseMove( event ) {
+
+				mouseX = event.clientX - windowHalfX;
+
+				targetRotation = targetRotationOnMouseDown + ( mouseX - mouseXOnMouseDown ) * 0.02;
+
+			}
+
+			function onDocumentTouchStart( event ) {
+
+				if ( event.touches.length == 1 ) {
+
+					event.preventDefault();
+
+					mouseXOnMouseDown = event.touches[ 0 ].pageX - windowHalfX;
+					targetRotationOnMouseDown = targetRotation;
+
+				}
+
+			}
+
+			function onDocumentTouchMove( event ) {
+
+				if ( event.touches.length == 1 ) {
+
+					event.preventDefault();
+
+					mouseX = event.touches[ 0 ].pageX - windowHalfX;
+					targetRotation = targetRotationOnMouseDown + ( mouseX - mouseXOnMouseDown ) * 0.05;
+
+				}
+
+			}
+
+			//
+
+			function animate() {
+
+				requestAnimationFrame( animate );
+
+				render();
+				stats.update();
+
+			}
+
+
+
+			function render() {
+
+				particleCloud.geometry.__dirtyVertices = true;
+				particleCloud.geometry.__dirtyColors = true;
+				attributes.size.needsUpdate = true;
+				attributes.ca.needsUpdate = true;
+
+
+
+				// Pretty cool effect if you enable this
+				//particleCloud.rotation.y += 0.05;
+
+				parent.rotation.y += ( targetRotation - parent.rotation.y ) * 0.05;
+				//renderer.render( scene, camera );
+				composer.render( );
+
+
+			}
+
+		</script>
+
+	</body>
+</html>