animating one million letters
by icodeforlove
HTML
<script src="http://www.html5rocks.com/en/tutorials/webgl/million_letters/Three.js"></script>
<script src="http://www.html5rocks.com/en/tutorials/webgl/million_letters/book.js"></script>
<script src="http://www.html5rocks.com/en/tutorials/webgl/million_letters/dat.gui.min.js"></script>
<script id="vertex" type="text/x-glsl-vert">
varying float vZ;
uniform float time;
uniform float effectAmount;
varying vec2 vUv;
mat3 rotateAngleAxisMatrix(float angle, vec3 axis) {
float c = cos(angle);
float s = sin(angle);
float t = 1.0 - c;
axis = normalize(axis);
float x = axis.x, y = axis.y, z = axis.z;
return mat3(
t*x*x + c, t*x*y + s*z, t*x*z - s*y,
t*x*y - s*z, t*y*y + c, t*y*z + s*x,
t*x*z + s*y, t*y*z - s*x, t*z*z + c
);
}
vec3 rotateAngleAxis(float angle, vec3 axis, vec3 v) {
return rotateAngleAxisMatrix(angle, axis) * v;
}
void main() {
float idx = floor(position.y/1.1)*80.0 + floor(position.x/1.1);
vec3 corner = vec3(floor(position.x/1.1)*1.1, floor(position.y/1.1)*1.1, 0.0);
vec3 mid = corner + vec3(0.5, 0.5, 0.0);
vec3 rpos = rotateAngleAxis(idx+time, vec3(mod(idx,16.0), -8.0+mod(idx,15.0), 1.0), position - mid) + mid;
vec4 fpos = vec4( mix(position,rpos,effectAmount), 1.0 );
fpos.x += -35.0;
fpos.z += ((sin(idx+time*2.0)))*4.2*effectAmount;
fpos.y += ((cos(idx+time*2.0)))*4.2*effectAmount;
vec4 mvPosition = modelViewMatrix * fpos;
mvPosition.y += 10.0*sin(time*0.5+mvPosition.x/25.0)*effectAmount;
mvPosition.x -= 10.0*cos(time*0.5+mvPosition.y/25.0)*effectAmount;
vec4 p = projectionMatrix * mvPosition;
vUv = uv;
vZ = p.z;
gl_Position = p;
}
</script>
<script id="fragment" type="text/x-glsl-frag">
varying float vZ;
varying vec2 vUv;
uniform float time;
...
JavaScript
var renderer = new THREE.WebGLRenderer({antialias: true});
renderer.setClearColor( 0xffffff );
document.body.appendChild(renderer.domElement);
var camera = new THREE.PerspectiveCamera(45,1,4,40000);
camera.setLens(35);
window.onresize = function() {
renderer.setSize(window.innerWidth, window.innerHeight);
camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();
};
window.onresize();
var radius = 60;
var scene = new THREE.Scene();
camera.position.z = radius;
scene.add(camera);
var fontSize = 16;
var lettersPerSide = 16;
var c = document.createElement('canvas');
c.width = c.height = fontSize*lettersPerSide;
var ctx = c.getContext('2d');
ctx.font = fontSize+'px Monospace';
var i=0;
for (var y=0; y<lettersPerSide; y++) {
for (var x=0; x<lettersPerSide; x++,i++) {
var ch = String.fromCharCode(i);
ctx.fillText(ch, x*fontSize, -(8/32)*fontSize+(y+1)*fontSize);
}
}
var tex = new THREE.Texture(c);
tex.flipY = false;
tex.needsUpdate = true;
var mat = new THREE.MeshBasicMaterial({map: tex});
mat.transparent = true;
var geo = new THREE.Geometry();
var str = BOOK;
var j=0, ln=0;
for (i=0; i<str.length; i++) {
var code = str.charCodeAt(i);
var cx = code % lettersPerSide;
var cy = Math.floor(code / lettersPerSide);
var v,t;
geo.vertices.push(
new THREE.Vector3( j*1.1+0.05, ln*1.1+0.05, 0 ),
new THREE.Vector3( j*1.1+1.05, ln*1.1+0.05, 0 ),
new THREE.Vector3( j*1.1+1.05, ln*1.1+1.05, 0 ),
new THREE.Vector3( j*1.1+0.05, ln*1.1+1.05, 0 )
);
var face = new THREE.Face3(i*4+0, i*4+1, i*4+2);
geo.faces.push(face);
face = new THREE.Face3(i*4+0, i*4+2, i*4+3);
geo.faces.push(face);
var ox=(cx+0.05)/lettersPerSide, oy=(cy+0.05)/lettersPerSide, off=0.9/lettersPerSide;
var sz = lettersPerSide*fontSize;
geo.faceVertexUvs[0].push([
new THREE.Vector2( ox, oy+off ),
new...