Browse Source

New ShapeBufferGeometry (#9970)

* ShapeBufferGeometry: Initial commit

* ShapeBufferGeometry: Clean up
Michael Herzog 8 years ago
parent
commit
7ea23ec3a5

+ 71 - 0
docs/api/geometries/ShapeBufferGeometry.html

@@ -0,0 +1,71 @@
+<!DOCTYPE html>
+<html lang="en">
+	<head>
+		<meta charset="utf-8" />
+		<base href="../../" />
+		<script src="list.js"></script>
+		<script src="page.js"></script>
+		<link type="text/css" rel="stylesheet" href="page.css" />
+	</head>
+	<body>
+		[page:BufferGeometry] &rarr;
+
+		<h1>[name]</h1>
+
+		<div class="desc">Creates an one-sided polygonal geometry from one or more path shapes.</div>
+
+		<iframe id="scene" src="scenes/geometry-browser.html#ShapeBufferGeometry"></iframe>
+
+		<script>
+
+		// iOS iframe auto-resize workaround
+
+		if ( /(iPad|iPhone|iPod)/g.test( navigator.userAgent ) ) {
+
+			var scene = document.getElementById( 'scene' );
+
+			scene.style.width = getComputedStyle( scene ).width;
+			scene.style.height = getComputedStyle( scene ).height;
+			scene.setAttribute( 'scrolling', 'no' );
+
+		}
+
+		</script>
+
+
+		<h2>Example</h2>
+
+
+		<code>
+		var x = 0, y = 0;
+
+		var heartShape = new THREE.Shape();
+
+		heartShape.moveTo( x + 5, y + 5 );
+		heartShape.bezierCurveTo( x + 5, y + 5, x + 4, y, x, y );
+		heartShape.bezierCurveTo( x - 6, y, x - 6, y + 7,x - 6, y + 7 );
+		heartShape.bezierCurveTo( x - 6, y + 11, x - 3, y + 15.4, x + 5, y + 19 );
+		heartShape.bezierCurveTo( x + 12, y + 15.4, x + 16, y + 11, x + 16, y + 7 );
+		heartShape.bezierCurveTo( x + 16, y + 7, x + 16, y, x + 10, y );
+		heartShape.bezierCurveTo( x + 7, y, x + 5, y + 5, x + 5, y + 5 );
+
+		var geometry = new THREE.ShapeBufferGeometry( heartShape );
+		var material = new THREE.MeshBasicMaterial( { color: 0x00ff00 } );
+		var mesh = new THREE.Mesh( geometry, material ) ;
+		scene.add( mesh );
+		</code>
+
+		<h2>Constructor</h2>
+
+
+		<h3>[name]([page:Array shapes], [page:Integer curveSegments])</h3>
+		<div>
+		shapes — [page:Array] of shapes or a single [page:Shape shape].<br />
+		curveSegments - [page:Integer] - Number of segments per shape. Default is 12.
+		</div>
+
+		<h2>Source</h2>
+
+		[link:https://github.com/mrdoob/three.js/blob/master/src/[path].js src/[path].js]
+	</body>
+</html>

+ 15 - 39
docs/api/geometries/ShapeGeometry.html

@@ -12,7 +12,7 @@
 
 		<h1>[name]</h1>
 
-		<div class="desc">Creates a one-sided polygonal geometry from one or more path shapes. Similar to [page:ExtrudeGeometry].</div>
+		<div class="desc">Creates an one-sided polygonal geometry from one or more path shapes.</div>
 
 		<iframe id="scene" src="scenes/geometry-browser.html#ShapeGeometry"></iframe>
 
@@ -37,16 +37,19 @@
 
 
 		<code>
-		var length = 16, width = 12;
+		var x = 0, y = 0;
 
-		var shape = new THREE.Shape();
-		shape.moveTo( 0,0 );
-		shape.lineTo( 0, width );
-		shape.lineTo( length, width );
-		shape.lineTo( length, 0 );
-		shape.lineTo( 0, 0 );
+		var heartShape = new THREE.Shape();
 
-		var geometry = new THREE.ShapeGeometry( shape );
+		heartShape.moveTo( x + 5, y + 5 );
+		heartShape.bezierCurveTo( x + 5, y + 5, x + 4, y, x, y );
+		heartShape.bezierCurveTo( x - 6, y, x - 6, y + 7,x - 6, y + 7 );
+		heartShape.bezierCurveTo( x - 6, y + 11, x - 3, y + 15.4, x + 5, y + 19 );
+		heartShape.bezierCurveTo( x + 12, y + 15.4, x + 16, y + 11, x + 16, y + 7 );
+		heartShape.bezierCurveTo( x + 16, y + 7, x + 16, y, x + 10, y );
+		heartShape.bezierCurveTo( x + 7, y, x + 5, y + 5, x + 5, y + 5 );
+
+		var geometry = new THREE.ShapeGeometry( heartShape );
 		var material = new THREE.MeshBasicMaterial( { color: 0x00ff00 } );
 		var mesh = new THREE.Mesh( geometry, material ) ;
 		scene.add( mesh );
@@ -55,39 +58,12 @@
 		<h2>Constructor</h2>
 
 
-		<h3>[name]([page:Array shapes], [page:Object options])</h3>
-		<div>
-		shapes — [page:Array] of shapes, or a single [page:Shape shape] <br />
-		options — Optional options [page:Object object]
-		<ul>
-		<li>curveSegments - [page:Integer] - Not used at the moment - defaults to 12</li>
-		<li>material - [page:Integer] - index of the material in a material list</li>
-		<li>UVGenerator - A UV generator, defaults to [page:ExtrudeGeometry]'s WorldUVGenerator</li>
-		</ul>
-		</div>
-
-
-		<h2>Methods</h2>
-
-
-
-		<h3>.addShapeList([page:Array shapes], [page:Object options]) [page:this]</h3>
-		<div>
-		shapes — [page:Array] of [page:Shape shapes] <br />
-		options — See options in constructor
-		</div>
+		<h3>[name]([page:Array shapes], [page:Integer curveSegments])</h3>
 		<div>
-		Adds a list of shapes to the geometry.
+		shapes — [page:Array] of shapes or a single [page:Shape shape].<br />
+		curveSegments - [page:Integer] - Number of segments per shape. Default is 12.
 		</div>
 
-		<h3>[method:null addShape]([page:Shape shape], [page:Object options])</h3>
-		<div>
-		shape — [page:Shape] <br />
-		options — See options in constructor
-		</div>
-		<div>
-		Adds a single shape to the geometry
-		</div>
 
 		<h2>Source</h2>
 

+ 1 - 0
docs/list.js

@@ -63,6 +63,7 @@ var list = {
 			[ "PolyhedronGeometry", "api/geometries/PolyhedronGeometry" ],
 			[ "RingBufferGeometry", "api/geometries/RingBufferGeometry" ],
 			[ "RingGeometry", "api/geometries/RingGeometry" ],
+			[ "ShapeBufferGeometry", "api/geometries/ShapeBufferGeometry" ],
 			[ "ShapeGeometry", "api/geometries/ShapeGeometry" ],
 			[ "SphereBufferGeometry", "api/geometries/SphereBufferGeometry" ],
 			[ "SphereGeometry", "api/geometries/SphereGeometry" ],

+ 40 - 9
docs/scenes/js/geometry.js

@@ -111,6 +111,20 @@ var CustomSinCurve = THREE.Curve.create(
 
 );
 
+// heart shape
+
+var x = 0, y = 0;
+
+var heartShape = new THREE.Shape();
+
+heartShape.moveTo( x + 5, y + 5 );
+heartShape.bezierCurveTo( x + 5, y + 5, x + 4, y, x, y );
+heartShape.bezierCurveTo( x - 6, y, x - 6, y + 7,x - 6, y + 7 );
+heartShape.bezierCurveTo( x - 6, y + 11, x - 3, y + 15.4, x + 5, y + 19 );
+heartShape.bezierCurveTo( x + 12, y + 15.4, x + 16, y + 11, x + 16, y + 7 );
+heartShape.bezierCurveTo( x + 16, y + 7, x + 16, y, x + 10, y );
+heartShape.bezierCurveTo( x + 7, y, x + 5, y + 5, x + 5, y + 5 );
+
 var guis = {
 
 	BoxBufferGeometry : function( mesh ) {
@@ -1206,24 +1220,41 @@ var guis = {
 
 	ShapeGeometry: function( mesh ) {
 
-		var length = 16, width = 12;
-
-		var shape = new THREE.Shape();
-		shape.moveTo( 0,0 );
-		shape.lineTo( 0, width );
-		shape.lineTo( length, width );
-		shape.lineTo( length, 0 );
-		shape.lineTo( 0, 0 );
+		var data = {
+			segments : 12
+		};
 
 		function generateGeometry() {
 
 			updateGroupGeometry( mesh,
-				new THREE.ShapeGeometry( shape )
+				new THREE.ShapeGeometry( heartShape, data.segments )
 			);
 
 		}
 
 		var folder = gui.addFolder( 'THREE.ShapeGeometry' );
+		folder.add( data, 'segments', 1, 100 ).step( 1 ).onChange( generateGeometry );
+
+		generateGeometry();
+
+	},
+
+	ShapeBufferGeometry: function( mesh ) {
+
+		var data = {
+			segments : 12
+		};
+
+		function generateGeometry() {
+
+			updateGroupGeometry( mesh,
+				new THREE.ShapeBufferGeometry( heartShape, data.segments )
+			);
+
+		}
+
+		var folder = gui.addFolder( 'THREE.ShapeBufferGeometry' );
+		folder.add( data, 'segments', 1, 100 ).step( 1 ).onChange( generateGeometry );
 
 		generateGeometry();
 

+ 6 - 3
examples/webgl_geometry_shapes.html

@@ -66,15 +66,18 @@
 
 				var loader = new THREE.TextureLoader();
 				var texture = loader.load( "textures/UV_Grid_Sm.jpg" );
+
+				// it's necessary to apply these settings in order to correctly display the texture on a shape geometry
+
 				texture.wrapS = texture.wrapT = THREE.RepeatWrapping;
 				texture.repeat.set( 0.008, 0.008 );
 
 				function addShape( shape, extrudeSettings, color, x, y, z, rx, ry, rz, s ) {
 
 					// flat shape with texture
-					// note: default UVs generated by ShapeGemoetry are simply the x- and y-coordinates of the vertices
+					// note: default UVs generated by ShapeBufferGemoetry are simply the x- and y-coordinates of the vertices
 
-					var geometry = new THREE.ShapeGeometry( shape );
+					var geometry = new THREE.ShapeBufferGeometry( shape );
 
 					var mesh = new THREE.Mesh( geometry, new THREE.MeshPhongMaterial( { side: THREE.DoubleSide, map: texture } ) );
 					mesh.position.set( x, y, z - 175 );
@@ -84,7 +87,7 @@
 
 					// flat shape
 
-					var geometry = new THREE.ShapeGeometry( shape );
+					var geometry = new THREE.ShapeBufferGeometry( shape );
 
 					var mesh = new THREE.Mesh( geometry, new THREE.MeshPhongMaterial( { color: color, side: THREE.DoubleSide } ) );
 					mesh.position.set( x, y, z - 125 );

+ 1 - 0
src/geometries/Geometries.js

@@ -27,6 +27,7 @@ export { PlaneGeometry } from './PlaneGeometry.js';
 export { LatheGeometry } from './LatheGeometry.js';
 export { LatheBufferGeometry } from './LatheBufferGeometry.js';
 export { ShapeGeometry } from './ShapeGeometry.js';
+export { ShapeBufferGeometry } from './ShapeBufferGeometry.js';
 export { ExtrudeGeometry } from './ExtrudeGeometry.js';
 export { EdgesGeometry } from './EdgesGeometry.js';
 export { ConeGeometry } from './ConeGeometry.js';

+ 142 - 0
src/geometries/ShapeBufferGeometry.js

@@ -0,0 +1,142 @@
+import { BufferGeometry } from '../core/BufferGeometry';
+import { Float32Attribute, Uint16Attribute, Uint32Attribute } from '../core/BufferAttribute';
+import { ShapeUtils } from '../extras/ShapeUtils';
+
+/**
+ * @author Mugen87 / https://github.com/Mugen87
+ *
+ * Creates a one-sided polygonal geometry from one or more shapes.
+ *
+ **/
+
+function ShapeBufferGeometry( shapes, curveSegments ) {
+
+	BufferGeometry.call( this );
+
+	this.type = 'ShapeBufferGeometry';
+
+	this.parameters = {
+		shapes: shapes,
+		curveSegments: curveSegments
+	};
+
+	curveSegments = curveSegments || 12;
+
+	var vertices = [];
+	var normals = [];
+	var uvs = [];
+	var indices = [];
+
+	var groupStart = 0;
+	var groupCount = 0;
+
+	// allow single and array values for "shapes" parameter
+
+	if ( Array.isArray( shapes ) === false ) {
+
+		addShape( shapes );
+
+	} else {
+
+		for ( var i = 0; i < shapes.length; i++ ) {
+
+			addShape( shapes[ i ] );
+
+			this.addGroup( groupStart, groupCount, i ); // enables MultiMaterial support
+
+			groupStart += groupCount;
+			groupCount = 0;
+
+		}
+
+	}
+
+	// build geometry
+
+	this.setIndex( ( indices.length > 65535 ? Uint32Attribute : Uint16Attribute )( indices, 1 ) );
+	this.addAttribute( 'position', Float32Attribute( vertices, 3 ) );
+	this.addAttribute( 'normal', Float32Attribute( normals, 3 ) );
+	this.addAttribute( 'uv', Float32Attribute( uvs, 2 ) );
+
+
+	// helper functions
+
+	function addShape( shape ) {
+
+		var i, l, shapeHole;
+
+		var indexOffset = vertices.length / 3;
+		var points = shape.extractPoints( curveSegments );
+
+		var shapeVertices = points.shape;
+		var shapeHoles = points.holes;
+
+		// check direction of vertices
+
+		if ( ShapeUtils.isClockWise( shapeVertices ) === false ) {
+
+			shapeVertices = shapeVertices.reverse();
+
+			// also check if holes are in the opposite direction
+
+			for ( i = 0, l = shapeHoles.length; i < l; i ++ ) {
+
+				shapeHole = shapeHoles[ i ];
+
+				if ( ShapeUtils.isClockWise( shapeHole ) === true ) {
+
+					shapeHoles[ i ] = shapeHole.reverse();
+
+				}
+
+			}
+
+		}
+
+		var faces = ShapeUtils.triangulateShape( shapeVertices, shapeHoles );
+
+		// join vertices of inner and outer paths to a single array
+
+		for ( i = 0, l = shapeHoles.length; i < l; i ++ ) {
+
+			shapeHole = shapeHoles[ i ];
+			shapeVertices = shapeVertices.concat( shapeHole );
+
+		}
+
+		// vertices, normals, uvs
+
+		for ( i = 0, l = shapeVertices.length; i < l; i ++ ) {
+
+			var vertex = shapeVertices[ i ];
+
+			vertices.push( vertex.x, vertex.y, 0 );
+			normals.push( 0, 0, 1 );
+			uvs.push( vertex.x, vertex.y ); // world uvs
+
+		}
+
+		// incides
+
+		for ( i = 0, l = faces.length; i < l; i ++ ) {
+
+			var face = faces[ i ];
+
+			var a = face[ 0 ] + indexOffset;
+			var b = face[ 1 ] + indexOffset;
+			var c = face[ 2 ] + indexOffset;
+
+			indices.push( a, b, c );
+			groupCount += 3;
+
+		}
+
+	}
+
+}
+
+ShapeBufferGeometry.prototype = Object.create( BufferGeometry.prototype );
+ShapeBufferGeometry.prototype.constructor = ShapeBufferGeometry;
+
+
+export { ShapeBufferGeometry };

+ 15 - 116
src/geometries/ShapeGeometry.js

@@ -1,140 +1,39 @@
 import { Geometry } from '../core/Geometry';
-import { Face3 } from '../core/Face3';
-import { Vector3 } from '../math/Vector3';
-import { ShapeUtils } from '../extras/ShapeUtils';
-import { ExtrudeGeometry } from './ExtrudeGeometry';
+import { ShapeBufferGeometry } from './ShapeBufferGeometry';
 
 /**
  * @author jonobr1 / http://jonobr1.com
  *
- * Creates a one-sided polygonal geometry from a path shape. Similar to
- * ExtrudeGeometry.
+ * Creates a one-sided polygonal geometry from a path shape.
  *
- * parameters = {
- *
- *	curveSegments: <int>, // number of points on the curves. NOT USED AT THE MOMENT.
- *
- *	material: <int> // material index for front and back faces
- *	uvGenerator: <Object> // object that provides UV generator functions
- *
- * }
  **/
 
-function ShapeGeometry( shapes, options ) {
+function ShapeGeometry( shapes, curveSegments ) {
 
 	Geometry.call( this );
 
 	this.type = 'ShapeGeometry';
 
-	if ( Array.isArray( shapes ) === false ) shapes = [ shapes ];
-
-	this.addShapeList( shapes, options );
-
-	this.computeFaceNormals();
-
-}
-
-ShapeGeometry.prototype = Object.create( Geometry.prototype );
-ShapeGeometry.prototype.constructor = ShapeGeometry;
-
-/**
- * Add an array of shapes to THREE.ShapeGeometry.
- */
-ShapeGeometry.prototype.addShapeList = function ( shapes, options ) {
-
-	for ( var i = 0, l = shapes.length; i < l; i ++ ) {
-
-		this.addShape( shapes[ i ], options );
-
-	}
-
-	return this;
-
-};
-
-/**
- * Adds a shape to THREE.ShapeGeometry, based on THREE.ExtrudeGeometry.
- */
-ShapeGeometry.prototype.addShape = function ( shape, options ) {
-
-	if ( options === undefined ) options = {};
-	var curveSegments = options.curveSegments !== undefined ? options.curveSegments : 12;
-
-	var material = options.material;
-	var uvgen = options.UVGenerator === undefined ? ExtrudeGeometry.WorldUVGenerator : options.UVGenerator;
-
-	//
-
-	var i, l, hole;
-
-	var shapesOffset = this.vertices.length;
-	var shapePoints = shape.extractPoints( curveSegments );
-
-	var vertices = shapePoints.shape;
-	var holes = shapePoints.holes;
-
-	var reverse = ! ShapeUtils.isClockWise( vertices );
+	if ( typeof curveSegments === 'object' ) {
 
-	if ( reverse ) {
+		console.warn( 'THREE.ShapeGeometry: Options parameter has been removed.' );
 
-		vertices = vertices.reverse();
-
-		// Maybe we should also check if holes are in the opposite direction, just to be safe...
-
-		for ( i = 0, l = holes.length; i < l; i ++ ) {
-
-			hole = holes[ i ];
-
-			if ( ShapeUtils.isClockWise( hole ) ) {
-
-				holes[ i ] = hole.reverse();
-
-			}
-
-		}
-
-		reverse = false;
-
-	}
-
-	var faces = ShapeUtils.triangulateShape( vertices, holes );
-
-	// Vertices
-
-	for ( i = 0, l = holes.length; i < l; i ++ ) {
-
-		hole = holes[ i ];
-		vertices = vertices.concat( hole );
+		curveSegments = curveSegments.curveSegments;
 
 	}
 
-	//
+	this.parameters = {
+		shapes: shapes,
+		curveSegments: curveSegments
+	};
 
-	var vert, vlen = vertices.length;
-	var face, flen = faces.length;
+	this.fromBufferGeometry( new ShapeBufferGeometry( shapes, curveSegments ) );
+	this.mergeVertices();
 
-	for ( i = 0; i < vlen; i ++ ) {
-
-		vert = vertices[ i ];
-
-		this.vertices.push( new Vector3( vert.x, vert.y, 0 ) );
-
-	}
-
-	for ( i = 0; i < flen; i ++ ) {
-
-		face = faces[ i ];
-
-		var a = face[ 0 ] + shapesOffset;
-		var b = face[ 1 ] + shapesOffset;
-		var c = face[ 2 ] + shapesOffset;
-
-		this.faces.push( new Face3( a, b, c, null, null, material ) );
-		this.faceVertexUvs[ 0 ].push( uvgen.generateTopUV( this, a, b, c ) );
-
-	}
+}
 
-};
+ShapeGeometry.prototype = Object.create( Geometry.prototype );
+ShapeGeometry.prototype.constructor = ShapeGeometry;
 
 
 export { ShapeGeometry };