Przeglądaj źródła

SpriteNodeMaterial and example

sunag 8 lat temu
rodzic
commit
dd840a9055

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

@@ -0,0 +1,125 @@
+/**
+ * @author sunag / http://www.sunag.com.br/
+ */
+
+THREE.SpriteNode = function () {
+
+	THREE.GLNode.call( this );
+
+	this.color = new THREE.ColorNode( 0xEEEEEE );
+
+};
+
+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;',
+
+			// 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;',
+
+			// Second colunm.
+			'modelViewMtx[1][0] = 0.0;',
+			'modelViewMtx[1][1] = 1.0;',
+			'modelViewMtx[1][2] = 0.0;',
+
+			// 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' ] );

BIN
examples/textures/WalkingManSpriteSheet.png


+ 269 - 0
examples/webgl_sprites_nodes.html

@@ -0,0 +1,269 @@
+<!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 );
+
+			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.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>