Pārlūkot izejas kodu

Merge pull request #11531 from sunag/86dev

SpriteNodeMaterial and example
Mr.doob 8 gadi atpakaļ
vecāks
revīzija
aef4f28db8

+ 1 - 0
examples/files.js

@@ -246,6 +246,7 @@ var files = {
 		"webgl_simple_gi",
 		"webgl_skinning_simple",
 		"webgl_sprites",
+		"webgl_sprites_nodes",
 		"webgl_terrain_dynamic",
 		"webgl_test_memory",
 		"webgl_test_memory2",

+ 27 - 27
examples/js/nodes/materials/PhongNode.js

@@ -2,7 +2,7 @@
  * @author sunag / http://www.sunag.com.br/
  */
 
-THREE.PhongNode = function() {
+THREE.PhongNode = function () {
 
 	THREE.GLNode.call( this );
 
@@ -15,7 +15,7 @@ THREE.PhongNode = function() {
 THREE.PhongNode.prototype = Object.create( THREE.GLNode.prototype );
 THREE.PhongNode.prototype.constructor = THREE.PhongNode;
 
-THREE.PhongNode.prototype.build = function( builder ) {
+THREE.PhongNode.prototype.build = function ( builder ) {
 
 	var material = builder.material;
 	var code;
@@ -27,7 +27,7 @@ THREE.PhongNode.prototype.build = function( builder ) {
 
 	if ( builder.isShader( 'vertex' ) ) {
 
-		var transform = this.transform ? this.transform.parseAndBuildCode( builder, 'v3', { cache : 'transform' } ) : undefined;
+		var transform = this.transform ? this.transform.parseAndBuildCode( builder, 'v3', { cache: 'transform' } ) : undefined;
 
 		material.mergeUniform( THREE.UniformsUtils.merge( [
 
@@ -46,7 +46,7 @@ THREE.PhongNode.prototype.build = function( builder ) {
 			"#endif",
 
 			THREE.ShaderChunk[ "common" ],
-			THREE.ShaderChunk[ "fog_parse_vertex" ],
+			THREE.ShaderChunk[ "fog_pars_vertex" ],
 			THREE.ShaderChunk[ "morphtarget_pars_vertex" ],
 			THREE.ShaderChunk[ "skinning_pars_vertex" ],
 			THREE.ShaderChunk[ "shadowmap_pars_vertex" ],
@@ -55,11 +55,11 @@ THREE.PhongNode.prototype.build = function( builder ) {
 		].join( "\n" ) );
 
 		var output = [
-				THREE.ShaderChunk[ "beginnormal_vertex" ],
-				THREE.ShaderChunk[ "morphnormal_vertex" ],
-				THREE.ShaderChunk[ "skinbase_vertex" ],
-				THREE.ShaderChunk[ "skinnormal_vertex" ],
-				THREE.ShaderChunk[ "defaultnormal_vertex" ],
+			THREE.ShaderChunk[ "beginnormal_vertex" ],
+			THREE.ShaderChunk[ "morphnormal_vertex" ],
+			THREE.ShaderChunk[ "skinbase_vertex" ],
+			THREE.ShaderChunk[ "skinnormal_vertex" ],
+			THREE.ShaderChunk[ "defaultnormal_vertex" ],
 
 			"#ifndef FLAT_SHADED", // Normal computed with derivatives when FLAT_SHADED
 
@@ -67,8 +67,7 @@ THREE.PhongNode.prototype.build = function( builder ) {
 
 			"#endif",
 
-				THREE.ShaderChunk[ "begin_vertex" ],
-				THREE.ShaderChunk[ "fog_vertex" ]
+			THREE.ShaderChunk[ "begin_vertex" ]
 		];
 
 		if ( transform ) {
@@ -84,6 +83,7 @@ THREE.PhongNode.prototype.build = function( builder ) {
 				THREE.ShaderChunk[ "morphtarget_vertex" ],
 				THREE.ShaderChunk[ "skinning_vertex" ],
 				THREE.ShaderChunk[ "project_vertex" ],
+				THREE.ShaderChunk[ "fog_vertex" ],
 				THREE.ShaderChunk[ "logdepthbuf_vertex" ],
 
 			"	vViewPosition = - mvPosition.xyz;",
@@ -98,44 +98,44 @@ THREE.PhongNode.prototype.build = function( builder ) {
 
 		// parse all nodes to reuse generate codes
 
-		this.color.parse( builder, { slot : 'color' } );
+		this.color.parse( builder, { slot: 'color' } );
 		this.specular.parse( builder );
 		this.shininess.parse( builder );
 
 		if ( this.alpha ) this.alpha.parse( builder );
-		
+
 		if ( this.normal ) this.normal.parse( builder );
 		if ( this.normalScale && this.normal ) this.normalScale.parse( builder );
-		
-		if ( this.light ) this.light.parse( builder, { cache : 'light' } );
+
+		if ( this.light ) this.light.parse( builder, { cache: 'light' } );
 
 		if ( this.ao ) this.ao.parse( builder );
 		if ( this.ambient ) this.ambient.parse( builder );
 		if ( this.shadow ) this.shadow.parse( builder );
-		if ( this.emissive ) this.emissive.parse( builder, { slot : 'emissive' } );
+		if ( this.emissive ) this.emissive.parse( builder, { slot: 'emissive' } );
 
-		if ( this.environment ) this.environment.parse( builder, { slot : 'environment' } );
+		if ( this.environment ) this.environment.parse( builder, { slot: 'environment' } );
 		if ( this.environmentAlpha && this.environment ) this.environmentAlpha.parse( builder );
 
 		// build code
 
-		var color = this.color.buildCode( builder, 'c', { slot : 'color' } );
+		var color = this.color.buildCode( builder, 'c', { slot: 'color' } );
 		var specular = this.specular.buildCode( builder, 'c' );
 		var shininess = this.shininess.buildCode( builder, 'fv1' );
 
 		var alpha = this.alpha ? this.alpha.buildCode( builder, 'fv1' ) : undefined;
-		
+
 		var normal = this.normal ? this.normal.buildCode( builder, 'v3' ) : undefined;
 		var normalScale = this.normalScale && this.normal ? this.normalScale.buildCode( builder, 'v2' ) : undefined;
-		
-		var light = this.light ? this.light.buildCode( builder, 'v3', { cache : 'light' } ) : undefined;
+
+		var light = this.light ? this.light.buildCode( builder, 'v3', { cache: 'light' } ) : undefined;
 
 		var ao = this.ao ? this.ao.buildCode( builder, 'fv1' ) : undefined;
 		var ambient = this.ambient ? this.ambient.buildCode( builder, 'c' ) : undefined;
 		var shadow = this.shadow ? this.shadow.buildCode( builder, 'c' ) : undefined;
-		var emissive = this.emissive ? this.emissive.buildCode( builder, 'c', { slot : 'emissive' } ) : undefined;
+		var emissive = this.emissive ? this.emissive.buildCode( builder, 'c', { slot: 'emissive' } ) : undefined;
 
-		var environment = this.environment ? this.environment.buildCode( builder, 'c', { slot : 'environment' } ) : undefined;
+		var environment = this.environment ? this.environment.buildCode( builder, 'c', { slot: 'environment' } ) : undefined;
 		var environmentAlpha = this.environmentAlpha && this.environment ? this.environmentAlpha.buildCode( builder, 'fv1' ) : undefined;
 
 		material.requestAttribs.transparent = alpha != undefined;
@@ -152,17 +152,17 @@ THREE.PhongNode.prototype.build = function( builder ) {
 
 		var output = [
 				// prevent undeclared normal
-				THREE.ShaderChunk[ "normal_flip" ],
-				THREE.ShaderChunk[ "normal_fragment" ],
+			THREE.ShaderChunk[ "normal_flip" ],
+			THREE.ShaderChunk[ "normal_fragment" ],
 
 				// prevent undeclared material
 			"	BlinnPhongMaterial material;",
 
-				color.code,
+			color.code,
 			"	vec3 diffuseColor = " + color.result + ";",
 			"	ReflectedLight reflectedLight = ReflectedLight( vec3( 0.0 ), vec3( 0.0 ), vec3( 0.0 ), vec3( 0.0 ) );",
 
-				THREE.ShaderChunk[ "logdepthbuf_fragment" ],
+			THREE.ShaderChunk[ "logdepthbuf_fragment" ],
 
 			specular.code,
 			"	vec3 specular = " + specular.result + ";",

+ 150 - 0
examples/js/nodes/materials/SpriteNode.js

@@ -0,0 +1,150 @@
+/**
+ * @author sunag / http://www.sunag.com.br/
+ */
+
+THREE.SpriteNode = function () {
+
+	THREE.GLNode.call( this );
+
+	this.color = new THREE.ColorNode( 0xEEEEEE );
+	this.spherical = true;
+
+};
+
+THREE.SpriteNode.prototype = Object.create( THREE.GLNode.prototype );
+THREE.SpriteNode.prototype.constructor = THREE.SpriteNode;
+
+THREE.SpriteNode.prototype.build = function ( builder ) {
+
+	var material = builder.material;
+	var output, code;
+
+	material.define( 'SPRITE' );
+
+	material.requestAttribs.light = false;
+	material.requestAttribs.transparent = this.alpha != undefined;
+
+	if ( builder.isShader( 'vertex' ) ) {
+
+		var transform = this.transform ? this.transform.parseAndBuildCode( builder, 'v3', { cache: 'transform' } ) : undefined;
+
+		material.mergeUniform( THREE.UniformsUtils.merge( [
+			THREE.UniformsLib[ "fog" ]
+		] ) );
+
+		material.addVertexPars( [
+			THREE.ShaderChunk[ "fog_pars_vertex" ],
+		].join( "\n" ) );
+
+		output = [
+			THREE.ShaderChunk[ "begin_vertex" ]
+		];
+
+		if ( transform ) {
+
+			output.push(
+				transform.code,
+				"transformed = " + transform.result + ";"
+			);
+
+		}
+
+		output.push(
+
+			THREE.ShaderChunk[ "project_vertex" ],
+			THREE.ShaderChunk[ "fog_vertex" ],
+
+			'mat4 modelViewMtx = modelViewMatrix;',
+			'mat4 modelMtx = modelMatrix;',
+
+			// ignore position from modelMatrix (use vary position)
+			'modelMtx[3][0] = 0.0;',
+			'modelMtx[3][1] = 0.0;',
+			'modelMtx[3][2] = 0.0;'
+		);
+
+		if ( ! this.spherical ) {
+
+			output.push(
+
+			'modelMtx[1][1] = 1.0;'
+
+			);
+
+		}
+
+		output.push(
+			// http://www.geeks3d.com/20140807/billboarding-vertex-shader-glsl/
+			// First colunm.
+			'modelViewMtx[0][0] = 1.0;',
+			'modelViewMtx[0][1] = 0.0;',
+			'modelViewMtx[0][2] = 0.0;'
+
+		);
+
+		if ( this.spherical ) {
+
+			output.push(
+
+				// Second colunm.
+				'modelViewMtx[1][0] = 0.0;',
+				'modelViewMtx[1][1] = 1.0;',
+				'modelViewMtx[1][2] = 0.0;'
+
+			);
+
+		}
+
+		output.push(
+
+			// Thrid colunm.
+			'modelViewMtx[2][0] = 0.0;',
+			'modelViewMtx[2][1] = 0.0;',
+			'modelViewMtx[2][2] = 1.0;',
+
+			// apply
+			'gl_Position = projectionMatrix * modelViewMtx * modelMtx * vec4( position, 1.0 );'
+		);
+
+		code = output.join( "\n" );
+
+	} else {
+
+		material.addFragmentPars( [
+			THREE.ShaderChunk[ "fog_pars_fragment" ]
+		].join( "\n" ) );
+
+		// parse all nodes to reuse generate codes
+
+		this.color.parse( builder, { slot: 'color' } );
+		if ( this.alpha ) this.alpha.parse( builder );
+
+		// build code
+
+		var color = this.color.buildCode( builder, 'c', { slot: 'color' } );
+		var alpha = this.alpha ? this.alpha.buildCode( builder, 'fv1' ) : undefined;
+
+		output = [ color.code ];
+
+		if ( alpha ) {
+
+			output.push(
+				alpha.code,
+				"gl_FragColor = vec4( " + color.result + ", " + alpha.result + " );"
+			);
+
+		} else {
+
+			output.push( "gl_FragColor = vec4( " + color.result + ", 1.0 );" );
+
+		}
+
+		output.push( THREE.ShaderChunk[ "fog_fragment" ] );
+
+		code = output.join( "\n" );
+
+	}
+
+	return code;
+
+};

+ 17 - 0
examples/js/nodes/materials/SpriteNodeMaterial.js

@@ -0,0 +1,17 @@
+/**
+ * @author sunag / http://www.sunag.com.br/
+ */
+
+THREE.SpriteNodeMaterial = function () {
+
+	this.node = new THREE.SpriteNode();
+
+	THREE.NodeMaterial.call( this, this.node, this.node );
+
+};
+
+THREE.SpriteNodeMaterial.prototype = Object.create( THREE.NodeMaterial.prototype );
+THREE.SpriteNodeMaterial.prototype.constructor = THREE.SpriteNodeMaterial;
+
+THREE.NodeMaterial.addShortcuts( THREE.SpriteNodeMaterial.prototype, 'node',
+[ 'color', 'alpha', 'transform', 'spherical' ] );

+ 49 - 49
examples/js/nodes/materials/StandardNode.js

@@ -2,7 +2,7 @@
  * @author sunag / http://www.sunag.com.br/
  */
 
-THREE.StandardNode = function() {
+THREE.StandardNode = function () {
 
 	THREE.GLNode.call( this );
 
@@ -15,14 +15,14 @@ THREE.StandardNode = function() {
 THREE.StandardNode.prototype = Object.create( THREE.GLNode.prototype );
 THREE.StandardNode.prototype.constructor = THREE.StandardNode;
 
-THREE.StandardNode.prototype.build = function( builder ) {
+THREE.StandardNode.prototype.build = function ( builder ) {
 
 	var material = builder.material;
 	var code;
 
 	material.define( 'PHYSICAL' );
 
-	if ( !this.clearCoat && !this.clearCoatRoughness ) material.define( 'STANDARD' );
+	if ( ! this.clearCoat && ! this.clearCoatRoughness ) material.define( 'STANDARD' );
 
 	material.define( 'ALPHATEST', '0.0' );
 
@@ -32,7 +32,7 @@ THREE.StandardNode.prototype.build = function( builder ) {
 
 	if ( builder.isShader( 'vertex' ) ) {
 
-		var transform = this.transform ? this.transform.parseAndBuildCode( builder, 'v3', { cache : 'transform' } ) : undefined;
+		var transform = this.transform ? this.transform.parseAndBuildCode( builder, 'v3', { cache: 'transform' } ) : undefined;
 
 		material.mergeUniform( THREE.UniformsUtils.merge( [
 
@@ -72,8 +72,7 @@ THREE.StandardNode.prototype.build = function( builder ) {
 
 			"#endif",
 
-			THREE.ShaderChunk[ "begin_vertex" ],
-			THREE.ShaderChunk[ "fog_vertex" ]        
+			THREE.ShaderChunk[ "begin_vertex" ]
 		];
 
 		if ( transform ) {
@@ -89,6 +88,7 @@ THREE.StandardNode.prototype.build = function( builder ) {
 			THREE.ShaderChunk[ "morphtarget_vertex" ],
 			THREE.ShaderChunk[ "skinning_vertex" ],
 			THREE.ShaderChunk[ "project_vertex" ],
+			THREE.ShaderChunk[ "fog_vertex" ],
 			THREE.ShaderChunk[ "logdepthbuf_vertex" ],
 
 			"	vViewPosition = - mvPosition.xyz;",
@@ -104,64 +104,64 @@ THREE.StandardNode.prototype.build = function( builder ) {
 		// blur textures for PBR effect
 
 		var requires = {
-			bias : new THREE.RoughnessToBlinnExponentNode(),
-			offsetU : 0,
-			offsetV : 0
+			bias: new THREE.RoughnessToBlinnExponentNode(),
+			offsetU: 0,
+			offsetV: 0
 		};
 
-		var useClearCoat = !material.isDefined( 'STANDARD' );
-		
+		var useClearCoat = ! material.isDefined( 'STANDARD' );
+
 		// parse all nodes to reuse generate codes
 
-		this.color.parse( builder, { slot : 'color' } );
+		this.color.parse( builder, { slot: 'color' } );
 		this.roughness.parse( builder );
 		this.metalness.parse( builder );
 
 		if ( this.alpha ) this.alpha.parse( builder );
-		
+
 		if ( this.normal ) this.normal.parse( builder );
 		if ( this.normalScale && this.normal ) this.normalScale.parse( builder );
-		
-		if (this.clearCoat) this.clearCoat.parse( builder );
-		if (this.clearCoatRoughness) this.clearCoatRoughness.parse( builder );
-		
+
+		if ( this.clearCoat ) this.clearCoat.parse( builder );
+		if ( this.clearCoatRoughness ) this.clearCoatRoughness.parse( builder );
+
 		if ( this.reflectivity ) this.reflectivity.parse( builder );
 
-		if ( this.light ) this.light.parse( builder, { cache : 'light' } );
+		if ( this.light ) this.light.parse( builder, { cache: 'light' } );
 
 		if ( this.ao ) this.ao.parse( builder );
 		if ( this.ambient ) this.ambient.parse( builder );
 		if ( this.shadow ) this.shadow.parse( builder );
-		if ( this.emissive ) this.emissive.parse( builder, { slot : 'emissive' } );
+		if ( this.emissive ) this.emissive.parse( builder, { slot: 'emissive' } );
 
-		if ( this.environment ) this.environment.parse( builder, { cache : 'env', requires : requires, slot : 'environment' } ); // isolate environment from others inputs ( see TextureNode, CubeTextureNode )
+		if ( this.environment ) this.environment.parse( builder, { cache: 'env', requires: requires, slot: 'environment' } ); // isolate environment from others inputs ( see TextureNode, CubeTextureNode )
 
 		// build code
 
-		var color = this.color.buildCode( builder, 'c', { slot : 'color' } );
+		var color = this.color.buildCode( builder, 'c', { slot: 'color' } );
 		var roughness = this.roughness.buildCode( builder, 'fv1' );
 		var metalness = this.metalness.buildCode( builder, 'fv1' );
 
 		var alpha = this.alpha ? this.alpha.buildCode( builder, 'fv1' ) : undefined;
-		
+
 		var normal = this.normal ? this.normal.buildCode( builder, 'v3' ) : undefined;
 		var normalScale = this.normalScale && this.normal ? this.normalScale.buildCode( builder, 'v2' ) : undefined;
-		
+
 		var clearCoat = this.clearCoat ? this.clearCoat.buildCode( builder, 'fv1' ) : undefined;
 		var clearCoatRoughness = this.clearCoatRoughness ? this.clearCoatRoughness.buildCode( builder, 'fv1' ) : undefined;
-		
+
 		var reflectivity = this.reflectivity ? this.reflectivity.buildCode( builder, 'fv1' ) : undefined;
 
-		var light = this.light ? this.light.buildCode( builder, 'v3', { cache : 'light' } ) : undefined;
+		var light = this.light ? this.light.buildCode( builder, 'v3', { cache: 'light' } ) : undefined;
 
 		var ao = this.ao ? this.ao.buildCode( builder, 'fv1' ) : undefined;
 		var ambient = this.ambient ? this.ambient.buildCode( builder, 'c' ) : undefined;
 		var shadow = this.shadow ? this.shadow.buildCode( builder, 'c' ) : undefined;
-		var emissive = this.emissive ? this.emissive.buildCode( builder, 'c', { slot : 'emissive' } ) : undefined;
+		var emissive = this.emissive ? this.emissive.buildCode( builder, 'c', { slot: 'emissive' } ) : undefined;
 
-		var environment = this.environment ? this.environment.buildCode( builder, 'c', { cache : 'env', requires : requires, slot : 'environment' } ) : undefined;
+		var environment = this.environment ? this.environment.buildCode( builder, 'c', { cache: 'env', requires: requires, slot: 'environment' } ) : undefined;
 
-		var clearCoatEnv = useClearCoat && environment ? this.environment.buildCode( builder, 'c', { cache : 'clearCoat', requires : requires, slot : 'environment' } ) : undefined;
+		var clearCoatEnv = useClearCoat && environment ? this.environment.buildCode( builder, 'c', { cache: 'clearCoat', requires: requires, slot: 'environment' } ) : undefined;
 
 		material.requestAttribs.transparent = alpha != undefined;
 
@@ -186,18 +186,18 @@ THREE.StandardNode.prototype.build = function( builder ) {
 
 		var output = [
 				// prevent undeclared normal
-				THREE.ShaderChunk[ "normal_flip" ],
-				THREE.ShaderChunk[ "normal_fragment" ],
+			THREE.ShaderChunk[ "normal_flip" ],
+			THREE.ShaderChunk[ "normal_fragment" ],
 
 				// prevent undeclared material
 			"	PhysicalMaterial material;",
 			"	material.diffuseColor = vec3( 1.0 );",
 
-				color.code,
+			color.code,
 			"	vec3 diffuseColor = " + color.result + ";",
 			"	ReflectedLight reflectedLight = ReflectedLight( vec3( 0.0 ), vec3( 0.0 ), vec3( 0.0 ), vec3( 0.0 ) );",
 
-				THREE.ShaderChunk[ "logdepthbuf_fragment" ],
+			THREE.ShaderChunk[ "logdepthbuf_fragment" ],
 
 			roughness.code,
 			"	float roughnessFactor = " + roughness.result + ";",
@@ -240,33 +240,33 @@ THREE.StandardNode.prototype.build = function( builder ) {
 			// accumulation
 			'material.specularRoughness = clamp( roughnessFactor, DEFAULT_SPECULAR_COEFFICIENT, 1.0 );' // disney's remapping of [ 0, 1 ] roughness to [ 0.001, 1 ]
 		);
-		
-		if (clearCoat) {
-			
+
+		if ( clearCoat ) {
+
 			output.push(
 				clearCoat.code,
 				'material.clearCoat = saturate( ' + clearCoat.result + ' );'
 			);
-			
-		} else if (useClearCoat) {
-			
+
+		} else if ( useClearCoat ) {
+
 			output.push( 'material.clearCoat = 0.0;' );
-			
+
 		}
-		
-		if (clearCoatRoughness) {
-			
+
+		if ( clearCoatRoughness ) {
+
 			output.push(
 				clearCoatRoughness.code,
 				'material.clearCoatRoughness = clamp( ' + clearCoatRoughness.result + ', DEFAULT_SPECULAR_COEFFICIENT, 1.0 );'
 			);
-			
-		} else if (useClearCoat) {
-			
+
+		} else if ( useClearCoat ) {
+
 			output.push( 'material.clearCoatRoughness = 0.0;' );
-			
+
 		}
-		
+
 		if ( reflectivity ) {
 
 			output.push(
@@ -347,7 +347,7 @@ THREE.StandardNode.prototype.build = function( builder ) {
 
 			output.push( environment.code );
 
-			if (clearCoatEnv) {
+			if ( clearCoatEnv ) {
 
 				output.push(
 					clearCoatEnv.code,
@@ -356,7 +356,7 @@ THREE.StandardNode.prototype.build = function( builder ) {
 
 			} else {
 
-				output.push("vec3 clearCoatRadiance = vec3( 0.0 );");
+				output.push( "vec3 clearCoatRadiance = vec3( 0.0 );" );
 
 			}
 

BIN
examples/textures/WalkingManSpriteSheet.png


+ 271 - 0
examples/webgl_sprites_nodes.html

@@ -0,0 +1,271 @@
+<!DOCTYPE html>
+<html lang="en">
+	<head>
+		<title>three.js webgl - sprites nodes</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 {
+				color: #fff;
+				font-family:Monospace;
+				font-size:13px;
+				margin: 0px;
+				text-align:center;
+				overflow: hidden;
+			}
+
+			#info {
+				color: #fff;
+				position: absolute;
+				top: 10px;
+				width: 100%;
+				text-align: center;
+				display:block;
+			}
+
+			a { color: white }
+		</style>
+	</head>
+	<body>
+
+		<div id="container"></div>
+		<div id="info">
+			<a href="http://threejs.org" target="_blank" rel="noopener">three.js</a> - Node-Based Sprites
+		</div>
+
+		<script src="../build/three.js"></script>
+
+		<script src='js/geometries/TeapotBufferGeometry.js'></script>
+		<script src="js/controls/OrbitControls.js"></script>
+		<script src="js/libs/dat.gui.min.js"></script>
+
+		<!-- NodeLibrary -->
+		<script src="js/nodes/GLNode.js"></script>
+		<script src="js/nodes/RawNode.js"></script>
+		<script src="js/nodes/TempNode.js"></script>
+		<script src="js/nodes/InputNode.js"></script>
+		<script src="js/nodes/ConstNode.js"></script>
+		<script src="js/nodes/VarNode.js"></script>
+		<script src="js/nodes/FunctionNode.js"></script>
+		<script src="js/nodes/FunctionCallNode.js"></script>
+		<script src="js/nodes/AttributeNode.js"></script>
+		<script src="js/nodes/NodeBuilder.js"></script>
+		<script src="js/nodes/NodeLib.js"></script>
+		<script src="js/nodes/NodeMaterial.js"></script>
+
+		<!-- Accessors -->
+		<script src="js/nodes/accessors/PositionNode.js"></script>
+		<script src="js/nodes/accessors/NormalNode.js"></script>
+		<script src="js/nodes/accessors/UVNode.js"></script>
+		<script src="js/nodes/accessors/ScreenUVNode.js"></script>
+		<script src="js/nodes/accessors/ColorsNode.js"></script>
+		<script src="js/nodes/accessors/CameraNode.js"></script>
+		<script src="js/nodes/accessors/ReflectNode.js"></script>
+		<script src="js/nodes/accessors/LightNode.js"></script>
+
+		<!-- Inputs -->
+		<script src="js/nodes/inputs/IntNode.js"></script>
+		<script src="js/nodes/inputs/FloatNode.js"></script>
+		<script src="js/nodes/inputs/ColorNode.js"></script>
+		<script src="js/nodes/inputs/Vector2Node.js"></script>
+		<script src="js/nodes/inputs/Vector3Node.js"></script>
+		<script src="js/nodes/inputs/Vector4Node.js"></script>
+		<script src="js/nodes/inputs/TextureNode.js"></script>
+		<script src="js/nodes/inputs/Matrix4Node.js"></script>
+		<script src="js/nodes/inputs/CubeTextureNode.js"></script>
+
+		<!-- Math -->
+		<script src="js/nodes/math/Math1Node.js"></script>
+		<script src="js/nodes/math/Math2Node.js"></script>
+		<script src="js/nodes/math/Math3Node.js"></script>
+		<script src="js/nodes/math/OperatorNode.js"></script>
+
+		<!-- Utils -->
+		<script src="js/nodes/utils/SwitchNode.js"></script>
+		<script src="js/nodes/utils/JoinNode.js"></script>
+		<script src="js/nodes/utils/TimerNode.js"></script>
+		<script src="js/nodes/utils/RoughnessToBlinnExponentNode.js"></script>
+		<script src="js/nodes/utils/VelocityNode.js"></script>
+		<script src="js/nodes/utils/LuminanceNode.js"></script>
+		<script src="js/nodes/utils/ColorAdjustmentNode.js"></script>
+		<script src="js/nodes/utils/NoiseNode.js"></script>
+		<script src="js/nodes/utils/ResolutionNode.js"></script>
+		<script src="js/nodes/utils/BumpNode.js"></script>
+		<script src="js/nodes/utils/BlurNode.js"></script>
+		<script src="js/nodes/utils/UVTransformNode.js"></script>
+
+		<!-- Sprite Material -->
+		<script src="js/nodes/materials/SpriteNode.js"></script>
+		<script src="js/nodes/materials/SpriteNodeMaterial.js"></script>
+		
+		<script>
+
+		var container = document.getElementById( 'container' );
+
+		var renderer, scene, camera, clock = new THREE.Clock(), fov = 50;
+		var plane, sprite1, sprite2, sprite3;
+		var controls;
+
+		window.addEventListener( 'load', init );
+
+		function init() {
+
+			//
+			// Renderer / Controls
+			//
+
+			renderer = new THREE.WebGLRenderer( { antialias: true } );
+			renderer.setPixelRatio( window.devicePixelRatio );
+			renderer.setSize( window.innerWidth, window.innerHeight );
+			container.appendChild( renderer.domElement );
+
+			scene = new THREE.Scene();
+			scene.fog = new THREE.Fog( 0x0000FF, 0.0, 100 );
+
+			camera = new THREE.PerspectiveCamera( fov, window.innerWidth / window.innerHeight, 1, 1000 );
+			camera.position.z = 50;
+			camera.target = new THREE.Vector3();
+
+			controls = new THREE.OrbitControls( camera, renderer.domElement );
+			controls.minDistance = 50;
+			controls.maxDistance = 200;
+
+			//
+			// SpriteNode
+			//
+
+			// use scale to adjuste the real sprite size
+			plane = new THREE.PlaneBufferGeometry( 1, 1 );
+
+			// https://openclipart.org/detail/239883/walking-man-sprite-sheet
+			var walkingManTexture = new THREE.TextureLoader().load( "textures/WalkingManSpriteSheet.png" );
+			walkingManTexture.wrapS = walkingManTexture.wrapT = THREE.RepeatWrapping;
+
+			// horizontal sprite-sheet animator
+
+			function createHorizontalSpriteSheetNode( hCount, speed ) {
+
+				var speed = new THREE.Vector2Node( speed, 0 ); // frame per second
+				var scale = new THREE.Vector2Node( 1 / hCount, 1 ); // 8 horizontal images in sprite-sheet
+
+				var uvTimer = new THREE.OperatorNode(
+					new THREE.TimerNode(),
+					speed,
+					THREE.OperatorNode.MUL
+				);
+
+				var uvIntegerTimer = new THREE.Math1Node(
+					uvTimer,
+					THREE.Math1Node.FLOOR
+				);
+
+				var uvFrameOffset = new THREE.OperatorNode(
+					uvIntegerTimer,
+					scale,
+					THREE.OperatorNode.MUL
+				);
+
+				var uvScale = new THREE.OperatorNode(
+					new THREE.UVNode(),
+					scale,
+					THREE.OperatorNode.MUL
+				);
+
+				var uvFrame = new THREE.OperatorNode(
+					uvScale,
+					uvFrameOffset,
+					THREE.OperatorNode.ADD
+				);
+
+				return uvFrame;
+
+			}
+
+			// sprites
+
+			var spriteWidth = 20,
+				spriteHeight = 20;
+
+			scene.add( sprite1 = new THREE.Mesh( plane, new THREE.SpriteNodeMaterial() ) );
+			sprite1.scale.x = spriteWidth;
+			sprite1.scale.y = spriteHeight;
+			sprite1.material.color = new THREE.TextureNode( walkingManTexture );
+			sprite1.material.color.coord = createHorizontalSpriteSheetNode( 8, 10 );
+			sprite1.material.build();
+
+			scene.add( sprite2 = new THREE.Mesh( plane, new THREE.SpriteNodeMaterial() ) );
+			sprite2.position.x = 30;
+			sprite2.scale.x = spriteWidth;
+			sprite2.scale.y = spriteHeight;
+			sprite2.material.color = new THREE.TextureNode( walkingManTexture );
+			sprite2.material.color.coord = createHorizontalSpriteSheetNode( 8, 30 );
+			sprite2.material.color = new THREE.Math1Node( sprite2.material.color, THREE.Math1Node.INVERT );
+			sprite2.material.spherical = false; // look at camera horizontally only, very used to vegetation
+			sprite2.material.build();
+
+			var sineWaveFunction = new THREE.FunctionNode( [
+				// https://stackoverflow.com/questions/36174431/how-to-make-a-wave-warp-effect-in-shader
+				"vec2 sineWave(vec2 uv, vec2 phase) {",
+				// wave distortion
+				"	float x = sin( 25.0*uv.y + 30.0*uv.x + 6.28*phase.x) * 0.01;",
+				"	float y = sin( 25.0*uv.y + 30.0*uv.x + 6.28*phase.y) * 0.03;",
+				"	return vec2(uv.x+x, uv.y+y);",
+				"}"
+			].join( "\n" ) );
+
+			scene.add( sprite3 = new THREE.Mesh( plane, new THREE.SpriteNodeMaterial() ) );
+			sprite3.position.x = - 30;
+			sprite3.scale.x = spriteWidth;
+			sprite3.scale.y = spriteHeight;
+			sprite3.material.fog = true;
+			sprite3.material.color = new THREE.TextureNode( walkingManTexture );
+			sprite3.material.color.coord = new THREE.FunctionCallNode( sineWaveFunction, {
+				"uv": createHorizontalSpriteSheetNode( 8, 0 ),
+				"phase": new THREE.TimerNode()
+			} );
+			sprite3.material.build();
+
+			//
+			// Events
+			//
+
+			window.addEventListener( 'resize', onWindowResize, false );
+
+			onWindowResize();
+			animate();
+
+		}
+
+		function onWindowResize() {
+
+			var width = window.innerWidth, height = window.innerHeight;
+
+			camera.aspect = width / height;
+			camera.updateProjectionMatrix();
+
+			renderer.setSize( width, height );
+
+		}
+
+		function animate() {
+
+			var delta = clock.getDelta();
+
+			// update material animation and/or gpu calcs (pre-renderer)
+			sprite1.material.updateFrame( delta );
+			sprite2.material.updateFrame( delta );
+			sprite3.material.updateFrame( delta );
+
+			// rotate sprite
+			sprite3.rotation.z -= Math.PI * .005;
+
+			renderer.render( scene, camera );
+
+			requestAnimationFrame( animate );
+
+		}
+
+		</script>
+
+	</body>
+</html>