You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
258 lines
6.8 KiB
258 lines
6.8 KiB
<!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>
|
|
|
|
<script type="module">
|
|
|
|
import './js/nodes/THREE.Nodes.js';
|
|
import './js/loaders/NodeMaterialLoader.js';
|
|
|
|
var container = document.getElementById( 'container' );
|
|
|
|
var renderer, scene, camera, clock = new THREE.Clock(), fov = 50;
|
|
var frame = new THREE.NodeFrame();
|
|
var sprite1, sprite2, sprite3;
|
|
var walkingManTexture, walkingManTextureURL;
|
|
var library = {};
|
|
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, 70, 150 );
|
|
|
|
camera = new THREE.PerspectiveCamera( fov, window.innerWidth / window.innerHeight, 1, 1000 );
|
|
camera.position.z = 100;
|
|
camera.target = new THREE.Vector3();
|
|
|
|
controls = new THREE.OrbitControls( camera, renderer.domElement );
|
|
controls.minDistance = 50;
|
|
controls.maxDistance = 200;
|
|
|
|
//
|
|
// SpriteNode
|
|
//
|
|
|
|
// https://openclipart.org/detail/239883/walking-man-sprite-sheet
|
|
walkingManTextureURL = "textures/WalkingManSpriteSheet.png";
|
|
|
|
walkingManTexture = new THREE.TextureLoader().load( walkingManTextureURL );
|
|
walkingManTexture.wrapS = walkingManTexture.wrapT = THREE.RepeatWrapping;
|
|
|
|
library[ walkingManTextureURL ] = walkingManTexture;
|
|
|
|
// 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.Sprite( new THREE.SpriteNodeMaterial() ) );
|
|
sprite1.scale.x = spriteWidth;
|
|
sprite1.scale.y = spriteHeight;
|
|
sprite1.material.color = new THREE.TextureNode( walkingManTexture );
|
|
sprite1.material.color.uv = createHorizontalSpriteSheetNode( 8, 10 );
|
|
|
|
scene.add( sprite2 = new THREE.Sprite( 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.uv = 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 in vegetation
|
|
// horizontal zigzag sprite
|
|
sprite2.material.position = new THREE.OperatorNode(
|
|
new THREE.OperatorNode(
|
|
new THREE.Math1Node( new THREE.TimerNode( 3 ), THREE.Math1Node.SIN ), // 3 is speed (time scale)
|
|
new THREE.Vector2Node( .3, 0 ), // horizontal scale (position)
|
|
THREE.OperatorNode.MUL
|
|
),
|
|
new THREE.PositionNode(),
|
|
THREE.OperatorNode.ADD
|
|
);
|
|
|
|
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.Sprite( new THREE.SpriteNodeMaterial() ) );
|
|
sprite3.position.x = - 30;
|
|
sprite3.scale.x = spriteWidth;
|
|
sprite3.scale.y = spriteHeight;
|
|
sprite3.material.color = new THREE.TextureNode( walkingManTexture );
|
|
sprite3.material.color.uv = new THREE.FunctionCallNode( sineWaveFunction, {
|
|
"uv": createHorizontalSpriteSheetNode( 8, 10 ),
|
|
"phase": new THREE.TimerNode()
|
|
} );
|
|
sprite3.material.fog = true;
|
|
|
|
//
|
|
// Test serialization
|
|
//
|
|
|
|
spriteToJSON( sprite1 );
|
|
spriteToJSON( sprite2 );
|
|
spriteToJSON( sprite3 );
|
|
|
|
//
|
|
// Events
|
|
//
|
|
|
|
window.addEventListener( 'resize', onWindowResize, false );
|
|
|
|
onWindowResize();
|
|
animate();
|
|
|
|
}
|
|
|
|
function spriteToJSON( sprite ) {
|
|
|
|
// serialize
|
|
|
|
var json = sprite.material.toJSON();
|
|
|
|
// replace uuid to url (facilitates the load of textures using url otherside uuid)
|
|
|
|
THREE.NodeMaterialLoaderUtils.replaceUUID( json, walkingManTexture, walkingManTextureURL );
|
|
|
|
// deserialize
|
|
|
|
var material = new THREE.NodeMaterialLoader( null, library ).parse( json );
|
|
|
|
// replace material
|
|
|
|
sprite.material.dispose();
|
|
|
|
sprite.material = material;
|
|
|
|
}
|
|
|
|
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)
|
|
frame.update( delta )
|
|
.updateNode( sprite1.material )
|
|
.updateNode( sprite2.material )
|
|
.updateNode( sprite3.material );
|
|
|
|
// rotate sprite
|
|
sprite3.rotation.z -= Math.PI * .005;
|
|
|
|
renderer.render( scene, camera );
|
|
|
|
requestAnimationFrame( animate );
|
|
|
|
}
|
|
|
|
</script>
|
|
|
|
</body>
|
|
</html>
|