Explorar o código

Add example Resolution-Independent Vector Fonts rendering with WebGL

See #4746
Joshua Koo %!s(int64=11) %!d(string=hai) anos
pai
achega
a1928a83d9
Modificáronse 1 ficheiros con 404 adicións e 0 borrados
  1. 404 0
      examples/webgl_shaders_vector.html

+ 404 - 0
examples/webgl_shaders_vector.html

@@ -0,0 +1,404 @@
+<!DOCTYPE html>
+<html lang="en">
+	<head>
+		<title>three.js webgl - vector - 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: #f0f0f0;
+				margin: 0px;
+				overflow: hidden;
+			}
+		</style>
+	</head>
+	<body>
+
+		<script src="../build/three.min.js"></script>
+		<script src="./js/controls/OrbitControls.js"></script>
+
+		<script src="js/libs/stats.min.js"></script>
+
+		<!-- load the font file from canvas-text -->
+
+		<script src="fonts/helvetiker_regular.typeface.js"></script>
+
+		<script type="x-shader/x-fragment" id="fs">
+
+			varying vec2 vUv;
+			varying float flip;
+			uniform vec3 color;
+			
+			float inCurve(vec2 uv) {
+				return uv.x * uv.x - uv.y;
+			}
+
+			float delta = 0.1;
+
+			void main() {
+				float x = inCurve(vUv);
+
+				if (x * flip > 0.) discard;
+				gl_FragColor = vec4(color, 1.);
+			}
+
+		</script>
+
+		<script type="x-shader/x-vertex" id="vs">
+
+			varying vec2 vUv;
+			attribute float invert;
+			varying float flip;
+
+			void main() {
+
+				vUv = uv;
+				flip = invert;
+				vec4 mvPosition = modelViewMatrix * vec4( position, 1.0 );
+				gl_Position = projectionMatrix * mvPosition;
+
+			}
+
+		</script>
+
+
+		<script>
+
+			var container, stats;
+
+			var camera, scene, renderer, controls;
+
+			var group, text;
+
+			var targetRotation = 0;
+			var targetRotationOnMouseDown = 0;
+
+			var mouseX = 0;
+			var mouseXOnMouseDown = 0;
+
+			var windowHalfX = window.innerWidth / 2;
+			var windowHalfY = window.innerHeight / 2;
+
+			var t = false;
+
+			function toggle() {
+
+				if ( t ) {
+
+					text2.visible = 0;
+					text1.visible = 1;
+
+				} else {
+
+					text2.visible = 1;
+					text1.visible = 0;
+
+				}
+
+				t = !t;
+			}
+
+			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 = 'Resolution-Independent Vector Fonts<br/><a href="https://github.com/mrdoob/three.js/issues/4746">rendered with three.js and WebGL </a>';
+				container.appendChild( info );
+
+				camera = new THREE.PerspectiveCamera( 50, window.innerWidth / window.innerHeight, 1, 1000 );
+				camera.position.set( 0, 150, 500 );
+
+
+				controls = new THREE.OrbitControls( camera );
+
+				scene = new THREE.Scene();
+
+				
+				var theText = "&"; // i % & j b 8
+
+				var options = {
+					size: 180,
+					height: 20,
+					curveSegments: 2,
+					font: "helvetiker",
+					bevelEnabled: false
+				};
+
+				group = new THREE.Object3D();
+				scene.add( group );
+
+
+				var textMaterial = new THREE.MeshBasicMaterial( { color: new THREE.Color(0, 0, 1 ), overdraw: 0.5, wireframe: true, side: THREE.DoubleSide } );
+
+				textShapes = THREE.FontUtils.generateShapes( theText, options );
+
+				text3d = new THREE.ShapeGeometry( textShapes );
+
+				text3d.computeBoundingBox();
+				var centerOffset = -0.5 * ( text3d.boundingBox.max.x - text3d.boundingBox.min.x );
+				text = new THREE.Mesh( text3d, textMaterial );
+
+				text.position.x = centerOffset - 150;
+				group.add( text );
+
+				//
+				
+				vA = new THREE.Vector2();
+				vB = new THREE.Vector2();
+				vDot = new THREE.Vector2();
+
+				function processShape(path, reverse) {
+
+					var pts = []; // bigger area (convex hull)
+					var pts2 = []; // smaller area (full solid shapes)
+					var beziers = []; // quad bezier points
+					var invert = [];
+					var z;
+
+					var wind;
+
+					pts.push( path[0].getPoint(0) );
+					pts2.push( path[0].getPoint(0) );
+
+					for (var i=0; i < path.length; i++) {
+						curve = path[i];
+						if (curve instanceof THREE.LineCurve) {
+							pts.push( curve.v2 );
+							pts2.push( curve.v2 );
+						} else if (curve instanceof THREE.QuadraticBezierCurve) {
+							vA = vA.subVectors( curve.v1, curve.v0 ); // .normalize()
+							vB = vB.subVectors( curve.v2, curve.v1 );
+							z = vA.x * vB.y - vA.y * vB.x; // z component of cross Production
+							wind = z < 0; // clockwise/anticlock wind
+							// if (reverse) wind = !wind;
+
+							// console.log(z, wind , wind ? 'clockwise' : 'anti');
+
+							if (wind) {
+								pts.push( curve.v1 );
+								pts.push( curve.v2 );
+								pts2.push( curve.v2 );
+							} else {
+								pts.push( curve.v2 );
+								pts2.push( curve.v1 );
+								pts2.push( curve.v2 );
+							}
+
+							var flip = wind ? 1 : -1;
+							// if (reverse) flip *= -1;
+
+							invert.push(flip, flip, flip);
+							beziers.push( curve.v0, curve.v1, curve.v2);
+
+						}
+					}
+
+					return {
+						pts: pts,
+						pts2: pts2,
+						beziers: beziers,
+						invert: invert
+					};
+				}
+
+				var subshape;
+				var convexhullShapeGroup = [];
+				var solidShapeGroup = [];
+
+				var beziers = [], invert = [];
+
+				for (var s=0;s<textShapes.length;s++) {
+
+					subshape = textShapes[s];
+					var process = processShape(subshape.curves);
+
+					pts = process.pts;
+					pts2 = process.pts2;
+					beziers = beziers.concat(process.beziers);
+					invert = invert.concat(process.invert);
+
+					convexhullShape = new THREE.Shape( pts );
+					solidShape = new THREE.Shape( pts2 );
+					
+					convexhullShapeGroup.push( convexhullShape );
+					solidShapeGroup.push( solidShape );
+
+					for (var i=0; i<subshape.holes.length;i++) {
+						hole = subshape.holes[i];
+						console.log('hole', hole);
+
+						process = processShape(hole.curves, true);
+
+						pts = process.pts;
+						pts2 = process.pts2;
+						beziers = beziers.concat(process.beziers);
+						invert = invert.concat(process.invert);
+
+						convexhullShape.holes.push(new THREE.Shape(pts));
+						solidShape.holes.push(new THREE.Shape(pts2));
+
+					}
+
+				} // end of subshape
+
+				bezierGeometry = new THREE.Geometry();
+
+				for (var i=0;i<beziers.length;i++) {
+					p = beziers[i];
+					bezierGeometry.vertices.push( new THREE.Vector3(p.x, p.y, 0) );			
+				}
+
+				for (i=0;i<beziers.length;i+=3) {
+					bezierGeometry.faces.push( new THREE.Face3(i, i+1, i+2) );
+					bezierGeometry.faceVertexUvs[0].push( [
+						new THREE.Vector2(0, 0),
+						new THREE.Vector2(0.5, 0),
+						new THREE.Vector2(1, 1)
+					] );
+				}
+
+				text3d = new THREE.ShapeGeometry( convexhullShapeGroup );
+				text3d.computeBoundingBox();
+				var centerOffset = -0.5 * ( text3d.boundingBox.max.x - text3d.boundingBox.min.x );
+				
+				text1 = new THREE.Mesh( text3d, textMaterial );
+
+				text1.position.x = centerOffset + 150;
+
+				group.add( text1 );
+
+				text3d = new THREE.ShapeGeometry( solidShapeGroup );
+				text3d.computeBoundingBox();
+				var centerOffset = -0.5 * ( text3d.boundingBox.max.x - text3d.boundingBox.min.x );
+				
+				text2 = new THREE.Mesh( text3d, new THREE.MeshBasicMaterial( { color: new THREE.Color(1, 0, 0 ), side: THREE.DoubleSide, wireframe: true } ) ); 
+
+				text2.position.x = centerOffset + 150;
+
+				group.add( text2 );
+
+				//
+				bezierGeometry.computeBoundingBox();
+				bezierGeometry.computeFaceNormals();
+				bezierGeometry.computeVertexNormals();
+				
+				// 
+
+				var uniforms = {
+					color: { type: 'c', value: new THREE.Color(0.45 * 0xffffff) }
+				};
+				var vertexShader = document.getElementById( 'vs' ).textContent;
+				var fragmentShader = document.getElementById( 'fs' ).textContent;
+
+
+				
+				newMaterial = new THREE.ShaderMaterial({
+					attributes: { invert: { type: 'f', value: invert } },
+					uniforms: uniforms,
+					vertexShader: vertexShader,
+					fragmentShader: fragmentShader,
+					side: THREE.DoubleSide
+				});
+
+
+				text = new THREE.Mesh( bezierGeometry, newMaterial );
+
+				text.position.x = centerOffset;
+				text.position.y = 0;
+				text.position.z = 0;
+
+				text.rotation.x = 0;
+				text.rotation.y = Math.PI * 2;
+
+				group.add( text );
+
+				//
+
+
+				text3d = new THREE.ShapeGeometry( solidShapeGroup );
+				text3d.computeBoundingBox();
+				
+				text = new THREE.Mesh( text3d, new THREE.MeshBasicMaterial( { color: 0.45 * 0xffffff, side: THREE.DoubleSide } ) );
+				text.position.x = centerOffset;
+				text.position.y = 0;
+				text.position.z = 0;
+
+				text.rotation.x = 0;
+				text.rotation.y = Math.PI * 2;
+
+				group.add( text );
+
+				//
+
+				renderer = new THREE.WebGLRenderer();
+				renderer.setClearColor( 0xf0f0f0 );
+				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 );
+
+				//
+
+				window.addEventListener( 'resize', onWindowResize, false );
+
+			}
+
+			function onWindowResize() {
+
+				windowHalfX = window.innerWidth / 2;
+				windowHalfY = window.innerHeight / 2;
+
+				camera.aspect = window.innerWidth / window.innerHeight;
+				camera.updateProjectionMatrix();
+
+				renderer.setSize( window.innerWidth, window.innerHeight );
+
+			}
+
+			//
+
+			function onDocumentMouseDown( event ) {
+
+				toggle();
+
+			}
+
+
+			//
+
+			function animate() {
+
+				requestAnimationFrame( animate );
+
+				render();
+				stats.update();
+
+			}
+
+			function render() {
+
+				controls.update();
+				renderer.render( scene, camera );
+
+			}
+
+		</script>
+
+	</body>
+</html>