Files
three.js/examples/webgl_geometry_text.html
T
alteredq 942a6c89c9 Updated Clock to be more compatible with Timer (now uses seconds and getDelta API).
Lots of code got cleaner with seconds, seems we used them before all around.

Also changed examples that didn't need deltas to simple Date.now() plus some more examples cleaning, trying to get rid of obsolescence warnings.
2011-10-15 00:57:50 +02:00

635 lines
15 KiB
HTML

<!doctype html>
<html lang="en">
<head>
<title>three.js webgl - geometry - text</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 {
font-family: Monospace;
background-color: #000;
color: #fff;
margin: 0px;
overflow: hidden;
}
#info {
position: absolute;
top: 10px;
width: 100%;
text-align: center;
z-index: 100;
display:block;
}
#info a, .button { color: #f00; font-weight: bold; text-decoration: underline; cursor: pointer }
</style>
</head>
<body>
<div id="info">
<a href="http://github.com/mrdoob/three.js" target="_blank">three.js</a> - procedural 3D text by <a href="http://www.lab4games.net/zz85/blog" target="_blank">zz85</a> &amp; alteredq
(fonts from <a href="http://typeface.neocracy.org/">typeface.js</a> and <a href="http://en.wikipedia.org/wiki/Droid_%28font%29">Droid</a>)
<br/>type to enter new text, drag to spin the text
<br/><span class="button" id="color">change color</span>,
<span class="button" id="font">change font</span>,
<span class="button" id="weight">change weight</span>,
<span class="button" id="bevel">change bevel</span>,
<span class="button" id="bend">bend</span>,
<span class="button" id="postprocessing">change postprocessing</span>,
<a id="permalink" href="#">permalink</a>
</div>
<script src="../build/Three.js"></script>
<script src="js/ShaderExtras.js"></script>
<script src="js/postprocessing/EffectComposer.js"></script>
<script src="js/postprocessing/RenderPass.js"></script>
<script src="js/postprocessing/ShaderPass.js"></script>
<script src="js/postprocessing/MaskPass.js"></script>
<script src="js/postprocessing/BloomPass.js"></script>
<script src="js/postprocessing/FilmPass.js"></script>
<script src="js/Detector.js"></script>
<script src="js/RequestAnimationFrame.js"></script>
<script src="js/Stats.js"></script>
<!-- load the font files -->
<script src="fonts/gentilis_bold.typeface.js"></script>
<script src="fonts/gentilis_regular.typeface.js"></script>
<script src="fonts/optimer_bold.typeface.js"></script>
<script src="fonts/optimer_regular.typeface.js"></script>
<script src="fonts/helvetiker_bold.typeface.js"></script>
<script src="fonts/helvetiker_regular.typeface.js"></script>
<script src="fonts/droid/droid_sans_regular.typeface.js"></script>
<script src="fonts/droid/droid_sans_bold.typeface.js"></script>
<script src="fonts/droid/droid_serif_regular.typeface.js"></script>
<script src="fonts/droid/droid_serif_bold.typeface.js"></script>
<!-- todo async loader for fonts -->
<script>
if ( ! Detector.webgl ) Detector.addGetWebGLMessage();
var container, stats, permalink, hex, color;
var camera, cameraTarget, scene, renderer;
var composer;
var textMesh1, textMesh2, textGeo, faceMaterial, textMaterialFront, textMaterialSide, parent;
var firstLetter = true;
var text = "three.js",
height = 20,
size = 70,
hover = 30,
curveSegments = 4,
bevelThickness = 2,
bevelSize = 1.5,
bevelSegments = 3,
bevelEnabled = true,
bend = true,
font = "optimer", // helvetiker, optimer, gentilis, droid sans, droid serif
weight = "bold", // normal bold
style = "normal"; // normal italic
var mirror = true;
var fontMap = {
"helvetiker" : 0,
"optimer" : 1,
"gentilis" : 2,
"droid sans" : 3,
"droid serif" : 4
};
var weightMap = {
"normal" : 0,
"bold" : 1
}
var reverseFontMap = {};
var reverseWeightMap = {};
for ( var i in fontMap ) reverseFontMap[ fontMap[i] ] = i;
for ( var i in weightMap ) reverseWeightMap[ weightMap[i] ] = i;
var targetRotation = 0;
var targetRotationOnMouseDown = 0;
var mouseX = 0;
var mouseXOnMouseDown = 0;
var windowHalfX = window.innerWidth / 2;
var windowHalfY = window.innerHeight / 2;
var postprocessing = { enabled : false };
var glow = 0.9;
init();
animate();
function capitalize( txt ) {
return txt.substring( 0, 1 ).toUpperCase() + txt.substring( 1 );
}
function decimalToHex( d ) {
var hex = Number( d ).toString( 16 );
hex = "000000".substr( 0, 6 - hex.length ) + hex;
return hex.toUpperCase();
}
function init() {
container = document.createElement( 'div' );
document.body.appendChild( container );
permalink = document.getElementById( "permalink" );
// CAMERA
camera = new THREE.PerspectiveCamera( 30, window.innerWidth / window.innerHeight, 1, 1500 );
camera.position.set( 0, 400, 700 );
cameraTarget = new THREE.Vector3( 0, 150, 0 );
// SCENE
scene = new THREE.Scene();
scene.fog = new THREE.Fog( 0x000000, 250, 1400 );
var dirLight = new THREE.DirectionalLight( 0xffffff, 0.125 );
dirLight.position.set( 0, 0, 1 ).normalize();
scene.add( dirLight );
var pointLight = new THREE.PointLight( 0xffffff, 1.5 );
pointLight.position.set( 0, 100, 90 );
scene.add( pointLight );
//text = capitalize( font ) + " " + capitalize( weight );
//text = "abcdefghijklmnopqrstuvwxyz0123456789";
//text = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
// Get text from hash
var hash = document.location.hash.substr( 1 );
if ( hash.length !== 0 ) {
var colorhash = hash.substring( 0, 6 );
var fonthash = hash.substring( 6, 7 );
var weighthash = hash.substring( 7, 8 );
var pphash = hash.substring( 8, 9 );
var bevelhash = hash.substring( 9, 10 );
var bendhash = hash.substring( 10, 11 );
var texthash = hash.substring( 12 );
hex = colorhash;
pointLight.color.setHex( parseInt( colorhash, 16 ) );
font = reverseFontMap[ parseInt( fonthash ) ];
weight = reverseWeightMap[ parseInt( weighthash ) ];
postprocessing.enabled = parseInt( pphash );
bevelEnabled = parseInt( bevelhash );
bend = parseInt( bendhash );
text = decodeURI( texthash );
updatePermalink();
} else {
pointLight.color.setHSV( Math.random(), 0.95, 0.85 );
hex = decimalToHex( pointLight.color.getHex() );
}
faceMaterial = new THREE.MeshFaceMaterial();
textMaterialFront = new THREE.MeshPhongMaterial( { color: 0xffffff, shading: THREE.FlatShading } );
textMaterialSide = new THREE.MeshPhongMaterial( { color: 0xffffff, shading: THREE.SmoothShading } );
parent = new THREE.Object3D();
parent.position.y = 100;
scene.add( parent );
createText();
var plane = new THREE.Mesh( new THREE.PlaneGeometry( 10000, 10000 ), new THREE.MeshBasicMaterial( { color: 0xffffff, opacity: 0.5, transparent: true } ) );
plane.rotation.x = -Math.PI/2;
plane.position.y = 100;
scene.add( plane );
// RENDERER
renderer = new THREE.WebGLRenderer( { antialias: true } );
renderer.setSize( window.innerWidth, window.innerHeight );
renderer.setClearColor( scene.fog.color, 1 );
container.appendChild( renderer.domElement );
// STATS
stats = new Stats();
stats.domElement.style.position = 'absolute';
stats.domElement.style.top = '0px';
//container.appendChild( stats.domElement );
// EVENTS
document.addEventListener( 'mousedown', onDocumentMouseDown, false );
document.addEventListener( 'touchstart', onDocumentTouchStart, false );
document.addEventListener( 'touchmove', onDocumentTouchMove, false );
document.addEventListener( 'keypress', onDocumentKeyPress, false );
document.addEventListener( 'keydown', onDocumentKeyDown, false );
document.getElementById( "color" ).addEventListener( 'click', function() {
pointLight.color.setHSV( Math.random(), 0.95, 0.85 );
hex = decimalToHex( pointLight.color.getHex() );
updatePermalink();
}, false );
document.getElementById( "font" ).addEventListener( 'click', function() {
if ( font == "helvetiker" ) {
font = "optimer";
} else if ( font == "optimer" ) {
font = "gentilis";
} else if ( font == "gentilis" ) {
font = "droid sans";
} else if ( font == "droid sans" ) {
font = "droid serif";
} else {
font = "helvetiker";
}
refreshText();
}, false );
document.getElementById( "weight" ).addEventListener( 'click', function() {
if ( weight == "bold" ) {
weight = "normal";
} else {
weight = "bold";
}
refreshText();
}, false );
document.getElementById( "bevel" ).addEventListener( 'click', function() {
bevelEnabled = !bevelEnabled;
refreshText();
}, false );
document.getElementById( "bend" ).addEventListener( 'click', function() {
bend = !bend;
refreshText();
}, false );
document.getElementById( "postprocessing" ).addEventListener( 'click', function() {
postprocessing.enabled = !postprocessing.enabled;
updatePermalink();
}, false );
// POSTPROCESSING
renderer.autoClear = false;
var renderModel = new THREE.RenderPass( scene, camera );
var effectBloom = new THREE.BloomPass( 0.25 );
var effectFilm = new THREE.FilmPass( 0.5, 0.125, 2048, false );
var effectFXAA = new THREE.ShaderPass( THREE.ShaderExtras[ "fxaa" ] );
effectFXAA.uniforms[ 'resolution' ].value.set( 1 / window.innerWidth, 1 / window.innerHeight );
effectFilm.renderToScreen = true;
composer = new THREE.EffectComposer( renderer );
composer.addPass( renderModel );
composer.addPass( effectFXAA );
composer.addPass( effectBloom );
composer.addPass( effectFilm );
}
//
function boolToNum( b ) {
return b ? 1 : 0;
}
function updatePermalink() {
var link = hex + fontMap[ font ] + weightMap[ weight ] + boolToNum( postprocessing.enabled ) + boolToNum( bevelEnabled )
+ boolToNum( bend ) + "#" + encodeURI( text );
permalink.href = "#" + link;
window.location.hash = link;
}
function onDocumentKeyDown( event ) {
if ( firstLetter ) {
firstLetter = false;
text = "";
}
var keyCode = event.keyCode;
// backspace
if ( keyCode == 8 ) {
event.preventDefault();
text = text.substring( 0, text.length - 1 );
refreshText();
return false;
}
}
function onDocumentKeyPress( event ) {
var keyCode = event.which;
// backspace
if ( keyCode == 8 ) {
event.preventDefault();
} else {
var ch = String.fromCharCode( keyCode );
text += ch;
refreshText();
}
}
function createText() {
textGeo = new THREE.TextGeometry( text, {
size: size,
height: height,
curveSegments: curveSegments,
font: font,
weight: weight,
style: style,
bevelThickness: bevelThickness,
bevelSize: bevelSize,
bevelEnabled: bevelEnabled,
bend: bend,
material: textMaterialFront,
extrudeMaterial: textMaterialSide
});
textGeo.computeBoundingBox();
textGeo.computeVertexNormals();
// "fix" side normals by removing z-component of normals for side faces
// (this doesn't work well for beveled geometry as then we lose nice curvature around z-axis)
if ( ! bevelEnabled ) {
var triangleAreaHeuristics = 0.1 * ( height * size );
for ( var i = 0; i < textGeo.faces.length; i ++ ) {
var face = textGeo.faces[ i ];
if ( face.materials[ 0 ].id == textMaterialSide.id ) {
for ( var j = 0; j < face.vertexNormals.length; j ++ ) {
face.vertexNormals[ j ].z = 0;
face.vertexNormals[ j ].normalize();
}
var va = textGeo.vertices[ face.a ].position;
var vb = textGeo.vertices[ face.b ].position;
var vc = textGeo.vertices[ face.c ].position;
var s = THREE.GeometryUtils.triangleArea( va, vb, vc );
if ( s > triangleAreaHeuristics ) {
for ( var j = 0; j < face.vertexNormals.length; j ++ ) {
face.vertexNormals[ j ].copy( face.normal );
}
}
}
}
}
var centerOffset = -0.5 * ( textGeo.boundingBox.x[ 1 ] - textGeo.boundingBox.x[ 0 ] );
textMesh1 = new THREE.Mesh( textGeo, faceMaterial );
textMesh1.position.x = centerOffset;
textMesh1.position.y = hover;
textMesh1.position.z = 0;
textMesh1.rotation.x = 0;
textMesh1.rotation.y = Math.PI * 2;
parent.add( textMesh1 );
if ( mirror ) {
textMesh2 = new THREE.Mesh( textGeo, faceMaterial );
textMesh2.position.x = centerOffset;
textMesh2.position.y = -hover;
textMesh2.position.z = height;
textMesh2.rotation.x = Math.PI;
textMesh2.rotation.y = Math.PI * 2;
parent.add( textMesh2 );
}
}
function refreshText() {
updatePermalink();
scene.remove( textMesh1 );
if ( mirror ) scene.remove( textMesh2 );
if ( !text ) return;
createText();
}
function onDocumentMouseDown( event ) {
event.preventDefault();
document.addEventListener( 'mousemove', onDocumentMouseMove, false );
document.addEventListener( 'mouseup', onDocumentMouseUp, false );
document.addEventListener( 'mouseout', onDocumentMouseOut, false );
mouseXOnMouseDown = event.clientX - windowHalfX;
targetRotationOnMouseDown = targetRotation;
}
function onDocumentMouseMove( event ) {
mouseX = event.clientX - windowHalfX;
targetRotation = targetRotationOnMouseDown + ( mouseX - mouseXOnMouseDown ) * 0.02;
}
function onDocumentMouseUp( event ) {
document.removeEventListener( 'mousemove', onDocumentMouseMove, false );
document.removeEventListener( 'mouseup', onDocumentMouseUp, false );
document.removeEventListener( 'mouseout', onDocumentMouseOut, false );
}
function onDocumentMouseOut( event ) {
document.removeEventListener( 'mousemove', onDocumentMouseMove, false );
document.removeEventListener( 'mouseup', onDocumentMouseUp, false );
document.removeEventListener( 'mouseout', onDocumentMouseOut, false );
}
function onDocumentTouchStart( event ) {
if ( event.touches.length == 1 ) {
event.preventDefault();
mouseXOnMouseDown = event.touches[ 0 ].pageX - windowHalfX;
targetRotationOnMouseDown = targetRotation;
}
}
function onDocumentTouchMove( event ) {
if ( event.touches.length == 1 ) {
event.preventDefault();
mouseX = event.touches[ 0 ].pageX - windowHalfX;
targetRotation = targetRotationOnMouseDown + ( mouseX - mouseXOnMouseDown ) * 0.05;
}
}
//
function animate() {
requestAnimationFrame( animate );
render();
stats.update();
}
function render() {
parent.rotation.y += ( targetRotation - parent.rotation.y ) * 0.05;
camera.lookAt( cameraTarget );
renderer.clear();
if ( postprocessing.enabled ) {
composer.render( 0.05 );
} else {
renderer.render( scene, camera );
}
}
</script>
</body>
</html>