From 7ea23ec3a535c66d440ab597bd4375f3946686eb Mon Sep 17 00:00:00 2001 From: Michael Herzog Date: Mon, 31 Oct 2016 16:56:43 +0100 Subject: [PATCH] New ShapeBufferGeometry (#9970) * ShapeBufferGeometry: Initial commit * ShapeBufferGeometry: Clean up --- docs/api/geometries/ShapeBufferGeometry.html | 71 ++++++++++ docs/api/geometries/ShapeGeometry.html | 54 ++----- docs/list.js | 1 + docs/scenes/js/geometry.js | 49 +++++-- examples/webgl_geometry_shapes.html | 9 +- src/geometries/Geometries.js | 1 + src/geometries/ShapeBufferGeometry.js | 142 +++++++++++++++++++ src/geometries/ShapeGeometry.js | 131 ++--------------- 8 files changed, 291 insertions(+), 167 deletions(-) create mode 100644 docs/api/geometries/ShapeBufferGeometry.html create mode 100644 src/geometries/ShapeBufferGeometry.js diff --git a/docs/api/geometries/ShapeBufferGeometry.html b/docs/api/geometries/ShapeBufferGeometry.html new file mode 100644 index 0000000000..0429411ef1 --- /dev/null +++ b/docs/api/geometries/ShapeBufferGeometry.html @@ -0,0 +1,71 @@ + + + + + + + + + + + [page:BufferGeometry] → + +

[name]

+ +
Creates an one-sided polygonal geometry from one or more path shapes.
+ + + + + + +

Example

+ + + + 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 ); + + +

Constructor

+ + +

[name]([page:Array shapes], [page:Integer curveSegments])

+
+ shapes — [page:Array] of shapes or a single [page:Shape shape].
+ curveSegments - [page:Integer] - Number of segments per shape. Default is 12. +
+ +

Source

+ + [link:https://github.com/mrdoob/three.js/blob/master/src/[path].js src/[path].js] + + diff --git a/docs/api/geometries/ShapeGeometry.html b/docs/api/geometries/ShapeGeometry.html index 163afe574b..3705501f3e 100644 --- a/docs/api/geometries/ShapeGeometry.html +++ b/docs/api/geometries/ShapeGeometry.html @@ -12,7 +12,7 @@

[name]

-
Creates a one-sided polygonal geometry from one or more path shapes. Similar to [page:ExtrudeGeometry].
+
Creates an one-sided polygonal geometry from one or more path shapes.
@@ -37,16 +37,19 @@ - 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 @@

Constructor

-

[name]([page:Array shapes], [page:Object options])

-
- shapes — [page:Array] of shapes, or a single [page:Shape shape]
- options — Optional options [page:Object object] -
    -
  • curveSegments - [page:Integer] - Not used at the moment - defaults to 12
  • -
  • material - [page:Integer] - index of the material in a material list
  • -
  • UVGenerator - A UV generator, defaults to [page:ExtrudeGeometry]'s WorldUVGenerator
  • -
-
- - -

Methods

- - - -

.addShapeList([page:Array shapes], [page:Object options]) [page:this]

-
- shapes — [page:Array] of [page:Shape shapes]
- options — See options in constructor -
+

[name]([page:Array shapes], [page:Integer curveSegments])

- Adds a list of shapes to the geometry. + shapes — [page:Array] of shapes or a single [page:Shape shape].
+ curveSegments - [page:Integer] - Number of segments per shape. Default is 12.
-

[method:null addShape]([page:Shape shape], [page:Object options])

-
- shape — [page:Shape]
- options — See options in constructor -
-
- Adds a single shape to the geometry -

Source

diff --git a/docs/list.js b/docs/list.js index bdef3978c7..1622bda6fd 100644 --- a/docs/list.js +++ b/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" ], diff --git a/docs/scenes/js/geometry.js b/docs/scenes/js/geometry.js index 1330364815..0b9c4ac00a 100644 --- a/docs/scenes/js/geometry.js +++ b/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(); diff --git a/examples/webgl_geometry_shapes.html b/examples/webgl_geometry_shapes.html index 15551dcdc4..b7d6e12fbc 100644 --- a/examples/webgl_geometry_shapes.html +++ b/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 ); diff --git a/src/geometries/Geometries.js b/src/geometries/Geometries.js index fe03fed08c..a625af4f1a 100644 --- a/src/geometries/Geometries.js +++ b/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'; diff --git a/src/geometries/ShapeBufferGeometry.js b/src/geometries/ShapeBufferGeometry.js new file mode 100644 index 0000000000..8d3fbe69f3 --- /dev/null +++ b/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 }; diff --git a/src/geometries/ShapeGeometry.js b/src/geometries/ShapeGeometry.js index cb3680d5b0..a5101fcf87 100644 --- a/src/geometries/ShapeGeometry.js +++ b/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: , // number of points on the curves. NOT USED AT THE MOMENT. - * - * material: // material index for front and back faces - * uvGenerator: // 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 }; -- GitLab