Hello freinds in this tutorial we will be working with sprites and texture animation. If you do not know, sprites are simply images, that could be attached to objects. These sprite images are always orthogonal to our camera.
Three.js provides a special material for the sprites – THREE.SpriteMaterial, as well as a special object – THREE.Sprite. Also in this tutorial we will learn how to play the animation using sprites.
As a result we got that only one tile is visible at a time. And every tile is visible within 100ms. So, the animation works pretty fast, as we needed to make.
Three.js provides a special material for the sprites – THREE.SpriteMaterial, as well as a special object – THREE.Sprite. Also in this tutorial we will learn how to play the animation using sprites.
Check this tutorial : How to make a Virtual Reality 3D Tracking headset
Demo
Preparation
As usual, we have to prepare a small index.html file with necessary html markup to work on:index.html
<!DOCTYPE html>In this code, we connect the main Three.js library and few additional utilites: WindowResize event handler, Orbit controls and Stats
<html lang="en" >
<head>
<meta charset="utf-8" />
<meta name="author" content="Script Tutorials" />
<title>WebGL With Three.js - Sprites and Texture Animation | S2P Tech</title>
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
<link href="css/main.css" rel="stylesheet" type="text/css" />
</head>
<body>
<script src="js/three.min.js"></script>
<script src="js/THREEx.WindowResize.js"></script>
<script src="js/OrbitControls.js"></script>
<script src="js/stats.min.js"></script>
<script src="js/script.js"></script>
<div style="position: absolute; top: 10px; left: 20px; text-align: center;"><a href="http://s2ptech.blogspot.com/2015/05/webgl-with-threejs-tutorial-and-demo.html" target="_blank">"WebGL With Three.js Tutorial"</a> is prepared by <a href="http://www.s2ptech.com/" target="_blank">S2P Tech</a> team.<br>Drag to spin</div>
</body>
</html>
File Explorer and Download File
Preparation of the main webgl scene
Now let’s create the main ‘script.js’ file and place the code shown below:Check this tutorials : How to add multiple recaptcha on same page
script.js
var lesson8 = {This code creates a basic scene with renderer, camera, controls, lights, stats and skybox. Similar code you already saw earlier in previous lessons. There is nothing new.
scene: null,
camera: null,
renderer: null,
container: null,
controls: null,
clock: null,
stats: null,
anim1: null, anim2: null, // animations
animReady1: false, animReady2: false,
init: function() { // initialization
// create main scene
this.scene = new THREE.Scene();
this.scene.fog = new THREE.FogExp2(0xcce0ff, 0.0003);
var SCREEN_WIDTH = window.innerWidth,
SCREEN_HEIGHT = window.innerHeight;
// prepare perspective camera
var VIEW_ANGLE = 60, ASPECT = SCREEN_WIDTH / SCREEN_HEIGHT, NEAR = 1, FAR = 1000;
this.camera = new THREE.PerspectiveCamera(VIEW_ANGLE, ASPECT, NEAR, FAR);
this.scene.add(this.camera);
this.camera.position.set(100, 0, 0);
this.camera.lookAt(new THREE.Vector3(0,0,0));
// prepare webgl renderer
this.renderer = new THREE.WebGLRenderer({ antialias:true });
this.renderer.setSize(SCREEN_WIDTH, SCREEN_HEIGHT);
this.renderer.setClearColor(this.scene.fog.color);
this.renderer.shadowMapEnabled = true;
this.renderer.shadowMapSoft = true;
// prepare container
this.container = document.createElement('div');
document.body.appendChild(this.container);
this.container.appendChild(this.renderer.domElement);
// events
THREEx.WindowResize(this.renderer, this.camera);
// prepare controls (OrbitControls)
this.controls = new THREE.OrbitControls(this.camera, this.renderer.domElement);
this.controls.target = new THREE.Vector3(0, 0, 0);
this.controls.maxDistance = 3000;
// prepare clock
this.clock = new THREE.Clock();
// prepare stats
this.stats = new Stats();
this.stats.domElement.style.position = 'absolute';
this.stats.domElement.style.left = '50px';
this.stats.domElement.style.bottom = '50px';
this.stats.domElement.style.zIndex = 1;
this.container.appendChild( this.stats.domElement );
// add lights
this.scene.add( new THREE.AmbientLight(0x606060) );
var dirLight = new THREE.DirectionalLight(0xffffff);
dirLight.position.set(200, 200, 1000).normalize();
this.camera.add(dirLight);
this.camera.add(dirLight.target);
// display skybox
this.addSkybox();
// display animated objects
this.addAnimatedObjects();
},
addSkybox: function() {
// define path and box sides images
var path = 'skybox/';
var sides = [ path + 'sbox_px.jpg', path + 'sbox_nx.jpg', path + 'sbox_py.jpg', path + 'sbox_ny.jpg', path + 'sbox_pz.jpg', path + 'sbox_nz.jpg' ];
// load images
var scCube = THREE.ImageUtils.loadTextureCube(sides);
scCube.format = THREE.RGBFormat;
// prepare skybox material (shader)
var skyShader = THREE.ShaderLib["cube"];
skyShader.uniforms["tCube"].value = scCube;
var skyMaterial = new THREE.ShaderMaterial( {
fragmentShader: skyShader.fragmentShader, vertexShader: skyShader.vertexShader,
uniforms: skyShader.uniforms, depthWrite: false, side: THREE.BackSide
});
// create Mesh with cube geometry and add to the scene
var skyBox = new THREE.Mesh(new THREE.BoxGeometry(500, 500, 500), skyMaterial);
skyMaterial.needsUpdate = true;
this.scene.add(skyBox);
}
};
// animate the scene
function animate() {
requestAnimationFrame(animate);
render();
update();
}
// update controls and stats
function update() {
var delta = lesson8.clock.getDelta();
lesson8.controls.update(delta);
lesson8.stats.update();
}
// Render the scene
function render() {
if (lesson8.renderer) {
lesson8.renderer.render(lesson8.scene, lesson8.camera);
}
}
// Initialize lesson on page load
function initializeLesson() {
lesson8.init();
animate();
}
if (window.addEventListener)
window.addEventListener('load', initializeLesson, false);
else if (window.attachEvent)
window.attachEvent('onload', initializeLesson);
else window.onload = initializeLesson;
Sprites
As mentioned earlier, sprites are (two-dimensional) images, which are orthogonal (perpendicular) to our camera. Now let’s add the sprites to our scene with the following function:addAnimatedObjects: function() {This code loads two textures (sprite1.png and sprite2.png). After both images are loaded, we create two sprite materials and the Sprite object, and add them to our scene. If you run the code now, you will see two two-dimensional images on our scene. As you may have noticed, the images are drawn as is – we see a lot of small images (tiles) – these image files were taken due to the fact that we will use these tiles to do the animation.
var texture1 = new THREE.ImageUtils.loadTexture('images/sprite1.png', undefined, function() {
var material1 = new THREE.SpriteMaterial( { map: texture1, useScreenCoordinates: false, side:THREE.DoubleSide, transparent: true } );
var mesh1 = new THREE.Sprite(material1);
mesh1.position.set(0, 0, -40);
mesh1.scale.set(64, 64, 1.0);
lesson8.scene.add(mesh1);
});
var texture2 = new THREE.ImageUtils.loadTexture('images/sprite2.png', undefined, function() {
var material2 = new THREE.SpriteMaterial( { map: texture2, useScreenCoordinates: false, transparent: true } );
var mesh2 = new THREE.Sprite(material2);
mesh2.position.set(0, 0, 40);
mesh2.scale.set(24, 46, 1.0);
lesson8.scene.add(mesh2);
});
}
Texture Animation
Now we need to add a new function to our script:TileTextureAnimator function
function TileTextureAnimator(texture, hTiles, vTiles, durationTile) {The ‘TileTextureAnimator’ function adjusts the original images to display animation. It turns between tiles of the image from first to last tile. This does at a specified interval of time. Every tile is visible within the certain duration time, after it turns to another tile. Now let’s update the
// current tile number
this.currentTile = 0;
// duration of every tile
this.durationTile = durationTile;
// internal time counter
this.currentTime = 0;
// amount of horizontal and vertical tiles, and total count of tiles
this.hTiles = hTiles;
this.vTiles = vTiles;
this.cntTiles = this.hTiles * this.vTiles;
texture.wrapS = texture.wrapT = THREE.RepeatWrapping;
texture.repeat.set(1 / this.hTiles, 1 / this.vTiles);
this.update = function(time) {
this.currentTime += time;
while (this.currentTime > this.durationTile) {
this.currentTime -= this.durationTile;
this.currentTile++;
if (this.currentTile == this.cntTiles) {
this.currentTile = 0;
}
var iColumn = this.currentTile % this.hTiles;
texture.offset.x = iColumn / this.hTiles;
var iRow = Math.floor(this.currentTile / this.hTiles);
texture.offset.y = iRow / this.vTiles;
}
};
}
‘addAnimatedObjects’ function
addAnimatedObjects: function() {The first sprite image contains 8 tiles in row, 8 rows total, the second image contains 9 tiles in row. Every tile will be visible for 100ms. Finally, in the main ‘update’ function, we need to put the following code:
var texture1 = new THREE.ImageUtils.loadTexture('images/sprite1.png', undefined, function() {
lesson8.anim1 = new TileTextureAnimator(texture1, 8, 8, 100);
var material1 = new THREE.SpriteMaterial( { map: texture1, useScreenCoordinates: false, side:THREE.DoubleSide, transparent: true } );
var mesh1 = new THREE.Sprite(material1);
mesh1.position.set(0, 0, -40);
mesh1.scale.set(64, 64, 1.0);
lesson8.scene.add(mesh1);
lesson8.animReady1 = true;
});
var texture2 = new THREE.ImageUtils.loadTexture('images/sprite2.png', undefined, function() {
lesson8.anim2 = new TileTextureAnimator(texture2, 9, 8, 100);
var material2 = new THREE.SpriteMaterial( { map: texture2, useScreenCoordinates: false, transparent: true } );
var mesh2 = new THREE.Sprite(material2);
mesh2.position.set(0, 0, 40);
mesh2.scale.set(24, 46, 1.0);
lesson8.scene.add(mesh2);
lesson8.animReady2 = true;
});
}
if (lesson8.animReady1) {This code invokes the ‘update’ function of ‘TileTextureAnimator’ class objects.
lesson8.anim1.update(1000 * delta);
}
if (lesson8.animReady2) {
lesson8.anim2.update(1000 * delta);
}
As a result we got that only one tile is visible at a time. And every tile is visible within 100ms. So, the animation works pretty fast, as we needed to make.