提交 d2cbf83d 编写于 作者: A alteredq

Merged zz85's 3d text pull request, cleaned up THREE.Text code.

因为 它太大了无法显示 source diff 。你可以改为 查看blob
......@@ -3,7 +3,8 @@ var THREE=THREE||{};if(!window.Int32Array)window.Int32Array=Array,window.Float32
THREE.Color.prototype={copy:function(a){this.r=a.r;this.g=a.g;this.b=a.b;this.hex=a.hex},setHex:function(a){this.hex=~~a&16777215;this.updateRGB()},setRGB:function(a,b,c){this.r=a;this.g=b;this.b=c;this.updateHex()},setHSV:function(a,b,c){var d,e,g,f,h,j;if(c==0)d=e=g=0;else switch(f=Math.floor(a*6),h=a*6-f,a=c*(1-b),j=c*(1-b*h),b=c*(1-b*(1-h)),f){case 1:d=j;e=c;g=a;break;case 2:d=a;e=c;g=b;break;case 3:d=a;e=j;g=c;break;case 4:d=b;e=a;g=c;break;case 5:d=c;e=a;g=j;break;case 6:case 0:d=c,e=b,g=a}this.setRGB(d,
e,g)},updateHex:function(){this.hex=~~(this.r*255)<<16^~~(this.g*255)<<8^~~(this.b*255)},updateRGB:function(){this.r=(this.hex>>16&255)/255;this.g=(this.hex>>8&255)/255;this.b=(this.hex&255)/255},clone:function(){return new THREE.Color(this.hex)}};THREE.Vector2=function(a,b){this.set(a||0,b||0)};
THREE.Vector2.prototype={set:function(a,b){this.x=a;this.y=b;return this},copy:function(a){this.x=a.x;this.y=a.y;return this},clone:function(){return new THREE.Vector2(this.x,this.y)},add:function(a,b){this.x=a.x+b.x;this.y=a.y+b.y;return this},addSelf:function(a){this.x+=a.x;this.y+=a.y;return this},sub:function(a,b){this.x=a.x-b.x;this.y=a.y-b.y;return this},subSelf:function(a){this.x-=a.x;this.y-=a.y;return this},multiplyScalar:function(a){this.x*=a;this.y*=a;return this},divideScalar:function(a){a?
(this.x/=a,this.y/=a):this.set(0,0);return this},negate:function(){return this.multiplyScalar(-1)},dot:function(a){return this.x*a.x+this.y*a.y},lengthSq:function(){return this.x*this.x+this.y*this.y},length:function(){return Math.sqrt(this.lengthSq())},normalize:function(){return this.divideScalar(this.length())},setLength:function(a){return this.normalize().multiplyScalar(a)},unit:function(){return this.normalize()}};THREE.Vector3=function(a,b,c){this.set(a||0,b||0,c||0)};
(this.x/=a,this.y/=a):this.set(0,0);return this},negate:function(){return this.multiplyScalar(-1)},dot:function(a){return this.x*a.x+this.y*a.y},lengthSq:function(){return this.x*this.x+this.y*this.y},length:function(){return Math.sqrt(this.lengthSq())},normalize:function(){return this.divideScalar(this.length())},distanceTo:function(a){return Math.sqrt(this.distanceToSquared(a))},distanceToSquared:function(a){var b=this.x-a.x,a=this.y-a.y;return b*b+a*a},setLength:function(a){return this.normalize().multiplyScalar(a)},
unit:function(){return this.normalize()},equals:function(a){return a.x==this.x&&a.y==this.y}};THREE.Vector3=function(a,b,c){this.set(a||0,b||0,c||0)};
THREE.Vector3.prototype={set:function(a,b,c){this.x=a;this.y=b;this.z=c;return this},copy:function(a){this.x=a.x;this.y=a.y;this.z=a.z;return this},clone:function(){return new THREE.Vector3(this.x,this.y,this.z)},add:function(a,b){this.x=a.x+b.x;this.y=a.y+b.y;this.z=a.z+b.z;return this},addSelf:function(a){this.x+=a.x;this.y+=a.y;this.z+=a.z;return this},addScalar:function(a){this.x+=a;this.y+=a;this.z+=a;return this},sub:function(a,b){this.x=a.x-b.x;this.y=a.y-b.y;this.z=a.z-b.z;return this},subSelf:function(a){this.x-=
a.x;this.y-=a.y;this.z-=a.z;return this},multiply:function(a,b){this.x=a.x*b.x;this.y=a.y*b.y;this.z=a.z*b.z;return this},multiplySelf:function(a){this.x*=a.x;this.y*=a.y;this.z*=a.y;return this},multiplyScalar:function(a){this.x*=a;this.y*=a;this.z*=a;return this},divideSelf:function(a){return this.divide(this,a)},divideScalar:function(a){a?(this.x/=a,this.y/=a,this.z/=a):this.set(0,0,0);return this},negate:function(){return this.multiplyScalar(-1)},dot:function(a){return this.x*a.x+this.y*a.y+this.z*
a.z},lengthSq:function(){return this.x*this.x+this.y*this.y+this.z*this.z},length:function(){return Math.sqrt(this.lengthSq())},lengthManhattan:function(){return this.x+this.y+this.z},normalize:function(){return this.divideScalar(this.length())},setLength:function(a){return this.normalize().multiplyScalar(a)},cross:function(a,b){this.x=a.y*b.z-a.z*b.y;this.y=a.z*b.x-a.x*b.z;this.z=a.x*b.y-a.y*b.x;return this},crossSelf:function(a){return this.set(this.y*a.z-this.z*a.y,this.z*a.x-this.x*a.z,this.x*
......
......@@ -3,7 +3,8 @@ var THREE=THREE||{};if(!window.Int32Array)window.Int32Array=Array,window.Float32
THREE.Color.prototype={copy:function(a){this.r=a.r;this.g=a.g;this.b=a.b;this.hex=a.hex},setHex:function(a){this.hex=~~a&16777215;this.updateRGB()},setRGB:function(a,b,c){this.r=a;this.g=b;this.b=c;this.updateHex()},setHSV:function(a,b,c){var d,e,g,f,h,i;if(c==0)d=e=g=0;else switch(f=Math.floor(a*6),h=a*6-f,a=c*(1-b),i=c*(1-b*h),b=c*(1-b*(1-h)),f){case 1:d=i;e=c;g=a;break;case 2:d=a;e=c;g=b;break;case 3:d=a;e=i;g=c;break;case 4:d=b;e=a;g=c;break;case 5:d=c;e=a;g=i;break;case 6:case 0:d=c,e=b,g=a}this.setRGB(d,
e,g)},updateHex:function(){this.hex=~~(this.r*255)<<16^~~(this.g*255)<<8^~~(this.b*255)},updateRGB:function(){this.r=(this.hex>>16&255)/255;this.g=(this.hex>>8&255)/255;this.b=(this.hex&255)/255},clone:function(){return new THREE.Color(this.hex)}};THREE.Vector2=function(a,b){this.set(a||0,b||0)};
THREE.Vector2.prototype={set:function(a,b){this.x=a;this.y=b;return this},copy:function(a){this.x=a.x;this.y=a.y;return this},clone:function(){return new THREE.Vector2(this.x,this.y)},add:function(a,b){this.x=a.x+b.x;this.y=a.y+b.y;return this},addSelf:function(a){this.x+=a.x;this.y+=a.y;return this},sub:function(a,b){this.x=a.x-b.x;this.y=a.y-b.y;return this},subSelf:function(a){this.x-=a.x;this.y-=a.y;return this},multiplyScalar:function(a){this.x*=a;this.y*=a;return this},divideScalar:function(a){a?
(this.x/=a,this.y/=a):this.set(0,0);return this},negate:function(){return this.multiplyScalar(-1)},dot:function(a){return this.x*a.x+this.y*a.y},lengthSq:function(){return this.x*this.x+this.y*this.y},length:function(){return Math.sqrt(this.lengthSq())},normalize:function(){return this.divideScalar(this.length())},setLength:function(a){return this.normalize().multiplyScalar(a)},unit:function(){return this.normalize()}};THREE.Vector3=function(a,b,c){this.set(a||0,b||0,c||0)};
(this.x/=a,this.y/=a):this.set(0,0);return this},negate:function(){return this.multiplyScalar(-1)},dot:function(a){return this.x*a.x+this.y*a.y},lengthSq:function(){return this.x*this.x+this.y*this.y},length:function(){return Math.sqrt(this.lengthSq())},normalize:function(){return this.divideScalar(this.length())},distanceTo:function(a){return Math.sqrt(this.distanceToSquared(a))},distanceToSquared:function(a){var b=this.x-a.x,a=this.y-a.y;return b*b+a*a},setLength:function(a){return this.normalize().multiplyScalar(a)},
unit:function(){return this.normalize()},equals:function(a){return a.x==this.x&&a.y==this.y}};THREE.Vector3=function(a,b,c){this.set(a||0,b||0,c||0)};
THREE.Vector3.prototype={set:function(a,b,c){this.x=a;this.y=b;this.z=c;return this},copy:function(a){this.x=a.x;this.y=a.y;this.z=a.z;return this},clone:function(){return new THREE.Vector3(this.x,this.y,this.z)},add:function(a,b){this.x=a.x+b.x;this.y=a.y+b.y;this.z=a.z+b.z;return this},addSelf:function(a){this.x+=a.x;this.y+=a.y;this.z+=a.z;return this},addScalar:function(a){this.x+=a;this.y+=a;this.z+=a;return this},sub:function(a,b){this.x=a.x-b.x;this.y=a.y-b.y;this.z=a.z-b.z;return this},subSelf:function(a){this.x-=
a.x;this.y-=a.y;this.z-=a.z;return this},multiply:function(a,b){this.x=a.x*b.x;this.y=a.y*b.y;this.z=a.z*b.z;return this},multiplySelf:function(a){this.x*=a.x;this.y*=a.y;this.z*=a.y;return this},multiplyScalar:function(a){this.x*=a;this.y*=a;this.z*=a;return this},divideSelf:function(a){return this.divide(this,a)},divideScalar:function(a){a?(this.x/=a,this.y/=a,this.z/=a):this.set(0,0,0);return this},negate:function(){return this.multiplyScalar(-1)},dot:function(a){return this.x*a.x+this.y*a.y+this.z*
a.z},lengthSq:function(){return this.x*this.x+this.y*this.y+this.z*this.z},length:function(){return Math.sqrt(this.lengthSq())},lengthManhattan:function(){return this.x+this.y+this.z},normalize:function(){return this.divideScalar(this.length())},setLength:function(a){return this.normalize().multiplyScalar(a)},cross:function(a,b){this.x=a.y*b.z-a.z*b.y;this.y=a.z*b.x-a.x*b.z;this.z=a.x*b.y-a.y*b.x;return this},crossSelf:function(a){return this.set(this.y*a.z-this.z*a.y,this.z*a.x-this.x*a.z,this.x*
......
此差异已折叠。
......@@ -3,7 +3,8 @@ var THREE=THREE||{};if(!window.Int32Array)window.Int32Array=Array,window.Float32
THREE.Color.prototype={copy:function(a){this.r=a.r;this.g=a.g;this.b=a.b;this.hex=a.hex},setHex:function(a){this.hex=~~a&16777215;this.updateRGB()},setRGB:function(a,b,c){this.r=a;this.g=b;this.b=c;this.updateHex()},setHSV:function(a,b,c){var d,e,g,f,h,i;if(c==0)d=e=g=0;else switch(f=Math.floor(a*6),h=a*6-f,a=c*(1-b),i=c*(1-b*h),b=c*(1-b*(1-h)),f){case 1:d=i;e=c;g=a;break;case 2:d=a;e=c;g=b;break;case 3:d=a;e=i;g=c;break;case 4:d=b;e=a;g=c;break;case 5:d=c;e=a;g=i;break;case 6:case 0:d=c,e=b,g=a}this.setRGB(d,
e,g)},updateHex:function(){this.hex=~~(this.r*255)<<16^~~(this.g*255)<<8^~~(this.b*255)},updateRGB:function(){this.r=(this.hex>>16&255)/255;this.g=(this.hex>>8&255)/255;this.b=(this.hex&255)/255},clone:function(){return new THREE.Color(this.hex)}};THREE.Vector2=function(a,b){this.set(a||0,b||0)};
THREE.Vector2.prototype={set:function(a,b){this.x=a;this.y=b;return this},copy:function(a){this.x=a.x;this.y=a.y;return this},clone:function(){return new THREE.Vector2(this.x,this.y)},add:function(a,b){this.x=a.x+b.x;this.y=a.y+b.y;return this},addSelf:function(a){this.x+=a.x;this.y+=a.y;return this},sub:function(a,b){this.x=a.x-b.x;this.y=a.y-b.y;return this},subSelf:function(a){this.x-=a.x;this.y-=a.y;return this},multiplyScalar:function(a){this.x*=a;this.y*=a;return this},divideScalar:function(a){a?
(this.x/=a,this.y/=a):this.set(0,0);return this},negate:function(){return this.multiplyScalar(-1)},dot:function(a){return this.x*a.x+this.y*a.y},lengthSq:function(){return this.x*this.x+this.y*this.y},length:function(){return Math.sqrt(this.lengthSq())},normalize:function(){return this.divideScalar(this.length())},setLength:function(a){return this.normalize().multiplyScalar(a)},unit:function(){return this.normalize()}};THREE.Vector3=function(a,b,c){this.set(a||0,b||0,c||0)};
(this.x/=a,this.y/=a):this.set(0,0);return this},negate:function(){return this.multiplyScalar(-1)},dot:function(a){return this.x*a.x+this.y*a.y},lengthSq:function(){return this.x*this.x+this.y*this.y},length:function(){return Math.sqrt(this.lengthSq())},normalize:function(){return this.divideScalar(this.length())},distanceTo:function(a){return Math.sqrt(this.distanceToSquared(a))},distanceToSquared:function(a){var b=this.x-a.x,a=this.y-a.y;return b*b+a*a},setLength:function(a){return this.normalize().multiplyScalar(a)},
unit:function(){return this.normalize()},equals:function(a){return a.x==this.x&&a.y==this.y}};THREE.Vector3=function(a,b,c){this.set(a||0,b||0,c||0)};
THREE.Vector3.prototype={set:function(a,b,c){this.x=a;this.y=b;this.z=c;return this},copy:function(a){this.x=a.x;this.y=a.y;this.z=a.z;return this},clone:function(){return new THREE.Vector3(this.x,this.y,this.z)},add:function(a,b){this.x=a.x+b.x;this.y=a.y+b.y;this.z=a.z+b.z;return this},addSelf:function(a){this.x+=a.x;this.y+=a.y;this.z+=a.z;return this},addScalar:function(a){this.x+=a;this.y+=a;this.z+=a;return this},sub:function(a,b){this.x=a.x-b.x;this.y=a.y-b.y;this.z=a.z-b.z;return this},subSelf:function(a){this.x-=
a.x;this.y-=a.y;this.z-=a.z;return this},multiply:function(a,b){this.x=a.x*b.x;this.y=a.y*b.y;this.z=a.z*b.z;return this},multiplySelf:function(a){this.x*=a.x;this.y*=a.y;this.z*=a.y;return this},multiplyScalar:function(a){this.x*=a;this.y*=a;this.z*=a;return this},divideSelf:function(a){return this.divide(this,a)},divideScalar:function(a){a?(this.x/=a,this.y/=a,this.z/=a):this.set(0,0,0);return this},negate:function(){return this.multiplyScalar(-1)},dot:function(a){return this.x*a.x+this.y*a.y+this.z*
a.z},lengthSq:function(){return this.x*this.x+this.y*this.y+this.z*this.z},length:function(){return Math.sqrt(this.lengthSq())},lengthManhattan:function(){return this.x+this.y+this.z},normalize:function(){return this.divideScalar(this.length())},setLength:function(a){return this.normalize().multiplyScalar(a)},cross:function(a,b){this.x=a.y*b.z-a.z*b.y;this.y=a.z*b.x-a.x*b.z;this.z=a.x*b.y-a.y*b.x;return this},crossSelf:function(a){return this.set(this.y*a.z-this.z*a.y,this.z*a.x-this.x*a.z,this.x*
......
此差异已折叠。
<!DOCTYPE HTML>
<html lang="en">
<head>
<title>three.js canvas/webgl - geometry - text</title>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width; initial-scale=1.0; maximum-scale=1.0; user-scalable=0;"/>
<style type="text/css">
body {
font-family: Monospace;
background-color: #f0f0f0;
margin: 0px;
overflow: hidden;
}
</style>
</head>
<body>
<script type="text/javascript" src="../build/Three.js"></script>
<script type="text/javascript" src="js/RequestAnimationFrame.js"></script>
<script type="text/javascript" src="js/Stats.js"></script>
<!-- load the font file from canvas-text -->
<script type="text/javascript" src="js/helvetiker-normal-normal.js"></script>
<script type="text/javascript">
var container, stats;
var camera, scene, renderer;
var text, plane;
var targetRotation = 0;
var targetRotationOnMouseDown = 0;
var mouseX = 0;
var mouseXOnMouseDown = 0;
var windowHalfX = window.innerWidth / 2;
var windowHalfY = window.innerHeight / 2;
init();
animate();
function init() {
container = document.createElement( 'div' );
document.body.appendChild( container );
var info = document.createElement( 'div' );
info.style.position = 'absolute';
info.style.top = '10px';
info.style.width = '100%';
info.style.textAlign = 'center';
info.innerHTML = 'Simple Dynamic 3D Text Example by <a href="http://www.lab4games.net/zz85/blog">zz85</a><br/>Drag to spin the text';
container.appendChild( info );
camera = new THREE.Camera( 50, window.innerWidth / window.innerHeight, 1, 1000 );
camera.position.y = 150;
camera.position.z = 500;
camera.target.position.y = 150;
scene = new THREE.Scene();
// Get text from hash
var theText = "Hello three.js! :)";
var hash = document.location.hash.substr( 1 );
if ( hash.length !== 0 ) {
theText = hash;
}
var text3d = new THREE.Text( theText, {
size: 80,
height: 20,
curveSegments: 2,
font: "helvetiker"
});
var textMaterial = new THREE.MeshBasicMaterial( { color: Math.random() * 0xffffff, wireframe:false } );
text = new THREE.Mesh( text3d, textMaterial );
text.doubleSided = false;
text.position.y = 0;
text.position.y = 100;
text.position.z = 0;
text.rotation.x = 0;
text.rotation.y = Math.PI*2;
text.overdraw = true;
scene.addObject( text );
// Plane
plane = new THREE.Mesh( new THREE.Plane( 800, 800 ), new THREE.MeshBasicMaterial( { color: 0xe0e0e0, wireframe:true }) );
plane.rotation.x = - 90 * ( Math.PI / 180 );
plane.position.x = 0;
plane.overdraw = true;
//scene.addObject( plane );
renderer = new THREE.CanvasRenderer();
renderer.setSize( window.innerWidth, window.innerHeight );
container.appendChild( renderer.domElement );
stats = new Stats();
stats.domElement.style.position = 'absolute';
stats.domElement.style.top = '0px';
container.appendChild( stats.domElement );
document.addEventListener( 'mousedown', onDocumentMouseDown, false );
document.addEventListener( 'touchstart', onDocumentTouchStart, false );
document.addEventListener( 'touchmove', onDocumentTouchMove, false );
}
//
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() {
plane.rotation.z = text.rotation.y += ( targetRotation - text.rotation.y ) * 0.05;
renderer.render( scene, camera );
}
</script>
</body>
</html>
此差异已折叠。
......@@ -2,6 +2,7 @@
* @author mr.doob / http://mrdoob.com/
* @author philogb / http://blog.thejit.org/
* @author egraether / http://egraether.com/
* @author zz85 / http://www.lab4games.net/zz85/blog
*/
THREE.Vector2 = function ( x, y ) {
......@@ -134,6 +135,20 @@ THREE.Vector2.prototype = {
return this.divideScalar( this.length() );
},
distanceTo : function ( v ) {
return Math.sqrt( this.distanceToSquared( v ) );
},
distanceToSquared : function ( v ) {
var dx = this.x - v.x, dy = this.y - v.y;
return dx * dx + dy * dy;
},
setLength : function ( l ) {
......@@ -149,6 +164,10 @@ THREE.Vector2.prototype = {
// this.multiplyScalar( 1 / this.length() );
// return this;
},
equals : function(v) {
return ( (v.x == this.x) && (v.y == this.y) );
}
};
/**
* @author zz85 / http://www.lab4games.net/zz85/blog
*
* For creating 3D text geometry in three.js
*
* It utilizes techniques used in
*
* typeface.js and canvastext
* For converting fonts and rendering with javascript
* http://typeface.neocracy.org
*
* Triangulation ported from AS3
* Simple Polygon Triangulation
* http://actionsnippet.com/?p=1462
*
* A Method to triangulate shapes with holes
* http://www.sakri.net/blog/2009/06/12/an-approach-to-triangulating-polygons-with-holes/
*
*/
THREE.Text = function ( text, parameters ) {
THREE.Geometry.call( this );
parameters = parameters || {};
var size = parameters.size !== undefined ? parameters.size : 100;
var height = parameters.height !== undefined ? parameters.height : 50;
var curveSegments = parameters.curveSegments !== undefined ? parameters.curveSegments: 4;
var font = parameters.font !== undefined ? parameters.font : "helvetiker";
THREE.FontUtils.size = size;
THREE.FontUtils.divisions = curveSegments;
// Get a Font data json object
var data = THREE.FontUtils.drawText( text );
//console.log( "data", data );
vertices = data.points;
faces = data.faces;
contour = data.contour;
var scope = this;
var i, face, vert, vlen = 0;
for ( i in vertices ) {
vert = vertices[ i ];
v( vert.x, vert.y, 0 );
vlen++;
}
for ( i in vertices ) {
vert = vertices[ i ];
v( vert.x, vert.y, height );
}
// Bottom faces
for ( i in faces ) {
face = faces[ i ];
f3( face[ 2 ], face[ 1 ], face[ 0 ] );
}
// Top faces
for ( i in faces ) {
face = faces[ i ];
f3( face[ 0 ] + vlen, face[ 1 ] + vlen, face[ 2 ] + vlen );
}
i = contour.length;
var j, k, lastV;
while ( --i > 0 ) {
if ( ! lastV ) {
lastV = contour[ i ];
} else if ( lastV.equals( contour[ i ] ) ) {
lastV = null;
continue;
}
for ( j = 0; j < vertices.length; j++ ) {
if ( vertices[ j ].equals( contour[ i ] ) ) break;
}
for ( k = 0; k < vertices.length; k++ ) {
if ( vertices[ k ].equals( contour[ i - 1 ] ) ) break;
}
f4( j, k, k + vlen, j + vlen );
}
// UVs to be added
this.computeCentroids();
this.computeFaceNormals();
//this.computeVertexNormals();
function v( x, y, z ) {
scope.vertices.push( new THREE.Vertex( new THREE.Vector3( x, y, z ) ) );
}
function f3( a, b, c) {
scope.faces.push( new THREE.Face3( a, b, c) );
}
function f4( a, b, c, d) {
scope.faces.push( new THREE.Face4( a, b, c, d) );
}
};
THREE.Text.prototype = new THREE.Geometry();
THREE.Text.prototype.constructor = THREE.Text;
THREE.FontUtils = {
faces : {},
// Just for now. face[weight][style]
face : "helvetiker",
weight: "normal",
style : "normal",
size : 150,
divisions : 10,
getFace : function() {
return this.faces[ this.face ][ this.weight ][ this.style ];
},
loadFace : function( data ) {
var family = data.familyName.toLowerCase();
var ThreeFont = this;
ThreeFont.faces[ family ] = ThreeFont.faces[ family ] || {};
ThreeFont.faces[ family ][ data.cssFontWeight ] = ThreeFont.faces[ family ][ data.cssFontWeight ] || {};
ThreeFont.faces[ family ][ data.cssFontWeight ][ data.cssFontStyle ] = data;
var face = ThreeFont.faces[ family ][ data.cssFontWeight ][ data.cssFontStyle ] = data;
return data;
},
extractPoints : function( points ) {
// Quick Exit
if ( points.length < 3 ) {
console.log( "not valid polygon" );
return;
}
// Try to split shapes and holes.
var all = [], point, shape;
var isolatedShapes = [];
// Use a quick hashmap for locating duplicates
for ( var p in points ) {
point = points[ p ];
all.push( point.x + "," + point.y );
}
var firstPt = all[ 0 ];
var endPt = all.slice( 1 ).indexOf( firstPt );
if ( endPt < all.length ) {
endPt ++;
shape = points.slice( 0, endPt );
}
holes = [];
while ( endPt < all.length ) {
firstIndex = endPt + 1;
firstPt = all[ firstIndex ];
endPt = all.slice( firstIndex + 1 ).indexOf( firstPt ) + firstIndex;
if ( endPt <= firstIndex ) break;
var contours = points.slice( firstIndex, endPt + 1 );
if ( this.Triangulate.area( contours ) < 0 ) {
isolatedShapes.push( { shape: shape, holes: holes } );
// Save the old shapes, then work on new additional separated shape
shape = contours;
holes = [];
} else {
holes.push( contours );
}
endPt++;
}
isolatedShapes.push( { shape: shape, holes: holes } );
//console.log("isolatedShapes", isolatedShapes);
// For each isolated shape, find the closest points and break to the hole to allow triangulation
// Find closest points between holes
// we could optimize with
// http://en.wikipedia.org/wiki/Proximity_problems
// http://en.wikipedia.org/wiki/Closest_pair_of_points
// http://stackoverflow.com/questions/1602164/shortest-distance-between-points-algorithm
var verts = [];
for ( var shapeId in isolatedShapes ) {
var shapeGroup = isolatedShapes[ shapeId ];
shape = shapeGroup.shape;
holes = shapeGroup.holes;
for ( var h in holes ) {
// we slice to each hole when neccessary
var hole = holes[ h ];
var shortest = Number.POSITIVE_INFINITY;
var holeIndex, shapeIndex;
for ( var h2 in hole ) {
var pts1 = hole[ h2 ];
for ( var p in shape ) {
var pts2 = shape[ p ];
d = pts1.distanceTo( pts2 );
if ( d<shortest ) {
shortest = d;
holeIndex = h2;
shapeIndex = p;
}
}
}
prevShapeVert = ( shapeIndex - 1 ) >= 0 ? shapeIndex - 1 : shape.length - 1;
nextShapeVert = ( shapeIndex + 1 ) < shape.length ? shapeIndex + 1 : 0;
prevHoleVert = ( holeIndex - 1 ) >= 0 ? holeIndex - 1 : hole.length - 1;
nextHoleVert = ( holeIndex + 1 ) < hole.length ? holeIndex + 1 : 0 ;
var tmpShape1 = shape.slice( 0, shapeIndex );
var tmpShape2 = shape.slice( shapeIndex );
var tmpHole1 = hole.slice( holeIndex );
var tmpHole2 = hole.slice( 0, holeIndex );
verts.push( hole[ holeIndex ] );
verts.push( shape[ shapeIndex ] );
verts.push( shape[ prevShapeVert ] );
verts.push( hole[ holeIndex ] );
verts.push( hole[ prevHoleVert ] );
verts.push( shape[ shapeIndex ] );
shapeGroup.shape = tmpShape1.concat( tmpHole1 ).concat( tmpHole2 ).concat( tmpShape2 );
}
}
points = [];
var triangulatedVertices = [];
var lastTriangles = 0;
for ( var shapeId in isolatedShapes ) {
var shapeGroup = isolatedShapes[ shapeId ];
shape = shapeGroup.shape;
points = points.concat( shape );
var triangles = THREE.FontUtils.Triangulate( shape, true );
// We need to offset vertex indices for faces
for ( var v in triangles ) {
var face = triangles[ v ];
face[ 0 ] += lastTriangles;
face[ 1 ] += lastTriangles;
face[ 2 ] += lastTriangles;
}
triangulatedVertices = triangulatedVertices.concat( triangles );
lastTriangles += shape.length;
}
// Now we push the "cutted" vertices back to the triangulated indices.
//console.log("we have verts.length",verts.length);
var j;
for ( var v = 0; v < verts.length / 3; v++ ) {
var face = [];
for ( var k = 0; k < 3; k++ ) {
for ( j = 0; j < points.length; j++ ) {
var l = v * 3 + k;
if ( points[ j ].equals( verts[ l ] ) ) {
face.push( j );
break;
}
}
}
triangulatedVertices.push( face );
}
//console.log("triangles", triangulatedVertices.length, "points", points);
return {
points: points,
faces: triangulatedVertices
};
},
drawText : function( text ) {
var pts = [];
// RenderText
var face = this.getFace(),
scale = ( this.size / face.resolution ),
offset = 0, i,
chars = String( text ).split( '' ),
length = chars.length;
for ( i = 0; i < length; i++ ) {
offset += this.extractGlyphPoints( pts, chars[ i ], face, scale, offset );
}
// get the width
var width = offset / 2;
for ( var p in pts ) {
pts[ p ].x -= width;
}
var extract = this.extractPoints( pts );
extract.contour = pts;
return extract;
},
// Bezier Curves formuals obtained from
// http://en.wikipedia.org/wiki/B%C3%A9zier_curve
// Quad Bezier Functions
b2p0: function ( t, p ) {
return ( 1 - t ) * ( 1 - t ) * p;
},
b2p1: function ( t, p ) {
return 2 * ( 1 - t ) * t * p;
},
b2p2: function ( t, p ) {
return t * t * p;
},
b2: function ( t, p0, p1, p2 ) {
return this.b2p0( t, p0 ) + this.b2p1( t, p1 ) + this.b2p2( t, p2 );
},
// Cubic Bezier Functions
b3p0: function ( t, p ) {
var k = 1 - t;
return k * k * k * p;
},
b3p1: function ( t, p ) {
var k = 1 - t;
return 3 * k * k * t * p;
},
b3p2: function ( t, p ) {
var k = 1 - t;
return 3 * k * t * t * p;
},
b3p3: function ( t, p ) {
return t * t * t * p;
},
b3: function ( t, p0, p1, p2, p3 ) {
return this.b3p0( t, p0 ) + this.b3p1( t, p1 ) + this.b3p2( t, p2 ) + this.b3p3( t, p3 );
},
extractGlyphPoints : function( pts, c, face, scale, offset ) {
var i, cpx, cpy, outline, action, length,
glyph = face.glyphs[ c ] || face.glyphs[ ctxt.options.fallbackCharacter ];
if ( !glyph ) return;
if ( glyph.o ) {
outline = glyph._cachedOutline || ( glyph._cachedOutline = glyph.o.split( ' ' ) );
length = outline.length;
var scaleX = scale;
var scaleY = scale;
for ( i = 0; i < length; ) {
action = outline[i++];
switch( action ) {
case 'm':
// Move To
x = outline[ i++ ] * scaleX + offset;
y = outline[ i++ ] * scaleY;
pts.push( new THREE.Vector2( x, y ) );
break;
case 'l':
// Line To
x = outline[ i++ ] * scaleX + offset;
y = outline[ i++ ] * scaleY;
pts.push( new THREE.Vector2( x, y ) );
break;
case 'q':
// quadraticCurveTo
cpx = outline[ i++ ] * scaleX + offset;
cpy = outline[ i++ ] * scaleY;
cpx1 = outline[ i++ ] * scaleX + offset;
cpy1 = outline[ i++ ] * scaleY;
var laste = pts[ pts.length - 1 ];
if ( laste ) {
cpx0 = laste.x;
cpy0 = laste.y;
for ( var i2 = 1, divisions = this.divisions; i2 <= divisions; i2++ ) {
var t = i2 / divisions;
var tx = THREE.FontUtils.b2( t, cpx0, cpx1, cpx );
var ty = THREE.FontUtils.b2( t, cpy0, cpy1, cpy );
pts.push( new THREE.Vector2( tx, ty ) );
}
}
break;
case 'b':
// Cubic Bezier Curve
cpx = outline[ i++ ] * scaleX + offset;
cpy = outline[ i++ ] * scaleY;
cpx1 = outline[ i++ ] * scale + offset;
cpy1 = outline[ i++ ] * -scale;
cpx2 = outline[ i++ ] * scale + offset;
cpy2 = outline[ i++ ] * -scale;
var laste = pts[ pts.length - 1 ];
if ( laste ) {
cpx0 = laste.x;
cpy0 = laste.y;
for ( var i2 = 1, divisions = this.divisions; i2 <= divisions; i2++ ) {
var t = i2 / divisions;
var tx = THREE.FontUtils.b3( t, cpx0, cpx1, cpx2, cpx );
var ty = THREE.FontUtils.b3( t, cpy0, cpy1, cpy2, cpy );
pts.push( new THREE.Vector2( tx, ty ) );
}
}
break;
}
}
}
return glyph.ha * scale;
}
};
/**
* This code is a quick port of code written in C++ which was submitted to
* flipcode.com by John W. Ratcliff // July 22, 2000
* See original code and more information here:
* http://www.flipcode.com/archives/Efficient_Polygon_Triangulation.shtml
*
* ported to actionscript by Zevan Rosser
* www.actionsnippet.com
*
* ported to javascript by Joshua Koo
* http://www.lab4games.net/zz85/blog
*
*/
( function( namespace ) {
var EPSILON = 0.0000000001;
// takes in an contour array and returns
var process = function( contour, indices ) {
var result = [];
var n = contour.length;
if ( n < 3 ) return null
var verts = [], vertIndices = [];
/* we want a counter-clockwise polygon in verts */
var v;
if ( 0.0 < area( contour ) ) {
for ( v = 0; v < n; v++ ) verts[ v ] = v;
} else {
for ( v=0; v < n; v++ ) verts[ v ] = ( n - 1 ) - v;
}
var nv = n;
/* remove nv-2 vertices, creating 1 triangle every time */
var count = 2 * nv; /* error detection */
var m;
for( m = 0, v = nv - 1; nv > 2; ) {
/* if we loop, it is probably a non-simple polygon */
if ( 0 >= ( count-- ) ){
//** Triangulate: ERROR - probable bad polygon!
console.log( "Warning, unable to triangulate polygon!" );
return null;
}
/* three consecutive vertices in current polygon, <u,v,w> */
var u = v; if ( nv <= u ) u = 0; /* previous */
v = u + 1; if ( nv <= v ) v = 0; /* new v */
var w = v + 1; if ( nv <= w ) w = 0; /* next */
if ( snip( contour, u, v, w, nv, verts ) ) {
var a, b, c, s, t;
/* true names of the vertices */
a = verts[ u ];
b = verts[ v ];
c = verts[ w ];
/* output Triangle */
result.push( contour[ a ] );
result.push( contour[ b ] );
result.push( contour[ c ] );
vertIndices.push( [ verts[ u ], verts[ v ], verts[ w ] ] );
//vertIndices.push( THREE.Face3( verts[ u ], verts[ v ], verts[ w ] ) );
m++;
/* remove v from remaining polygon */
for( s = v, t = v + 1; t < nv; s++, t++ ) {
verts[ s ] = verts[ t ];
}
nv--;
/* resest error detection counter */
count = 2 * nv;
}
}
if ( indices ) return vertIndices;
return result;
};
// calculate area of the contour polygon
var area = function ( contour ){
var n = contour.length;
var a = 0.0;
for( var p = n - 1, q = 0; q < n; p = q++ ){
a += contour[ p ].x * contour[ q ].y - contour[ q ].x * contour[ p ].y;
}
return a * 0.5;
};
// see if p is inside triangle abc
var insideTriangle = function(ax, ay, bx, by, cx, cy, px, py) {
var aX, aY, bX, bY;
var cX, cY, apx, apy;
var bpx, bpy, cpx, cpy;
var cCROSSap, bCROSScp, aCROSSbp;
aX = cx - bx; aY = cy - by;
bX = ax - cx; bY = ay - cy;
cX = bx - ax; cY = by - ay;
apx= px -ax; apy= py - ay;
bpx= px - bx; bpy= py - by;
cpx= px - cx; cpy= py - cy;
aCROSSbp = aX*bpy - aY*bpx;
cCROSSap = cX*apy - cY*apx;
bCROSScp = bX*cpy - bY*cpx;
return ( ( aCROSSbp >= 0.0 ) && ( bCROSScp >= 0.0 ) && ( cCROSSap >= 0.0 ) );
};
var snip = function ( contour, u, v, w, n, verts ) {
var p;
var ax, ay, bx, by;
var cx, cy, px, py;
ax = contour[ verts[ u ] ].x;
ay = contour[ verts[ u ] ].y;
bx = contour[ verts[ v ] ].x;
by = contour[ verts[ v ] ].y;
cx = contour[ verts[ w ] ].x;
cy = contour[ verts[ w ] ].y;
if ( EPSILON > ( ( ( bx - ax ) * ( cy - ay ) ) - ( ( by - ay ) * ( cx - ax ) ) ) ) return false;
for ( p = 0; p < n; p++ ) {
if( ( p == u ) || ( p == v ) || ( p == w ) ) continue;
px = contour[ verts[ p ] ].x
py = contour[ verts[ p ] ].y
if ( insideTriangle( ax, ay, bx, by, cx, cy, px, py ) ) return false;
}
return true;
};
namespace.Triangulate = process;
namespace.Triangulate.area = area;
return namespace;
})( THREE.FontUtils );
// To use the typeface.js face files, hook up the API
window._typeface_js = { faces: THREE.FontUtils.faces, loadFace: THREE.FontUtils.loadFace };
......@@ -102,6 +102,7 @@ EXTRAS_FILES = [
'extras/geometries/Sphere.js',
'extras/geometries/Torus.js',
'extras/geometries/TorusKnot.js',
'extras/geometries/Text.js',
'extras/io/Loader.js',
'extras/io/JSONLoader.js',
'extras/io/BinaryLoader.js',
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册