initial commit

This commit is contained in:
Mahdi Dibaiee
2018-12-25 17:29:22 +03:30
commit e983346ffc
388 changed files with 174266 additions and 0 deletions

View File

@ -0,0 +1,203 @@
/**
* @author mrdoob / http://mrdoob.com/
* @author Mugen87 / https://github.com/Mugen87
*/
import { Geometry } from '../core/Geometry.js';
import { BufferGeometry } from '../core/BufferGeometry.js';
import { Float32BufferAttribute } from '../core/BufferAttribute.js';
import { Vector3 } from '../math/Vector3.js';
// BoxGeometry
function BoxGeometry( width, height, depth, widthSegments, heightSegments, depthSegments ) {
Geometry.call( this );
this.type = 'BoxGeometry';
this.parameters = {
width: width,
height: height,
depth: depth,
widthSegments: widthSegments,
heightSegments: heightSegments,
depthSegments: depthSegments
};
this.fromBufferGeometry( new BoxBufferGeometry( width, height, depth, widthSegments, heightSegments, depthSegments ) );
this.mergeVertices();
}
BoxGeometry.prototype = Object.create( Geometry.prototype );
BoxGeometry.prototype.constructor = BoxGeometry;
// BoxBufferGeometry
function BoxBufferGeometry( width, height, depth, widthSegments, heightSegments, depthSegments ) {
BufferGeometry.call( this );
this.type = 'BoxBufferGeometry';
this.parameters = {
width: width,
height: height,
depth: depth,
widthSegments: widthSegments,
heightSegments: heightSegments,
depthSegments: depthSegments
};
var scope = this;
width = width || 1;
height = height || 1;
depth = depth || 1;
// segments
widthSegments = Math.floor( widthSegments ) || 1;
heightSegments = Math.floor( heightSegments ) || 1;
depthSegments = Math.floor( depthSegments ) || 1;
// buffers
var indices = [];
var vertices = [];
var normals = [];
var uvs = [];
// helper variables
var numberOfVertices = 0;
var groupStart = 0;
// build each side of the box geometry
buildPlane( 'z', 'y', 'x', - 1, - 1, depth, height, width, depthSegments, heightSegments, 0 ); // px
buildPlane( 'z', 'y', 'x', 1, - 1, depth, height, - width, depthSegments, heightSegments, 1 ); // nx
buildPlane( 'x', 'z', 'y', 1, 1, width, depth, height, widthSegments, depthSegments, 2 ); // py
buildPlane( 'x', 'z', 'y', 1, - 1, width, depth, - height, widthSegments, depthSegments, 3 ); // ny
buildPlane( 'x', 'y', 'z', 1, - 1, width, height, depth, widthSegments, heightSegments, 4 ); // pz
buildPlane( 'x', 'y', 'z', - 1, - 1, width, height, - depth, widthSegments, heightSegments, 5 ); // nz
// build geometry
this.setIndex( indices );
this.addAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) );
this.addAttribute( 'normal', new Float32BufferAttribute( normals, 3 ) );
this.addAttribute( 'uv', new Float32BufferAttribute( uvs, 2 ) );
function buildPlane( u, v, w, udir, vdir, width, height, depth, gridX, gridY, materialIndex ) {
var segmentWidth = width / gridX;
var segmentHeight = height / gridY;
var widthHalf = width / 2;
var heightHalf = height / 2;
var depthHalf = depth / 2;
var gridX1 = gridX + 1;
var gridY1 = gridY + 1;
var vertexCounter = 0;
var groupCount = 0;
var ix, iy;
var vector = new Vector3();
// generate vertices, normals and uvs
for ( iy = 0; iy < gridY1; iy ++ ) {
var y = iy * segmentHeight - heightHalf;
for ( ix = 0; ix < gridX1; ix ++ ) {
var x = ix * segmentWidth - widthHalf;
// set values to correct vector component
vector[ u ] = x * udir;
vector[ v ] = y * vdir;
vector[ w ] = depthHalf;
// now apply vector to vertex buffer
vertices.push( vector.x, vector.y, vector.z );
// set values to correct vector component
vector[ u ] = 0;
vector[ v ] = 0;
vector[ w ] = depth > 0 ? 1 : - 1;
// now apply vector to normal buffer
normals.push( vector.x, vector.y, vector.z );
// uvs
uvs.push( ix / gridX );
uvs.push( 1 - ( iy / gridY ) );
// counters
vertexCounter += 1;
}
}
// indices
// 1. you need three indices to draw a single face
// 2. a single segment consists of two faces
// 3. so we need to generate six (2*3) indices per segment
for ( iy = 0; iy < gridY; iy ++ ) {
for ( ix = 0; ix < gridX; ix ++ ) {
var a = numberOfVertices + ix + gridX1 * iy;
var b = numberOfVertices + ix + gridX1 * ( iy + 1 );
var c = numberOfVertices + ( ix + 1 ) + gridX1 * ( iy + 1 );
var d = numberOfVertices + ( ix + 1 ) + gridX1 * iy;
// faces
indices.push( a, b, d );
indices.push( b, c, d );
// increase counter
groupCount += 6;
}
}
// add a group to the geometry. this will ensure multi material support
scope.addGroup( groupStart, groupCount, materialIndex );
// calculate new start value for groups
groupStart += groupCount;
// update total number of vertices
numberOfVertices += vertexCounter;
}
}
BoxBufferGeometry.prototype = Object.create( BufferGeometry.prototype );
BoxBufferGeometry.prototype.constructor = BoxBufferGeometry;
export { BoxGeometry, BoxBufferGeometry };

View File

@ -0,0 +1,121 @@
/**
* @author benaadams / https://twitter.com/ben_a_adams
* @author Mugen87 / https://github.com/Mugen87
* @author hughes
*/
import { Geometry } from '../core/Geometry.js';
import { BufferGeometry } from '../core/BufferGeometry.js';
import { Float32BufferAttribute } from '../core/BufferAttribute.js';
import { Vector3 } from '../math/Vector3.js';
import { Vector2 } from '../math/Vector2.js';
// CircleGeometry
function CircleGeometry( radius, segments, thetaStart, thetaLength ) {
Geometry.call( this );
this.type = 'CircleGeometry';
this.parameters = {
radius: radius,
segments: segments,
thetaStart: thetaStart,
thetaLength: thetaLength
};
this.fromBufferGeometry( new CircleBufferGeometry( radius, segments, thetaStart, thetaLength ) );
this.mergeVertices();
}
CircleGeometry.prototype = Object.create( Geometry.prototype );
CircleGeometry.prototype.constructor = CircleGeometry;
// CircleBufferGeometry
function CircleBufferGeometry( radius, segments, thetaStart, thetaLength ) {
BufferGeometry.call( this );
this.type = 'CircleBufferGeometry';
this.parameters = {
radius: radius,
segments: segments,
thetaStart: thetaStart,
thetaLength: thetaLength
};
radius = radius || 1;
segments = segments !== undefined ? Math.max( 3, segments ) : 8;
thetaStart = thetaStart !== undefined ? thetaStart : 0;
thetaLength = thetaLength !== undefined ? thetaLength : Math.PI * 2;
// buffers
var indices = [];
var vertices = [];
var normals = [];
var uvs = [];
// helper variables
var i, s;
var vertex = new Vector3();
var uv = new Vector2();
// center point
vertices.push( 0, 0, 0 );
normals.push( 0, 0, 1 );
uvs.push( 0.5, 0.5 );
for ( s = 0, i = 3; s <= segments; s ++, i += 3 ) {
var segment = thetaStart + s / segments * thetaLength;
// vertex
vertex.x = radius * Math.cos( segment );
vertex.y = radius * Math.sin( segment );
vertices.push( vertex.x, vertex.y, vertex.z );
// normal
normals.push( 0, 0, 1 );
// uvs
uv.x = ( vertices[ i ] / radius + 1 ) / 2;
uv.y = ( vertices[ i + 1 ] / radius + 1 ) / 2;
uvs.push( uv.x, uv.y );
}
// indices
for ( i = 1; i <= segments; i ++ ) {
indices.push( i, i + 1, 0 );
}
// build geometry
this.setIndex( indices );
this.addAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) );
this.addAttribute( 'normal', new Float32BufferAttribute( normals, 3 ) );
this.addAttribute( 'uv', new Float32BufferAttribute( uvs, 2 ) );
}
CircleBufferGeometry.prototype = Object.create( BufferGeometry.prototype );
CircleBufferGeometry.prototype.constructor = CircleBufferGeometry;
export { CircleGeometry, CircleBufferGeometry };

View File

@ -0,0 +1,55 @@
/**
* @author abelnation / http://github.com/abelnation
*/
import { CylinderGeometry } from './CylinderGeometry.js';
import { CylinderBufferGeometry } from './CylinderGeometry.js';
// ConeGeometry
function ConeGeometry( radius, height, radialSegments, heightSegments, openEnded, thetaStart, thetaLength ) {
CylinderGeometry.call( this, 0, radius, height, radialSegments, heightSegments, openEnded, thetaStart, thetaLength );
this.type = 'ConeGeometry';
this.parameters = {
radius: radius,
height: height,
radialSegments: radialSegments,
heightSegments: heightSegments,
openEnded: openEnded,
thetaStart: thetaStart,
thetaLength: thetaLength
};
}
ConeGeometry.prototype = Object.create( CylinderGeometry.prototype );
ConeGeometry.prototype.constructor = ConeGeometry;
// ConeBufferGeometry
function ConeBufferGeometry( radius, height, radialSegments, heightSegments, openEnded, thetaStart, thetaLength ) {
CylinderBufferGeometry.call( this, 0, radius, height, radialSegments, heightSegments, openEnded, thetaStart, thetaLength );
this.type = 'ConeBufferGeometry';
this.parameters = {
radius: radius,
height: height,
radialSegments: radialSegments,
heightSegments: heightSegments,
openEnded: openEnded,
thetaStart: thetaStart,
thetaLength: thetaLength
};
}
ConeBufferGeometry.prototype = Object.create( CylinderBufferGeometry.prototype );
ConeBufferGeometry.prototype.constructor = ConeBufferGeometry;
export { ConeGeometry, ConeBufferGeometry };

View File

@ -0,0 +1,316 @@
/**
* @author mrdoob / http://mrdoob.com/
* @author Mugen87 / https://github.com/Mugen87
*/
import { Geometry } from '../core/Geometry.js';
import { BufferGeometry } from '../core/BufferGeometry.js';
import { Float32BufferAttribute } from '../core/BufferAttribute.js';
import { Vector3 } from '../math/Vector3.js';
import { Vector2 } from '../math/Vector2.js';
// CylinderGeometry
function CylinderGeometry( radiusTop, radiusBottom, height, radialSegments, heightSegments, openEnded, thetaStart, thetaLength ) {
Geometry.call( this );
this.type = 'CylinderGeometry';
this.parameters = {
radiusTop: radiusTop,
radiusBottom: radiusBottom,
height: height,
radialSegments: radialSegments,
heightSegments: heightSegments,
openEnded: openEnded,
thetaStart: thetaStart,
thetaLength: thetaLength
};
this.fromBufferGeometry( new CylinderBufferGeometry( radiusTop, radiusBottom, height, radialSegments, heightSegments, openEnded, thetaStart, thetaLength ) );
this.mergeVertices();
}
CylinderGeometry.prototype = Object.create( Geometry.prototype );
CylinderGeometry.prototype.constructor = CylinderGeometry;
// CylinderBufferGeometry
function CylinderBufferGeometry( radiusTop, radiusBottom, height, radialSegments, heightSegments, openEnded, thetaStart, thetaLength ) {
BufferGeometry.call( this );
this.type = 'CylinderBufferGeometry';
this.parameters = {
radiusTop: radiusTop,
radiusBottom: radiusBottom,
height: height,
radialSegments: radialSegments,
heightSegments: heightSegments,
openEnded: openEnded,
thetaStart: thetaStart,
thetaLength: thetaLength
};
var scope = this;
radiusTop = radiusTop !== undefined ? radiusTop : 1;
radiusBottom = radiusBottom !== undefined ? radiusBottom : 1;
height = height || 1;
radialSegments = Math.floor( radialSegments ) || 8;
heightSegments = Math.floor( heightSegments ) || 1;
openEnded = openEnded !== undefined ? openEnded : false;
thetaStart = thetaStart !== undefined ? thetaStart : 0.0;
thetaLength = thetaLength !== undefined ? thetaLength : Math.PI * 2;
// buffers
var indices = [];
var vertices = [];
var normals = [];
var uvs = [];
// helper variables
var index = 0;
var indexArray = [];
var halfHeight = height / 2;
var groupStart = 0;
// generate geometry
generateTorso();
if ( openEnded === false ) {
if ( radiusTop > 0 ) generateCap( true );
if ( radiusBottom > 0 ) generateCap( false );
}
// build geometry
this.setIndex( indices );
this.addAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) );
this.addAttribute( 'normal', new Float32BufferAttribute( normals, 3 ) );
this.addAttribute( 'uv', new Float32BufferAttribute( uvs, 2 ) );
function generateTorso() {
var x, y;
var normal = new Vector3();
var vertex = new Vector3();
var groupCount = 0;
// this will be used to calculate the normal
var slope = ( radiusBottom - radiusTop ) / height;
// generate vertices, normals and uvs
for ( y = 0; y <= heightSegments; y ++ ) {
var indexRow = [];
var v = y / heightSegments;
// calculate the radius of the current row
var radius = v * ( radiusBottom - radiusTop ) + radiusTop;
for ( x = 0; x <= radialSegments; x ++ ) {
var u = x / radialSegments;
var theta = u * thetaLength + thetaStart;
var sinTheta = Math.sin( theta );
var cosTheta = Math.cos( theta );
// vertex
vertex.x = radius * sinTheta;
vertex.y = - v * height + halfHeight;
vertex.z = radius * cosTheta;
vertices.push( vertex.x, vertex.y, vertex.z );
// normal
normal.set( sinTheta, slope, cosTheta ).normalize();
normals.push( normal.x, normal.y, normal.z );
// uv
uvs.push( u, 1 - v );
// save index of vertex in respective row
indexRow.push( index ++ );
}
// now save vertices of the row in our index array
indexArray.push( indexRow );
}
// generate indices
for ( x = 0; x < radialSegments; x ++ ) {
for ( y = 0; y < heightSegments; y ++ ) {
// we use the index array to access the correct indices
var a = indexArray[ y ][ x ];
var b = indexArray[ y + 1 ][ x ];
var c = indexArray[ y + 1 ][ x + 1 ];
var d = indexArray[ y ][ x + 1 ];
// faces
indices.push( a, b, d );
indices.push( b, c, d );
// update group counter
groupCount += 6;
}
}
// add a group to the geometry. this will ensure multi material support
scope.addGroup( groupStart, groupCount, 0 );
// calculate new start value for groups
groupStart += groupCount;
}
function generateCap( top ) {
var x, centerIndexStart, centerIndexEnd;
var uv = new Vector2();
var vertex = new Vector3();
var groupCount = 0;
var radius = ( top === true ) ? radiusTop : radiusBottom;
var sign = ( top === true ) ? 1 : - 1;
// save the index of the first center vertex
centerIndexStart = index;
// first we generate the center vertex data of the cap.
// because the geometry needs one set of uvs per face,
// we must generate a center vertex per face/segment
for ( x = 1; x <= radialSegments; x ++ ) {
// vertex
vertices.push( 0, halfHeight * sign, 0 );
// normal
normals.push( 0, sign, 0 );
// uv
uvs.push( 0.5, 0.5 );
// increase index
index ++;
}
// save the index of the last center vertex
centerIndexEnd = index;
// now we generate the surrounding vertices, normals and uvs
for ( x = 0; x <= radialSegments; x ++ ) {
var u = x / radialSegments;
var theta = u * thetaLength + thetaStart;
var cosTheta = Math.cos( theta );
var sinTheta = Math.sin( theta );
// vertex
vertex.x = radius * sinTheta;
vertex.y = halfHeight * sign;
vertex.z = radius * cosTheta;
vertices.push( vertex.x, vertex.y, vertex.z );
// normal
normals.push( 0, sign, 0 );
// uv
uv.x = ( cosTheta * 0.5 ) + 0.5;
uv.y = ( sinTheta * 0.5 * sign ) + 0.5;
uvs.push( uv.x, uv.y );
// increase index
index ++;
}
// generate indices
for ( x = 0; x < radialSegments; x ++ ) {
var c = centerIndexStart + x;
var i = centerIndexEnd + x;
if ( top === true ) {
// face top
indices.push( i, i + 1, c );
} else {
// face bottom
indices.push( i + 1, i, c );
}
groupCount += 3;
}
// add a group to the geometry. this will ensure multi material support
scope.addGroup( groupStart, groupCount, top === true ? 1 : 2 );
// calculate new start value for groups
groupStart += groupCount;
}
}
CylinderBufferGeometry.prototype = Object.create( BufferGeometry.prototype );
CylinderBufferGeometry.prototype.constructor = CylinderBufferGeometry;
export { CylinderGeometry, CylinderBufferGeometry };

View File

@ -0,0 +1,88 @@
/**
* @author Abe Pazos / https://hamoid.com
* @author Mugen87 / https://github.com/Mugen87
*/
import { Geometry } from '../core/Geometry.js';
import { PolyhedronBufferGeometry } from './PolyhedronGeometry.js';
// DodecahedronGeometry
function DodecahedronGeometry( radius, detail ) {
Geometry.call( this );
this.type = 'DodecahedronGeometry';
this.parameters = {
radius: radius,
detail: detail
};
this.fromBufferGeometry( new DodecahedronBufferGeometry( radius, detail ) );
this.mergeVertices();
}
DodecahedronGeometry.prototype = Object.create( Geometry.prototype );
DodecahedronGeometry.prototype.constructor = DodecahedronGeometry;
// DodecahedronBufferGeometry
function DodecahedronBufferGeometry( radius, detail ) {
var t = ( 1 + Math.sqrt( 5 ) ) / 2;
var r = 1 / t;
var vertices = [
// (±1, ±1, ±1)
- 1, - 1, - 1, - 1, - 1, 1,
- 1, 1, - 1, - 1, 1, 1,
1, - 1, - 1, 1, - 1, 1,
1, 1, - 1, 1, 1, 1,
// (0, ±1/φ, ±φ)
0, - r, - t, 0, - r, t,
0, r, - t, 0, r, t,
// (±1/φ, ±φ, 0)
- r, - t, 0, - r, t, 0,
r, - t, 0, r, t, 0,
// (±φ, 0, ±1/φ)
- t, 0, - r, t, 0, - r,
- t, 0, r, t, 0, r
];
var indices = [
3, 11, 7, 3, 7, 15, 3, 15, 13,
7, 19, 17, 7, 17, 6, 7, 6, 15,
17, 4, 8, 17, 8, 10, 17, 10, 6,
8, 0, 16, 8, 16, 2, 8, 2, 10,
0, 12, 1, 0, 1, 18, 0, 18, 16,
6, 10, 2, 6, 2, 13, 6, 13, 15,
2, 16, 18, 2, 18, 3, 2, 3, 13,
18, 1, 9, 18, 9, 11, 18, 11, 3,
4, 14, 12, 4, 12, 0, 4, 0, 8,
11, 9, 5, 11, 5, 19, 11, 19, 7,
19, 5, 14, 19, 14, 4, 19, 4, 17,
1, 12, 14, 1, 14, 5, 1, 5, 9
];
PolyhedronBufferGeometry.call( this, vertices, indices, radius, detail );
this.type = 'DodecahedronBufferGeometry';
this.parameters = {
radius: radius,
detail: detail
};
}
DodecahedronBufferGeometry.prototype = Object.create( PolyhedronBufferGeometry.prototype );
DodecahedronBufferGeometry.prototype.constructor = DodecahedronBufferGeometry;
export { DodecahedronGeometry, DodecahedronBufferGeometry };

View File

@ -0,0 +1,113 @@
/**
* @author WestLangley / http://github.com/WestLangley
* @author Mugen87 / https://github.com/Mugen87
*/
import { BufferGeometry } from '../core/BufferGeometry.js';
import { Float32BufferAttribute } from '../core/BufferAttribute.js';
import { Geometry } from '../core/Geometry.js';
import { _Math } from '../math/Math.js';
function EdgesGeometry( geometry, thresholdAngle ) {
BufferGeometry.call( this );
this.type = 'EdgesGeometry';
this.parameters = {
thresholdAngle: thresholdAngle
};
thresholdAngle = ( thresholdAngle !== undefined ) ? thresholdAngle : 1;
// buffer
var vertices = [];
// helper variables
var thresholdDot = Math.cos( _Math.DEG2RAD * thresholdAngle );
var edge = [ 0, 0 ], edges = {}, edge1, edge2;
var key, keys = [ 'a', 'b', 'c' ];
// prepare source geometry
var geometry2;
if ( geometry.isBufferGeometry ) {
geometry2 = new Geometry();
geometry2.fromBufferGeometry( geometry );
} else {
geometry2 = geometry.clone();
}
geometry2.mergeVertices();
geometry2.computeFaceNormals();
var sourceVertices = geometry2.vertices;
var faces = geometry2.faces;
// now create a data structure where each entry represents an edge with its adjoining faces
for ( var i = 0, l = faces.length; i < l; i ++ ) {
var face = faces[ i ];
for ( var j = 0; j < 3; j ++ ) {
edge1 = face[ keys[ j ] ];
edge2 = face[ keys[ ( j + 1 ) % 3 ] ];
edge[ 0 ] = Math.min( edge1, edge2 );
edge[ 1 ] = Math.max( edge1, edge2 );
key = edge[ 0 ] + ',' + edge[ 1 ];
if ( edges[ key ] === undefined ) {
edges[ key ] = { index1: edge[ 0 ], index2: edge[ 1 ], face1: i, face2: undefined };
} else {
edges[ key ].face2 = i;
}
}
}
// generate vertices
for ( key in edges ) {
var e = edges[ key ];
// an edge is only rendered if the angle (in degrees) between the face normals of the adjoining faces exceeds this value. default = 1 degree.
if ( e.face2 === undefined || faces[ e.face1 ].normal.dot( faces[ e.face2 ].normal ) <= thresholdDot ) {
var vertex = sourceVertices[ e.index1 ];
vertices.push( vertex.x, vertex.y, vertex.z );
vertex = sourceVertices[ e.index2 ];
vertices.push( vertex.x, vertex.y, vertex.z );
}
}
// build geometry
this.addAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) );
}
EdgesGeometry.prototype = Object.create( BufferGeometry.prototype );
EdgesGeometry.prototype.constructor = EdgesGeometry;
export { EdgesGeometry };

View File

@ -0,0 +1,832 @@
/**
* @author zz85 / http://www.lab4games.net/zz85/blog
*
* Creates extruded geometry from a path shape.
*
* parameters = {
*
* curveSegments: <int>, // number of points on the curves
* steps: <int>, // number of points for z-side extrusions / used for subdividing segments of extrude spline too
* depth: <float>, // Depth to extrude the shape
*
* bevelEnabled: <bool>, // turn on bevel
* bevelThickness: <float>, // how deep into the original shape bevel goes
* bevelSize: <float>, // how far from shape outline is bevel
* bevelSegments: <int>, // number of bevel layers
*
* extrudePath: <THREE.Curve> // curve to extrude shape along
*
* UVGenerator: <Object> // object that provides UV generator functions
*
* }
*/
import { Geometry } from '../core/Geometry.js';
import { BufferGeometry } from '../core/BufferGeometry.js';
import { Float32BufferAttribute } from '../core/BufferAttribute.js';
import { Vector2 } from '../math/Vector2.js';
import { Vector3 } from '../math/Vector3.js';
import { ShapeUtils } from '../extras/ShapeUtils.js';
// ExtrudeGeometry
function ExtrudeGeometry( shapes, options ) {
Geometry.call( this );
this.type = 'ExtrudeGeometry';
this.parameters = {
shapes: shapes,
options: options
};
this.fromBufferGeometry( new ExtrudeBufferGeometry( shapes, options ) );
this.mergeVertices();
}
ExtrudeGeometry.prototype = Object.create( Geometry.prototype );
ExtrudeGeometry.prototype.constructor = ExtrudeGeometry;
ExtrudeGeometry.prototype.toJSON = function () {
var data = Geometry.prototype.toJSON.call( this );
var shapes = this.parameters.shapes;
var options = this.parameters.options;
return toJSON( shapes, options, data );
};
// ExtrudeBufferGeometry
function ExtrudeBufferGeometry( shapes, options ) {
BufferGeometry.call( this );
this.type = 'ExtrudeBufferGeometry';
this.parameters = {
shapes: shapes,
options: options
};
shapes = Array.isArray( shapes ) ? shapes : [ shapes ];
var scope = this;
var verticesArray = [];
var uvArray = [];
for ( var i = 0, l = shapes.length; i < l; i ++ ) {
var shape = shapes[ i ];
addShape( shape );
}
// build geometry
this.addAttribute( 'position', new Float32BufferAttribute( verticesArray, 3 ) );
this.addAttribute( 'uv', new Float32BufferAttribute( uvArray, 2 ) );
this.computeVertexNormals();
// functions
function addShape( shape ) {
var placeholder = [];
// options
var curveSegments = options.curveSegments !== undefined ? options.curveSegments : 12;
var steps = options.steps !== undefined ? options.steps : 1;
var depth = options.depth !== undefined ? options.depth : 100;
var bevelEnabled = options.bevelEnabled !== undefined ? options.bevelEnabled : true;
var bevelThickness = options.bevelThickness !== undefined ? options.bevelThickness : 6;
var bevelSize = options.bevelSize !== undefined ? options.bevelSize : bevelThickness - 2;
var bevelSegments = options.bevelSegments !== undefined ? options.bevelSegments : 3;
var extrudePath = options.extrudePath;
var uvgen = options.UVGenerator !== undefined ? options.UVGenerator : WorldUVGenerator;
// deprecated options
if ( options.amount !== undefined ) {
console.warn( 'THREE.ExtrudeBufferGeometry: amount has been renamed to depth.' );
depth = options.amount;
}
//
var extrudePts, extrudeByPath = false;
var splineTube, binormal, normal, position2;
if ( extrudePath ) {
extrudePts = extrudePath.getSpacedPoints( steps );
extrudeByPath = true;
bevelEnabled = false; // bevels not supported for path extrusion
// SETUP TNB variables
// TODO1 - have a .isClosed in spline?
splineTube = extrudePath.computeFrenetFrames( steps, false );
// console.log(splineTube, 'splineTube', splineTube.normals.length, 'steps', steps, 'extrudePts', extrudePts.length);
binormal = new Vector3();
normal = new Vector3();
position2 = new Vector3();
}
// Safeguards if bevels are not enabled
if ( ! bevelEnabled ) {
bevelSegments = 0;
bevelThickness = 0;
bevelSize = 0;
}
// Variables initialization
var ahole, h, hl; // looping of holes
var shapePoints = shape.extractPoints( curveSegments );
var vertices = shapePoints.shape;
var holes = shapePoints.holes;
var reverse = ! ShapeUtils.isClockWise( vertices );
if ( reverse ) {
vertices = vertices.reverse();
// Maybe we should also check if holes are in the opposite direction, just to be safe ...
for ( h = 0, hl = holes.length; h < hl; h ++ ) {
ahole = holes[ h ];
if ( ShapeUtils.isClockWise( ahole ) ) {
holes[ h ] = ahole.reverse();
}
}
}
var faces = ShapeUtils.triangulateShape( vertices, holes );
/* Vertices */
var contour = vertices; // vertices has all points but contour has only points of circumference
for ( h = 0, hl = holes.length; h < hl; h ++ ) {
ahole = holes[ h ];
vertices = vertices.concat( ahole );
}
function scalePt2( pt, vec, size ) {
if ( ! vec ) console.error( "THREE.ExtrudeGeometry: vec does not exist" );
return vec.clone().multiplyScalar( size ).add( pt );
}
var b, bs, t, z,
vert, vlen = vertices.length,
face, flen = faces.length;
// Find directions for point movement
function getBevelVec( inPt, inPrev, inNext ) {
// computes for inPt the corresponding point inPt' on a new contour
// shifted by 1 unit (length of normalized vector) to the left
// if we walk along contour clockwise, this new contour is outside the old one
//
// inPt' is the intersection of the two lines parallel to the two
// adjacent edges of inPt at a distance of 1 unit on the left side.
var v_trans_x, v_trans_y, shrink_by; // resulting translation vector for inPt
// good reading for geometry algorithms (here: line-line intersection)
// http://geomalgorithms.com/a05-_intersect-1.html
var v_prev_x = inPt.x - inPrev.x,
v_prev_y = inPt.y - inPrev.y;
var v_next_x = inNext.x - inPt.x,
v_next_y = inNext.y - inPt.y;
var v_prev_lensq = ( v_prev_x * v_prev_x + v_prev_y * v_prev_y );
// check for collinear edges
var collinear0 = ( v_prev_x * v_next_y - v_prev_y * v_next_x );
if ( Math.abs( collinear0 ) > Number.EPSILON ) {
// not collinear
// length of vectors for normalizing
var v_prev_len = Math.sqrt( v_prev_lensq );
var v_next_len = Math.sqrt( v_next_x * v_next_x + v_next_y * v_next_y );
// shift adjacent points by unit vectors to the left
var ptPrevShift_x = ( inPrev.x - v_prev_y / v_prev_len );
var ptPrevShift_y = ( inPrev.y + v_prev_x / v_prev_len );
var ptNextShift_x = ( inNext.x - v_next_y / v_next_len );
var ptNextShift_y = ( inNext.y + v_next_x / v_next_len );
// scaling factor for v_prev to intersection point
var sf = ( ( ptNextShift_x - ptPrevShift_x ) * v_next_y -
( ptNextShift_y - ptPrevShift_y ) * v_next_x ) /
( v_prev_x * v_next_y - v_prev_y * v_next_x );
// vector from inPt to intersection point
v_trans_x = ( ptPrevShift_x + v_prev_x * sf - inPt.x );
v_trans_y = ( ptPrevShift_y + v_prev_y * sf - inPt.y );
// Don't normalize!, otherwise sharp corners become ugly
// but prevent crazy spikes
var v_trans_lensq = ( v_trans_x * v_trans_x + v_trans_y * v_trans_y );
if ( v_trans_lensq <= 2 ) {
return new Vector2( v_trans_x, v_trans_y );
} else {
shrink_by = Math.sqrt( v_trans_lensq / 2 );
}
} else {
// handle special case of collinear edges
var direction_eq = false; // assumes: opposite
if ( v_prev_x > Number.EPSILON ) {
if ( v_next_x > Number.EPSILON ) {
direction_eq = true;
}
} else {
if ( v_prev_x < - Number.EPSILON ) {
if ( v_next_x < - Number.EPSILON ) {
direction_eq = true;
}
} else {
if ( Math.sign( v_prev_y ) === Math.sign( v_next_y ) ) {
direction_eq = true;
}
}
}
if ( direction_eq ) {
// console.log("Warning: lines are a straight sequence");
v_trans_x = - v_prev_y;
v_trans_y = v_prev_x;
shrink_by = Math.sqrt( v_prev_lensq );
} else {
// console.log("Warning: lines are a straight spike");
v_trans_x = v_prev_x;
v_trans_y = v_prev_y;
shrink_by = Math.sqrt( v_prev_lensq / 2 );
}
}
return new Vector2( v_trans_x / shrink_by, v_trans_y / shrink_by );
}
var contourMovements = [];
for ( var i = 0, il = contour.length, j = il - 1, k = i + 1; i < il; i ++, j ++, k ++ ) {
if ( j === il ) j = 0;
if ( k === il ) k = 0;
// (j)---(i)---(k)
// console.log('i,j,k', i, j , k)
contourMovements[ i ] = getBevelVec( contour[ i ], contour[ j ], contour[ k ] );
}
var holesMovements = [],
oneHoleMovements, verticesMovements = contourMovements.concat();
for ( h = 0, hl = holes.length; h < hl; h ++ ) {
ahole = holes[ h ];
oneHoleMovements = [];
for ( i = 0, il = ahole.length, j = il - 1, k = i + 1; i < il; i ++, j ++, k ++ ) {
if ( j === il ) j = 0;
if ( k === il ) k = 0;
// (j)---(i)---(k)
oneHoleMovements[ i ] = getBevelVec( ahole[ i ], ahole[ j ], ahole[ k ] );
}
holesMovements.push( oneHoleMovements );
verticesMovements = verticesMovements.concat( oneHoleMovements );
}
// Loop bevelSegments, 1 for the front, 1 for the back
for ( b = 0; b < bevelSegments; b ++ ) {
//for ( b = bevelSegments; b > 0; b -- ) {
t = b / bevelSegments;
z = bevelThickness * Math.cos( t * Math.PI / 2 );
bs = bevelSize * Math.sin( t * Math.PI / 2 );
// contract shape
for ( i = 0, il = contour.length; i < il; i ++ ) {
vert = scalePt2( contour[ i ], contourMovements[ i ], bs );
v( vert.x, vert.y, - z );
}
// expand holes
for ( h = 0, hl = holes.length; h < hl; h ++ ) {
ahole = holes[ h ];
oneHoleMovements = holesMovements[ h ];
for ( i = 0, il = ahole.length; i < il; i ++ ) {
vert = scalePt2( ahole[ i ], oneHoleMovements[ i ], bs );
v( vert.x, vert.y, - z );
}
}
}
bs = bevelSize;
// Back facing vertices
for ( i = 0; i < vlen; i ++ ) {
vert = bevelEnabled ? scalePt2( vertices[ i ], verticesMovements[ i ], bs ) : vertices[ i ];
if ( ! extrudeByPath ) {
v( vert.x, vert.y, 0 );
} else {
// v( vert.x, vert.y + extrudePts[ 0 ].y, extrudePts[ 0 ].x );
normal.copy( splineTube.normals[ 0 ] ).multiplyScalar( vert.x );
binormal.copy( splineTube.binormals[ 0 ] ).multiplyScalar( vert.y );
position2.copy( extrudePts[ 0 ] ).add( normal ).add( binormal );
v( position2.x, position2.y, position2.z );
}
}
// Add stepped vertices...
// Including front facing vertices
var s;
for ( s = 1; s <= steps; s ++ ) {
for ( i = 0; i < vlen; i ++ ) {
vert = bevelEnabled ? scalePt2( vertices[ i ], verticesMovements[ i ], bs ) : vertices[ i ];
if ( ! extrudeByPath ) {
v( vert.x, vert.y, depth / steps * s );
} else {
// v( vert.x, vert.y + extrudePts[ s - 1 ].y, extrudePts[ s - 1 ].x );
normal.copy( splineTube.normals[ s ] ).multiplyScalar( vert.x );
binormal.copy( splineTube.binormals[ s ] ).multiplyScalar( vert.y );
position2.copy( extrudePts[ s ] ).add( normal ).add( binormal );
v( position2.x, position2.y, position2.z );
}
}
}
// Add bevel segments planes
//for ( b = 1; b <= bevelSegments; b ++ ) {
for ( b = bevelSegments - 1; b >= 0; b -- ) {
t = b / bevelSegments;
z = bevelThickness * Math.cos( t * Math.PI / 2 );
bs = bevelSize * Math.sin( t * Math.PI / 2 );
// contract shape
for ( i = 0, il = contour.length; i < il; i ++ ) {
vert = scalePt2( contour[ i ], contourMovements[ i ], bs );
v( vert.x, vert.y, depth + z );
}
// expand holes
for ( h = 0, hl = holes.length; h < hl; h ++ ) {
ahole = holes[ h ];
oneHoleMovements = holesMovements[ h ];
for ( i = 0, il = ahole.length; i < il; i ++ ) {
vert = scalePt2( ahole[ i ], oneHoleMovements[ i ], bs );
if ( ! extrudeByPath ) {
v( vert.x, vert.y, depth + z );
} else {
v( vert.x, vert.y + extrudePts[ steps - 1 ].y, extrudePts[ steps - 1 ].x + z );
}
}
}
}
/* Faces */
// Top and bottom faces
buildLidFaces();
// Sides faces
buildSideFaces();
///// Internal functions
function buildLidFaces() {
var start = verticesArray.length / 3;
if ( bevelEnabled ) {
var layer = 0; // steps + 1
var offset = vlen * layer;
// Bottom faces
for ( i = 0; i < flen; i ++ ) {
face = faces[ i ];
f3( face[ 2 ] + offset, face[ 1 ] + offset, face[ 0 ] + offset );
}
layer = steps + bevelSegments * 2;
offset = vlen * layer;
// Top faces
for ( i = 0; i < flen; i ++ ) {
face = faces[ i ];
f3( face[ 0 ] + offset, face[ 1 ] + offset, face[ 2 ] + offset );
}
} else {
// Bottom faces
for ( i = 0; i < flen; i ++ ) {
face = faces[ i ];
f3( face[ 2 ], face[ 1 ], face[ 0 ] );
}
// Top faces
for ( i = 0; i < flen; i ++ ) {
face = faces[ i ];
f3( face[ 0 ] + vlen * steps, face[ 1 ] + vlen * steps, face[ 2 ] + vlen * steps );
}
}
scope.addGroup( start, verticesArray.length / 3 - start, 0 );
}
// Create faces for the z-sides of the shape
function buildSideFaces() {
var start = verticesArray.length / 3;
var layeroffset = 0;
sidewalls( contour, layeroffset );
layeroffset += contour.length;
for ( h = 0, hl = holes.length; h < hl; h ++ ) {
ahole = holes[ h ];
sidewalls( ahole, layeroffset );
//, true
layeroffset += ahole.length;
}
scope.addGroup( start, verticesArray.length / 3 - start, 1 );
}
function sidewalls( contour, layeroffset ) {
var j, k;
i = contour.length;
while ( -- i >= 0 ) {
j = i;
k = i - 1;
if ( k < 0 ) k = contour.length - 1;
//console.log('b', i,j, i-1, k,vertices.length);
var s = 0,
sl = steps + bevelSegments * 2;
for ( s = 0; s < sl; s ++ ) {
var slen1 = vlen * s;
var slen2 = vlen * ( s + 1 );
var a = layeroffset + j + slen1,
b = layeroffset + k + slen1,
c = layeroffset + k + slen2,
d = layeroffset + j + slen2;
f4( a, b, c, d );
}
}
}
function v( x, y, z ) {
placeholder.push( x );
placeholder.push( y );
placeholder.push( z );
}
function f3( a, b, c ) {
addVertex( a );
addVertex( b );
addVertex( c );
var nextIndex = verticesArray.length / 3;
var uvs = uvgen.generateTopUV( scope, verticesArray, nextIndex - 3, nextIndex - 2, nextIndex - 1 );
addUV( uvs[ 0 ] );
addUV( uvs[ 1 ] );
addUV( uvs[ 2 ] );
}
function f4( a, b, c, d ) {
addVertex( a );
addVertex( b );
addVertex( d );
addVertex( b );
addVertex( c );
addVertex( d );
var nextIndex = verticesArray.length / 3;
var uvs = uvgen.generateSideWallUV( scope, verticesArray, nextIndex - 6, nextIndex - 3, nextIndex - 2, nextIndex - 1 );
addUV( uvs[ 0 ] );
addUV( uvs[ 1 ] );
addUV( uvs[ 3 ] );
addUV( uvs[ 1 ] );
addUV( uvs[ 2 ] );
addUV( uvs[ 3 ] );
}
function addVertex( index ) {
verticesArray.push( placeholder[ index * 3 + 0 ] );
verticesArray.push( placeholder[ index * 3 + 1 ] );
verticesArray.push( placeholder[ index * 3 + 2 ] );
}
function addUV( vector2 ) {
uvArray.push( vector2.x );
uvArray.push( vector2.y );
}
}
}
ExtrudeBufferGeometry.prototype = Object.create( BufferGeometry.prototype );
ExtrudeBufferGeometry.prototype.constructor = ExtrudeBufferGeometry;
ExtrudeBufferGeometry.prototype.toJSON = function () {
var data = BufferGeometry.prototype.toJSON.call( this );
var shapes = this.parameters.shapes;
var options = this.parameters.options;
return toJSON( shapes, options, data );
};
//
var WorldUVGenerator = {
generateTopUV: function ( geometry, vertices, indexA, indexB, indexC ) {
var a_x = vertices[ indexA * 3 ];
var a_y = vertices[ indexA * 3 + 1 ];
var b_x = vertices[ indexB * 3 ];
var b_y = vertices[ indexB * 3 + 1 ];
var c_x = vertices[ indexC * 3 ];
var c_y = vertices[ indexC * 3 + 1 ];
return [
new Vector2( a_x, a_y ),
new Vector2( b_x, b_y ),
new Vector2( c_x, c_y )
];
},
generateSideWallUV: function ( geometry, vertices, indexA, indexB, indexC, indexD ) {
var a_x = vertices[ indexA * 3 ];
var a_y = vertices[ indexA * 3 + 1 ];
var a_z = vertices[ indexA * 3 + 2 ];
var b_x = vertices[ indexB * 3 ];
var b_y = vertices[ indexB * 3 + 1 ];
var b_z = vertices[ indexB * 3 + 2 ];
var c_x = vertices[ indexC * 3 ];
var c_y = vertices[ indexC * 3 + 1 ];
var c_z = vertices[ indexC * 3 + 2 ];
var d_x = vertices[ indexD * 3 ];
var d_y = vertices[ indexD * 3 + 1 ];
var d_z = vertices[ indexD * 3 + 2 ];
if ( Math.abs( a_y - b_y ) < 0.01 ) {
return [
new Vector2( a_x, 1 - a_z ),
new Vector2( b_x, 1 - b_z ),
new Vector2( c_x, 1 - c_z ),
new Vector2( d_x, 1 - d_z )
];
} else {
return [
new Vector2( a_y, 1 - a_z ),
new Vector2( b_y, 1 - b_z ),
new Vector2( c_y, 1 - c_z ),
new Vector2( d_y, 1 - d_z )
];
}
}
};
function toJSON( shapes, options, data ) {
//
data.shapes = [];
if ( Array.isArray( shapes ) ) {
for ( var i = 0, l = shapes.length; i < l; i ++ ) {
var shape = shapes[ i ];
data.shapes.push( shape.uuid );
}
} else {
data.shapes.push( shapes.uuid );
}
//
if ( options.extrudePath !== undefined ) data.options.extrudePath = options.extrudePath.toJSON();
return data;
}
export { ExtrudeGeometry, ExtrudeBufferGeometry };

View File

@ -0,0 +1,22 @@
export { WireframeGeometry } from './WireframeGeometry.js';
export { ParametricGeometry, ParametricBufferGeometry } from './ParametricGeometry.js';
export { TetrahedronGeometry, TetrahedronBufferGeometry } from './TetrahedronGeometry.js';
export { OctahedronGeometry, OctahedronBufferGeometry } from './OctahedronGeometry.js';
export { IcosahedronGeometry, IcosahedronBufferGeometry } from './IcosahedronGeometry.js';
export { DodecahedronGeometry, DodecahedronBufferGeometry } from './DodecahedronGeometry.js';
export { PolyhedronGeometry, PolyhedronBufferGeometry } from './PolyhedronGeometry.js';
export { TubeGeometry, TubeBufferGeometry } from './TubeGeometry.js';
export { TorusKnotGeometry, TorusKnotBufferGeometry } from './TorusKnotGeometry.js';
export { TorusGeometry, TorusBufferGeometry } from './TorusGeometry.js';
export { TextGeometry, TextBufferGeometry } from './TextGeometry.js';
export { SphereGeometry, SphereBufferGeometry } from './SphereGeometry.js';
export { RingGeometry, RingBufferGeometry } from './RingGeometry.js';
export { PlaneGeometry, PlaneBufferGeometry } from './PlaneGeometry.js';
export { LatheGeometry, LatheBufferGeometry } from './LatheGeometry.js';
export { ShapeGeometry, ShapeBufferGeometry } from './ShapeGeometry.js';
export { ExtrudeGeometry, ExtrudeBufferGeometry } from './ExtrudeGeometry.js';
export { EdgesGeometry } from './EdgesGeometry.js';
export { ConeGeometry, ConeBufferGeometry } from './ConeGeometry.js';
export { CylinderGeometry, CylinderBufferGeometry } from './CylinderGeometry.js';
export { CircleGeometry, CircleBufferGeometry } from './CircleGeometry.js';
export { BoxGeometry, BoxBufferGeometry } from './BoxGeometry.js';

View File

@ -0,0 +1,64 @@
/**
* @author timothypratley / https://github.com/timothypratley
* @author Mugen87 / https://github.com/Mugen87
*/
import { Geometry } from '../core/Geometry.js';
import { PolyhedronBufferGeometry } from './PolyhedronGeometry.js';
// IcosahedronGeometry
function IcosahedronGeometry( radius, detail ) {
Geometry.call( this );
this.type = 'IcosahedronGeometry';
this.parameters = {
radius: radius,
detail: detail
};
this.fromBufferGeometry( new IcosahedronBufferGeometry( radius, detail ) );
this.mergeVertices();
}
IcosahedronGeometry.prototype = Object.create( Geometry.prototype );
IcosahedronGeometry.prototype.constructor = IcosahedronGeometry;
// IcosahedronBufferGeometry
function IcosahedronBufferGeometry( radius, detail ) {
var t = ( 1 + Math.sqrt( 5 ) ) / 2;
var vertices = [
- 1, t, 0, 1, t, 0, - 1, - t, 0, 1, - t, 0,
0, - 1, t, 0, 1, t, 0, - 1, - t, 0, 1, - t,
t, 0, - 1, t, 0, 1, - t, 0, - 1, - t, 0, 1
];
var indices = [
0, 11, 5, 0, 5, 1, 0, 1, 7, 0, 7, 10, 0, 10, 11,
1, 5, 9, 5, 11, 4, 11, 10, 2, 10, 7, 6, 7, 1, 8,
3, 9, 4, 3, 4, 2, 3, 2, 6, 3, 6, 8, 3, 8, 9,
4, 9, 5, 2, 4, 11, 6, 2, 10, 8, 6, 7, 9, 8, 1
];
PolyhedronBufferGeometry.call( this, vertices, indices, radius, detail );
this.type = 'IcosahedronBufferGeometry';
this.parameters = {
radius: radius,
detail: detail
};
}
IcosahedronBufferGeometry.prototype = Object.create( PolyhedronBufferGeometry.prototype );
IcosahedronBufferGeometry.prototype.constructor = IcosahedronBufferGeometry;
export { IcosahedronGeometry, IcosahedronBufferGeometry };

View File

@ -0,0 +1,186 @@
/**
* @author zz85 / https://github.com/zz85
* @author bhouston / http://clara.io
* @author Mugen87 / https://github.com/Mugen87
*/
import { Geometry } from '../core/Geometry.js';
import { Float32BufferAttribute } from '../core/BufferAttribute.js';
import { BufferGeometry } from '../core/BufferGeometry.js';
import { Vector3 } from '../math/Vector3.js';
import { Vector2 } from '../math/Vector2.js';
import { _Math } from '../math/Math.js';
// LatheGeometry
function LatheGeometry( points, segments, phiStart, phiLength ) {
Geometry.call( this );
this.type = 'LatheGeometry';
this.parameters = {
points: points,
segments: segments,
phiStart: phiStart,
phiLength: phiLength
};
this.fromBufferGeometry( new LatheBufferGeometry( points, segments, phiStart, phiLength ) );
this.mergeVertices();
}
LatheGeometry.prototype = Object.create( Geometry.prototype );
LatheGeometry.prototype.constructor = LatheGeometry;
// LatheBufferGeometry
function LatheBufferGeometry( points, segments, phiStart, phiLength ) {
BufferGeometry.call( this );
this.type = 'LatheBufferGeometry';
this.parameters = {
points: points,
segments: segments,
phiStart: phiStart,
phiLength: phiLength
};
segments = Math.floor( segments ) || 12;
phiStart = phiStart || 0;
phiLength = phiLength || Math.PI * 2;
// clamp phiLength so it's in range of [ 0, 2PI ]
phiLength = _Math.clamp( phiLength, 0, Math.PI * 2 );
// buffers
var indices = [];
var vertices = [];
var uvs = [];
// helper variables
var base;
var inverseSegments = 1.0 / segments;
var vertex = new Vector3();
var uv = new Vector2();
var i, j;
// generate vertices and uvs
for ( i = 0; i <= segments; i ++ ) {
var phi = phiStart + i * inverseSegments * phiLength;
var sin = Math.sin( phi );
var cos = Math.cos( phi );
for ( j = 0; j <= ( points.length - 1 ); j ++ ) {
// vertex
vertex.x = points[ j ].x * sin;
vertex.y = points[ j ].y;
vertex.z = points[ j ].x * cos;
vertices.push( vertex.x, vertex.y, vertex.z );
// uv
uv.x = i / segments;
uv.y = j / ( points.length - 1 );
uvs.push( uv.x, uv.y );
}
}
// indices
for ( i = 0; i < segments; i ++ ) {
for ( j = 0; j < ( points.length - 1 ); j ++ ) {
base = j + i * points.length;
var a = base;
var b = base + points.length;
var c = base + points.length + 1;
var d = base + 1;
// faces
indices.push( a, b, d );
indices.push( b, c, d );
}
}
// build geometry
this.setIndex( indices );
this.addAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) );
this.addAttribute( 'uv', new Float32BufferAttribute( uvs, 2 ) );
// generate normals
this.computeVertexNormals();
// if the geometry is closed, we need to average the normals along the seam.
// because the corresponding vertices are identical (but still have different UVs).
if ( phiLength === Math.PI * 2 ) {
var normals = this.attributes.normal.array;
var n1 = new Vector3();
var n2 = new Vector3();
var n = new Vector3();
// this is the buffer offset for the last line of vertices
base = segments * points.length * 3;
for ( i = 0, j = 0; i < points.length; i ++, j += 3 ) {
// select the normal of the vertex in the first line
n1.x = normals[ j + 0 ];
n1.y = normals[ j + 1 ];
n1.z = normals[ j + 2 ];
// select the normal of the vertex in the last line
n2.x = normals[ base + j + 0 ];
n2.y = normals[ base + j + 1 ];
n2.z = normals[ base + j + 2 ];
// average normals
n.addVectors( n1, n2 ).normalize();
// assign the new values to both normals
normals[ j + 0 ] = normals[ base + j + 0 ] = n.x;
normals[ j + 1 ] = normals[ base + j + 1 ] = n.y;
normals[ j + 2 ] = normals[ base + j + 2 ] = n.z;
}
}
}
LatheBufferGeometry.prototype = Object.create( BufferGeometry.prototype );
LatheBufferGeometry.prototype.constructor = LatheBufferGeometry;
export { LatheGeometry, LatheBufferGeometry };

View File

@ -0,0 +1,60 @@
/**
* @author timothypratley / https://github.com/timothypratley
* @author Mugen87 / https://github.com/Mugen87
*/
import { Geometry } from '../core/Geometry.js';
import { PolyhedronBufferGeometry } from './PolyhedronGeometry.js';
// OctahedronGeometry
function OctahedronGeometry( radius, detail ) {
Geometry.call( this );
this.type = 'OctahedronGeometry';
this.parameters = {
radius: radius,
detail: detail
};
this.fromBufferGeometry( new OctahedronBufferGeometry( radius, detail ) );
this.mergeVertices();
}
OctahedronGeometry.prototype = Object.create( Geometry.prototype );
OctahedronGeometry.prototype.constructor = OctahedronGeometry;
// OctahedronBufferGeometry
function OctahedronBufferGeometry( radius, detail ) {
var vertices = [
1, 0, 0, - 1, 0, 0, 0, 1, 0,
0, - 1, 0, 0, 0, 1, 0, 0, - 1
];
var indices = [
0, 2, 4, 0, 4, 3, 0, 3, 5,
0, 5, 2, 1, 2, 5, 1, 5, 3,
1, 3, 4, 1, 4, 2
];
PolyhedronBufferGeometry.call( this, vertices, indices, radius, detail );
this.type = 'OctahedronBufferGeometry';
this.parameters = {
radius: radius,
detail: detail
};
}
OctahedronBufferGeometry.prototype = Object.create( PolyhedronBufferGeometry.prototype );
OctahedronBufferGeometry.prototype.constructor = OctahedronBufferGeometry;
export { OctahedronGeometry, OctahedronBufferGeometry };

View File

@ -0,0 +1,163 @@
/**
* @author zz85 / https://github.com/zz85
* @author Mugen87 / https://github.com/Mugen87
*
* Parametric Surfaces Geometry
* based on the brilliant article by @prideout http://prideout.net/blog/?p=44
*/
import { Geometry } from '../core/Geometry.js';
import { BufferGeometry } from '../core/BufferGeometry.js';
import { Float32BufferAttribute } from '../core/BufferAttribute.js';
import { Vector3 } from '../math/Vector3.js';
// ParametricGeometry
function ParametricGeometry( func, slices, stacks ) {
Geometry.call( this );
this.type = 'ParametricGeometry';
this.parameters = {
func: func,
slices: slices,
stacks: stacks
};
this.fromBufferGeometry( new ParametricBufferGeometry( func, slices, stacks ) );
this.mergeVertices();
}
ParametricGeometry.prototype = Object.create( Geometry.prototype );
ParametricGeometry.prototype.constructor = ParametricGeometry;
// ParametricBufferGeometry
function ParametricBufferGeometry( func, slices, stacks ) {
BufferGeometry.call( this );
this.type = 'ParametricBufferGeometry';
this.parameters = {
func: func,
slices: slices,
stacks: stacks
};
// buffers
var indices = [];
var vertices = [];
var normals = [];
var uvs = [];
var EPS = 0.00001;
var normal = new Vector3();
var p0 = new Vector3(), p1 = new Vector3();
var pu = new Vector3(), pv = new Vector3();
var i, j;
if ( func.length < 3 ) {
console.error( 'THREE.ParametricGeometry: Function must now modify a Vector3 as third parameter.' );
}
// generate vertices, normals and uvs
var sliceCount = slices + 1;
for ( i = 0; i <= stacks; i ++ ) {
var v = i / stacks;
for ( j = 0; j <= slices; j ++ ) {
var u = j / slices;
// vertex
func( u, v, p0 );
vertices.push( p0.x, p0.y, p0.z );
// normal
// approximate tangent vectors via finite differences
if ( u - EPS >= 0 ) {
func( u - EPS, v, p1 );
pu.subVectors( p0, p1 );
} else {
func( u + EPS, v, p1 );
pu.subVectors( p1, p0 );
}
if ( v - EPS >= 0 ) {
func( u, v - EPS, p1 );
pv.subVectors( p0, p1 );
} else {
func( u, v + EPS, p1 );
pv.subVectors( p1, p0 );
}
// cross product of tangent vectors returns surface normal
normal.crossVectors( pu, pv ).normalize();
normals.push( normal.x, normal.y, normal.z );
// uv
uvs.push( u, v );
}
}
// generate indices
for ( i = 0; i < stacks; i ++ ) {
for ( j = 0; j < slices; j ++ ) {
var a = i * sliceCount + j;
var b = i * sliceCount + j + 1;
var c = ( i + 1 ) * sliceCount + j + 1;
var d = ( i + 1 ) * sliceCount + j;
// faces one and two
indices.push( a, b, d );
indices.push( b, c, d );
}
}
// build geometry
this.setIndex( indices );
this.addAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) );
this.addAttribute( 'normal', new Float32BufferAttribute( normals, 3 ) );
this.addAttribute( 'uv', new Float32BufferAttribute( uvs, 2 ) );
}
ParametricBufferGeometry.prototype = Object.create( BufferGeometry.prototype );
ParametricBufferGeometry.prototype.constructor = ParametricBufferGeometry;
export { ParametricGeometry, ParametricBufferGeometry };

View File

@ -0,0 +1,126 @@
/**
* @author mrdoob / http://mrdoob.com/
* @author Mugen87 / https://github.com/Mugen87
*/
import { Geometry } from '../core/Geometry.js';
import { BufferGeometry } from '../core/BufferGeometry.js';
import { Float32BufferAttribute } from '../core/BufferAttribute.js';
// PlaneGeometry
function PlaneGeometry( width, height, widthSegments, heightSegments ) {
Geometry.call( this );
this.type = 'PlaneGeometry';
this.parameters = {
width: width,
height: height,
widthSegments: widthSegments,
heightSegments: heightSegments
};
this.fromBufferGeometry( new PlaneBufferGeometry( width, height, widthSegments, heightSegments ) );
this.mergeVertices();
}
PlaneGeometry.prototype = Object.create( Geometry.prototype );
PlaneGeometry.prototype.constructor = PlaneGeometry;
// PlaneBufferGeometry
function PlaneBufferGeometry( width, height, widthSegments, heightSegments ) {
BufferGeometry.call( this );
this.type = 'PlaneBufferGeometry';
this.parameters = {
width: width,
height: height,
widthSegments: widthSegments,
heightSegments: heightSegments
};
width = width || 1;
height = height || 1;
var width_half = width / 2;
var height_half = height / 2;
var gridX = Math.floor( widthSegments ) || 1;
var gridY = Math.floor( heightSegments ) || 1;
var gridX1 = gridX + 1;
var gridY1 = gridY + 1;
var segment_width = width / gridX;
var segment_height = height / gridY;
var ix, iy;
// buffers
var indices = [];
var vertices = [];
var normals = [];
var uvs = [];
// generate vertices, normals and uvs
for ( iy = 0; iy < gridY1; iy ++ ) {
var y = iy * segment_height - height_half;
for ( ix = 0; ix < gridX1; ix ++ ) {
var x = ix * segment_width - width_half;
vertices.push( x, - y, 0 );
normals.push( 0, 0, 1 );
uvs.push( ix / gridX );
uvs.push( 1 - ( iy / gridY ) );
}
}
// indices
for ( iy = 0; iy < gridY; iy ++ ) {
for ( ix = 0; ix < gridX; ix ++ ) {
var a = ix + gridX1 * iy;
var b = ix + gridX1 * ( iy + 1 );
var c = ( ix + 1 ) + gridX1 * ( iy + 1 );
var d = ( ix + 1 ) + gridX1 * iy;
// faces
indices.push( a, b, d );
indices.push( b, c, d );
}
}
// build geometry
this.setIndex( indices );
this.addAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) );
this.addAttribute( 'normal', new Float32BufferAttribute( normals, 3 ) );
this.addAttribute( 'uv', new Float32BufferAttribute( uvs, 2 ) );
}
PlaneBufferGeometry.prototype = Object.create( BufferGeometry.prototype );
PlaneBufferGeometry.prototype.constructor = PlaneBufferGeometry;
export { PlaneGeometry, PlaneBufferGeometry };

View File

@ -0,0 +1,341 @@
/**
* @author clockworkgeek / https://github.com/clockworkgeek
* @author timothypratley / https://github.com/timothypratley
* @author WestLangley / http://github.com/WestLangley
* @author Mugen87 / https://github.com/Mugen87
*/
import { Geometry } from '../core/Geometry.js';
import { BufferGeometry } from '../core/BufferGeometry.js';
import { Float32BufferAttribute } from '../core/BufferAttribute.js';
import { Vector3 } from '../math/Vector3.js';
import { Vector2 } from '../math/Vector2.js';
// PolyhedronGeometry
function PolyhedronGeometry( vertices, indices, radius, detail ) {
Geometry.call( this );
this.type = 'PolyhedronGeometry';
this.parameters = {
vertices: vertices,
indices: indices,
radius: radius,
detail: detail
};
this.fromBufferGeometry( new PolyhedronBufferGeometry( vertices, indices, radius, detail ) );
this.mergeVertices();
}
PolyhedronGeometry.prototype = Object.create( Geometry.prototype );
PolyhedronGeometry.prototype.constructor = PolyhedronGeometry;
// PolyhedronBufferGeometry
function PolyhedronBufferGeometry( vertices, indices, radius, detail ) {
BufferGeometry.call( this );
this.type = 'PolyhedronBufferGeometry';
this.parameters = {
vertices: vertices,
indices: indices,
radius: radius,
detail: detail
};
radius = radius || 1;
detail = detail || 0;
// default buffer data
var vertexBuffer = [];
var uvBuffer = [];
// the subdivision creates the vertex buffer data
subdivide( detail );
// all vertices should lie on a conceptual sphere with a given radius
appplyRadius( radius );
// finally, create the uv data
generateUVs();
// build non-indexed geometry
this.addAttribute( 'position', new Float32BufferAttribute( vertexBuffer, 3 ) );
this.addAttribute( 'normal', new Float32BufferAttribute( vertexBuffer.slice(), 3 ) );
this.addAttribute( 'uv', new Float32BufferAttribute( uvBuffer, 2 ) );
if ( detail === 0 ) {
this.computeVertexNormals(); // flat normals
} else {
this.normalizeNormals(); // smooth normals
}
// helper functions
function subdivide( detail ) {
var a = new Vector3();
var b = new Vector3();
var c = new Vector3();
// iterate over all faces and apply a subdivison with the given detail value
for ( var i = 0; i < indices.length; i += 3 ) {
// get the vertices of the face
getVertexByIndex( indices[ i + 0 ], a );
getVertexByIndex( indices[ i + 1 ], b );
getVertexByIndex( indices[ i + 2 ], c );
// perform subdivision
subdivideFace( a, b, c, detail );
}
}
function subdivideFace( a, b, c, detail ) {
var cols = Math.pow( 2, detail );
// we use this multidimensional array as a data structure for creating the subdivision
var v = [];
var i, j;
// construct all of the vertices for this subdivision
for ( i = 0; i <= cols; i ++ ) {
v[ i ] = [];
var aj = a.clone().lerp( c, i / cols );
var bj = b.clone().lerp( c, i / cols );
var rows = cols - i;
for ( j = 0; j <= rows; j ++ ) {
if ( j === 0 && i === cols ) {
v[ i ][ j ] = aj;
} else {
v[ i ][ j ] = aj.clone().lerp( bj, j / rows );
}
}
}
// construct all of the faces
for ( i = 0; i < cols; i ++ ) {
for ( j = 0; j < 2 * ( cols - i ) - 1; j ++ ) {
var k = Math.floor( j / 2 );
if ( j % 2 === 0 ) {
pushVertex( v[ i ][ k + 1 ] );
pushVertex( v[ i + 1 ][ k ] );
pushVertex( v[ i ][ k ] );
} else {
pushVertex( v[ i ][ k + 1 ] );
pushVertex( v[ i + 1 ][ k + 1 ] );
pushVertex( v[ i + 1 ][ k ] );
}
}
}
}
function appplyRadius( radius ) {
var vertex = new Vector3();
// iterate over the entire buffer and apply the radius to each vertex
for ( var i = 0; i < vertexBuffer.length; i += 3 ) {
vertex.x = vertexBuffer[ i + 0 ];
vertex.y = vertexBuffer[ i + 1 ];
vertex.z = vertexBuffer[ i + 2 ];
vertex.normalize().multiplyScalar( radius );
vertexBuffer[ i + 0 ] = vertex.x;
vertexBuffer[ i + 1 ] = vertex.y;
vertexBuffer[ i + 2 ] = vertex.z;
}
}
function generateUVs() {
var vertex = new Vector3();
for ( var i = 0; i < vertexBuffer.length; i += 3 ) {
vertex.x = vertexBuffer[ i + 0 ];
vertex.y = vertexBuffer[ i + 1 ];
vertex.z = vertexBuffer[ i + 2 ];
var u = azimuth( vertex ) / 2 / Math.PI + 0.5;
var v = inclination( vertex ) / Math.PI + 0.5;
uvBuffer.push( u, 1 - v );
}
correctUVs();
correctSeam();
}
function correctSeam() {
// handle case when face straddles the seam, see #3269
for ( var i = 0; i < uvBuffer.length; i += 6 ) {
// uv data of a single face
var x0 = uvBuffer[ i + 0 ];
var x1 = uvBuffer[ i + 2 ];
var x2 = uvBuffer[ i + 4 ];
var max = Math.max( x0, x1, x2 );
var min = Math.min( x0, x1, x2 );
// 0.9 is somewhat arbitrary
if ( max > 0.9 && min < 0.1 ) {
if ( x0 < 0.2 ) uvBuffer[ i + 0 ] += 1;
if ( x1 < 0.2 ) uvBuffer[ i + 2 ] += 1;
if ( x2 < 0.2 ) uvBuffer[ i + 4 ] += 1;
}
}
}
function pushVertex( vertex ) {
vertexBuffer.push( vertex.x, vertex.y, vertex.z );
}
function getVertexByIndex( index, vertex ) {
var stride = index * 3;
vertex.x = vertices[ stride + 0 ];
vertex.y = vertices[ stride + 1 ];
vertex.z = vertices[ stride + 2 ];
}
function correctUVs() {
var a = new Vector3();
var b = new Vector3();
var c = new Vector3();
var centroid = new Vector3();
var uvA = new Vector2();
var uvB = new Vector2();
var uvC = new Vector2();
for ( var i = 0, j = 0; i < vertexBuffer.length; i += 9, j += 6 ) {
a.set( vertexBuffer[ i + 0 ], vertexBuffer[ i + 1 ], vertexBuffer[ i + 2 ] );
b.set( vertexBuffer[ i + 3 ], vertexBuffer[ i + 4 ], vertexBuffer[ i + 5 ] );
c.set( vertexBuffer[ i + 6 ], vertexBuffer[ i + 7 ], vertexBuffer[ i + 8 ] );
uvA.set( uvBuffer[ j + 0 ], uvBuffer[ j + 1 ] );
uvB.set( uvBuffer[ j + 2 ], uvBuffer[ j + 3 ] );
uvC.set( uvBuffer[ j + 4 ], uvBuffer[ j + 5 ] );
centroid.copy( a ).add( b ).add( c ).divideScalar( 3 );
var azi = azimuth( centroid );
correctUV( uvA, j + 0, a, azi );
correctUV( uvB, j + 2, b, azi );
correctUV( uvC, j + 4, c, azi );
}
}
function correctUV( uv, stride, vector, azimuth ) {
if ( ( azimuth < 0 ) && ( uv.x === 1 ) ) {
uvBuffer[ stride ] = uv.x - 1;
}
if ( ( vector.x === 0 ) && ( vector.z === 0 ) ) {
uvBuffer[ stride ] = azimuth / 2 / Math.PI + 0.5;
}
}
// Angle around the Y axis, counter-clockwise when looking from above.
function azimuth( vector ) {
return Math.atan2( vector.z, - vector.x );
}
// Angle above the XZ plane.
function inclination( vector ) {
return Math.atan2( - vector.y, Math.sqrt( ( vector.x * vector.x ) + ( vector.z * vector.z ) ) );
}
}
PolyhedronBufferGeometry.prototype = Object.create( BufferGeometry.prototype );
PolyhedronBufferGeometry.prototype.constructor = PolyhedronBufferGeometry;
export { PolyhedronGeometry, PolyhedronBufferGeometry };

View File

@ -0,0 +1,152 @@
/**
* @author Kaleb Murphy
* @author Mugen87 / https://github.com/Mugen87
*/
import { Geometry } from '../core/Geometry.js';
import { BufferGeometry } from '../core/BufferGeometry.js';
import { Float32BufferAttribute } from '../core/BufferAttribute.js';
import { Vector2 } from '../math/Vector2.js';
import { Vector3 } from '../math/Vector3.js';
// RingGeometry
function RingGeometry( innerRadius, outerRadius, thetaSegments, phiSegments, thetaStart, thetaLength ) {
Geometry.call( this );
this.type = 'RingGeometry';
this.parameters = {
innerRadius: innerRadius,
outerRadius: outerRadius,
thetaSegments: thetaSegments,
phiSegments: phiSegments,
thetaStart: thetaStart,
thetaLength: thetaLength
};
this.fromBufferGeometry( new RingBufferGeometry( innerRadius, outerRadius, thetaSegments, phiSegments, thetaStart, thetaLength ) );
this.mergeVertices();
}
RingGeometry.prototype = Object.create( Geometry.prototype );
RingGeometry.prototype.constructor = RingGeometry;
// RingBufferGeometry
function RingBufferGeometry( innerRadius, outerRadius, thetaSegments, phiSegments, thetaStart, thetaLength ) {
BufferGeometry.call( this );
this.type = 'RingBufferGeometry';
this.parameters = {
innerRadius: innerRadius,
outerRadius: outerRadius,
thetaSegments: thetaSegments,
phiSegments: phiSegments,
thetaStart: thetaStart,
thetaLength: thetaLength
};
innerRadius = innerRadius || 0.5;
outerRadius = outerRadius || 1;
thetaStart = thetaStart !== undefined ? thetaStart : 0;
thetaLength = thetaLength !== undefined ? thetaLength : Math.PI * 2;
thetaSegments = thetaSegments !== undefined ? Math.max( 3, thetaSegments ) : 8;
phiSegments = phiSegments !== undefined ? Math.max( 1, phiSegments ) : 1;
// buffers
var indices = [];
var vertices = [];
var normals = [];
var uvs = [];
// some helper variables
var segment;
var radius = innerRadius;
var radiusStep = ( ( outerRadius - innerRadius ) / phiSegments );
var vertex = new Vector3();
var uv = new Vector2();
var j, i;
// generate vertices, normals and uvs
for ( j = 0; j <= phiSegments; j ++ ) {
for ( i = 0; i <= thetaSegments; i ++ ) {
// values are generate from the inside of the ring to the outside
segment = thetaStart + i / thetaSegments * thetaLength;
// vertex
vertex.x = radius * Math.cos( segment );
vertex.y = radius * Math.sin( segment );
vertices.push( vertex.x, vertex.y, vertex.z );
// normal
normals.push( 0, 0, 1 );
// uv
uv.x = ( vertex.x / outerRadius + 1 ) / 2;
uv.y = ( vertex.y / outerRadius + 1 ) / 2;
uvs.push( uv.x, uv.y );
}
// increase the radius for next row of vertices
radius += radiusStep;
}
// indices
for ( j = 0; j < phiSegments; j ++ ) {
var thetaSegmentLevel = j * ( thetaSegments + 1 );
for ( i = 0; i < thetaSegments; i ++ ) {
segment = i + thetaSegmentLevel;
var a = segment;
var b = segment + thetaSegments + 1;
var c = segment + thetaSegments + 2;
var d = segment + 1;
// faces
indices.push( a, b, d );
indices.push( b, c, d );
}
}
// build geometry
this.setIndex( indices );
this.addAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) );
this.addAttribute( 'normal', new Float32BufferAttribute( normals, 3 ) );
this.addAttribute( 'uv', new Float32BufferAttribute( uvs, 2 ) );
}
RingBufferGeometry.prototype = Object.create( BufferGeometry.prototype );
RingBufferGeometry.prototype.constructor = RingBufferGeometry;
export { RingGeometry, RingBufferGeometry };

View File

@ -0,0 +1,222 @@
/**
* @author jonobr1 / http://jonobr1.com
* @author Mugen87 / https://github.com/Mugen87
*/
import { Geometry } from '../core/Geometry.js';
import { BufferGeometry } from '../core/BufferGeometry.js';
import { Float32BufferAttribute } from '../core/BufferAttribute.js';
import { ShapeUtils } from '../extras/ShapeUtils.js';
// ShapeGeometry
function ShapeGeometry( shapes, curveSegments ) {
Geometry.call( this );
this.type = 'ShapeGeometry';
if ( typeof curveSegments === 'object' ) {
console.warn( 'THREE.ShapeGeometry: Options parameter has been removed.' );
curveSegments = curveSegments.curveSegments;
}
this.parameters = {
shapes: shapes,
curveSegments: curveSegments
};
this.fromBufferGeometry( new ShapeBufferGeometry( shapes, curveSegments ) );
this.mergeVertices();
}
ShapeGeometry.prototype = Object.create( Geometry.prototype );
ShapeGeometry.prototype.constructor = ShapeGeometry;
ShapeGeometry.prototype.toJSON = function () {
var data = Geometry.prototype.toJSON.call( this );
var shapes = this.parameters.shapes;
return toJSON( shapes, data );
};
// ShapeBufferGeometry
function ShapeBufferGeometry( shapes, curveSegments ) {
BufferGeometry.call( this );
this.type = 'ShapeBufferGeometry';
this.parameters = {
shapes: shapes,
curveSegments: curveSegments
};
curveSegments = curveSegments || 12;
// buffers
var indices = [];
var vertices = [];
var normals = [];
var uvs = [];
// helper variables
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 );
this.addAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) );
this.addAttribute( 'normal', new Float32BufferAttribute( normals, 3 ) );
this.addAttribute( 'uv', new Float32BufferAttribute( 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;
ShapeBufferGeometry.prototype.toJSON = function () {
var data = BufferGeometry.prototype.toJSON.call( this );
var shapes = this.parameters.shapes;
return toJSON( shapes, data );
};
//
function toJSON( shapes, data ) {
data.shapes = [];
if ( Array.isArray( shapes ) ) {
for ( var i = 0, l = shapes.length; i < l; i ++ ) {
var shape = shapes[ i ];
data.shapes.push( shape.uuid );
}
} else {
data.shapes.push( shapes.uuid );
}
return data;
}
export { ShapeGeometry, ShapeBufferGeometry };

View File

@ -0,0 +1,152 @@
/**
* @author mrdoob / http://mrdoob.com/
* @author benaadams / https://twitter.com/ben_a_adams
* @author Mugen87 / https://github.com/Mugen87
*/
import { Geometry } from '../core/Geometry.js';
import { BufferGeometry } from '../core/BufferGeometry.js';
import { Float32BufferAttribute } from '../core/BufferAttribute.js';
import { Vector3 } from '../math/Vector3.js';
// SphereGeometry
function SphereGeometry( radius, widthSegments, heightSegments, phiStart, phiLength, thetaStart, thetaLength ) {
Geometry.call( this );
this.type = 'SphereGeometry';
this.parameters = {
radius: radius,
widthSegments: widthSegments,
heightSegments: heightSegments,
phiStart: phiStart,
phiLength: phiLength,
thetaStart: thetaStart,
thetaLength: thetaLength
};
this.fromBufferGeometry( new SphereBufferGeometry( radius, widthSegments, heightSegments, phiStart, phiLength, thetaStart, thetaLength ) );
this.mergeVertices();
}
SphereGeometry.prototype = Object.create( Geometry.prototype );
SphereGeometry.prototype.constructor = SphereGeometry;
// SphereBufferGeometry
function SphereBufferGeometry( radius, widthSegments, heightSegments, phiStart, phiLength, thetaStart, thetaLength ) {
BufferGeometry.call( this );
this.type = 'SphereBufferGeometry';
this.parameters = {
radius: radius,
widthSegments: widthSegments,
heightSegments: heightSegments,
phiStart: phiStart,
phiLength: phiLength,
thetaStart: thetaStart,
thetaLength: thetaLength
};
radius = radius || 1;
widthSegments = Math.max( 3, Math.floor( widthSegments ) || 8 );
heightSegments = Math.max( 2, Math.floor( heightSegments ) || 6 );
phiStart = phiStart !== undefined ? phiStart : 0;
phiLength = phiLength !== undefined ? phiLength : Math.PI * 2;
thetaStart = thetaStart !== undefined ? thetaStart : 0;
thetaLength = thetaLength !== undefined ? thetaLength : Math.PI;
var thetaEnd = thetaStart + thetaLength;
var ix, iy;
var index = 0;
var grid = [];
var vertex = new Vector3();
var normal = new Vector3();
// buffers
var indices = [];
var vertices = [];
var normals = [];
var uvs = [];
// generate vertices, normals and uvs
for ( iy = 0; iy <= heightSegments; iy ++ ) {
var verticesRow = [];
var v = iy / heightSegments;
for ( ix = 0; ix <= widthSegments; ix ++ ) {
var u = ix / widthSegments;
// vertex
vertex.x = - radius * Math.cos( phiStart + u * phiLength ) * Math.sin( thetaStart + v * thetaLength );
vertex.y = radius * Math.cos( thetaStart + v * thetaLength );
vertex.z = radius * Math.sin( phiStart + u * phiLength ) * Math.sin( thetaStart + v * thetaLength );
vertices.push( vertex.x, vertex.y, vertex.z );
// normal
normal.set( vertex.x, vertex.y, vertex.z ).normalize();
normals.push( normal.x, normal.y, normal.z );
// uv
uvs.push( u, 1 - v );
verticesRow.push( index ++ );
}
grid.push( verticesRow );
}
// indices
for ( iy = 0; iy < heightSegments; iy ++ ) {
for ( ix = 0; ix < widthSegments; ix ++ ) {
var a = grid[ iy ][ ix + 1 ];
var b = grid[ iy ][ ix ];
var c = grid[ iy + 1 ][ ix ];
var d = grid[ iy + 1 ][ ix + 1 ];
if ( iy !== 0 || thetaStart > 0 ) indices.push( a, b, d );
if ( iy !== heightSegments - 1 || thetaEnd < Math.PI ) indices.push( b, c, d );
}
}
// build geometry
this.setIndex( indices );
this.addAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) );
this.addAttribute( 'normal', new Float32BufferAttribute( normals, 3 ) );
this.addAttribute( 'uv', new Float32BufferAttribute( uvs, 2 ) );
}
SphereBufferGeometry.prototype = Object.create( BufferGeometry.prototype );
SphereBufferGeometry.prototype.constructor = SphereBufferGeometry;
export { SphereGeometry, SphereBufferGeometry };

View File

@ -0,0 +1,57 @@
/**
* @author timothypratley / https://github.com/timothypratley
* @author Mugen87 / https://github.com/Mugen87
*/
import { Geometry } from '../core/Geometry.js';
import { PolyhedronBufferGeometry } from './PolyhedronGeometry.js';
// TetrahedronGeometry
function TetrahedronGeometry( radius, detail ) {
Geometry.call( this );
this.type = 'TetrahedronGeometry';
this.parameters = {
radius: radius,
detail: detail
};
this.fromBufferGeometry( new TetrahedronBufferGeometry( radius, detail ) );
this.mergeVertices();
}
TetrahedronGeometry.prototype = Object.create( Geometry.prototype );
TetrahedronGeometry.prototype.constructor = TetrahedronGeometry;
// TetrahedronBufferGeometry
function TetrahedronBufferGeometry( radius, detail ) {
var vertices = [
1, 1, 1, - 1, - 1, 1, - 1, 1, - 1, 1, - 1, - 1
];
var indices = [
2, 1, 0, 0, 3, 2, 1, 3, 0, 2, 3, 1
];
PolyhedronBufferGeometry.call( this, vertices, indices, radius, detail );
this.type = 'TetrahedronBufferGeometry';
this.parameters = {
radius: radius,
detail: detail
};
}
TetrahedronBufferGeometry.prototype = Object.create( PolyhedronBufferGeometry.prototype );
TetrahedronBufferGeometry.prototype.constructor = TetrahedronBufferGeometry;
export { TetrahedronGeometry, TetrahedronBufferGeometry };

View File

@ -0,0 +1,81 @@
/**
* @author zz85 / http://www.lab4games.net/zz85/blog
* @author alteredq / http://alteredqualia.com/
*
* Text = 3D Text
*
* parameters = {
* font: <THREE.Font>, // font
*
* size: <float>, // size of the text
* height: <float>, // thickness to extrude text
* curveSegments: <int>, // number of points on the curves
*
* bevelEnabled: <bool>, // turn on bevel
* bevelThickness: <float>, // how deep into text bevel goes
* bevelSize: <float> // how far from text outline is bevel
* }
*/
import { Geometry } from '../core/Geometry.js';
import { ExtrudeBufferGeometry } from './ExtrudeGeometry.js';
// TextGeometry
function TextGeometry( text, parameters ) {
Geometry.call( this );
this.type = 'TextGeometry';
this.parameters = {
text: text,
parameters: parameters
};
this.fromBufferGeometry( new TextBufferGeometry( text, parameters ) );
this.mergeVertices();
}
TextGeometry.prototype = Object.create( Geometry.prototype );
TextGeometry.prototype.constructor = TextGeometry;
// TextBufferGeometry
function TextBufferGeometry( text, parameters ) {
parameters = parameters || {};
var font = parameters.font;
if ( ! ( font && font.isFont ) ) {
console.error( 'THREE.TextGeometry: font parameter is not an instance of THREE.Font.' );
return new Geometry();
}
var shapes = font.generateShapes( text, parameters.size );
// translate parameters to ExtrudeGeometry API
parameters.depth = parameters.height !== undefined ? parameters.height : 50;
// defaults
if ( parameters.bevelThickness === undefined ) parameters.bevelThickness = 10;
if ( parameters.bevelSize === undefined ) parameters.bevelSize = 8;
if ( parameters.bevelEnabled === undefined ) parameters.bevelEnabled = false;
ExtrudeBufferGeometry.call( this, shapes, parameters );
this.type = 'TextBufferGeometry';
}
TextBufferGeometry.prototype = Object.create( ExtrudeBufferGeometry.prototype );
TextBufferGeometry.prototype.constructor = TextBufferGeometry;
export { TextGeometry, TextBufferGeometry };

View File

@ -0,0 +1,142 @@
/**
* @author oosmoxiecode
* @author mrdoob / http://mrdoob.com/
* @author Mugen87 / https://github.com/Mugen87
*/
import { Geometry } from '../core/Geometry.js';
import { BufferGeometry } from '../core/BufferGeometry.js';
import { Float32BufferAttribute } from '../core/BufferAttribute.js';
import { Vector3 } from '../math/Vector3.js';
// TorusGeometry
function TorusGeometry( radius, tube, radialSegments, tubularSegments, arc ) {
Geometry.call( this );
this.type = 'TorusGeometry';
this.parameters = {
radius: radius,
tube: tube,
radialSegments: radialSegments,
tubularSegments: tubularSegments,
arc: arc
};
this.fromBufferGeometry( new TorusBufferGeometry( radius, tube, radialSegments, tubularSegments, arc ) );
this.mergeVertices();
}
TorusGeometry.prototype = Object.create( Geometry.prototype );
TorusGeometry.prototype.constructor = TorusGeometry;
// TorusBufferGeometry
function TorusBufferGeometry( radius, tube, radialSegments, tubularSegments, arc ) {
BufferGeometry.call( this );
this.type = 'TorusBufferGeometry';
this.parameters = {
radius: radius,
tube: tube,
radialSegments: radialSegments,
tubularSegments: tubularSegments,
arc: arc
};
radius = radius || 1;
tube = tube || 0.4;
radialSegments = Math.floor( radialSegments ) || 8;
tubularSegments = Math.floor( tubularSegments ) || 6;
arc = arc || Math.PI * 2;
// buffers
var indices = [];
var vertices = [];
var normals = [];
var uvs = [];
// helper variables
var center = new Vector3();
var vertex = new Vector3();
var normal = new Vector3();
var j, i;
// generate vertices, normals and uvs
for ( j = 0; j <= radialSegments; j ++ ) {
for ( i = 0; i <= tubularSegments; i ++ ) {
var u = i / tubularSegments * arc;
var v = j / radialSegments * Math.PI * 2;
// vertex
vertex.x = ( radius + tube * Math.cos( v ) ) * Math.cos( u );
vertex.y = ( radius + tube * Math.cos( v ) ) * Math.sin( u );
vertex.z = tube * Math.sin( v );
vertices.push( vertex.x, vertex.y, vertex.z );
// normal
center.x = radius * Math.cos( u );
center.y = radius * Math.sin( u );
normal.subVectors( vertex, center ).normalize();
normals.push( normal.x, normal.y, normal.z );
// uv
uvs.push( i / tubularSegments );
uvs.push( j / radialSegments );
}
}
// generate indices
for ( j = 1; j <= radialSegments; j ++ ) {
for ( i = 1; i <= tubularSegments; i ++ ) {
// indices
var a = ( tubularSegments + 1 ) * j + i - 1;
var b = ( tubularSegments + 1 ) * ( j - 1 ) + i - 1;
var c = ( tubularSegments + 1 ) * ( j - 1 ) + i;
var d = ( tubularSegments + 1 ) * j + i;
// faces
indices.push( a, b, d );
indices.push( b, c, d );
}
}
// build geometry
this.setIndex( indices );
this.addAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) );
this.addAttribute( 'normal', new Float32BufferAttribute( normals, 3 ) );
this.addAttribute( 'uv', new Float32BufferAttribute( uvs, 2 ) );
}
TorusBufferGeometry.prototype = Object.create( BufferGeometry.prototype );
TorusBufferGeometry.prototype.constructor = TorusBufferGeometry;
export { TorusGeometry, TorusBufferGeometry };

View File

@ -0,0 +1,194 @@
/**
* @author oosmoxiecode
* @author Mugen87 / https://github.com/Mugen87
*
* based on http://www.blackpawn.com/texts/pqtorus/
*/
import { Geometry } from '../core/Geometry.js';
import { BufferGeometry } from '../core/BufferGeometry.js';
import { Float32BufferAttribute } from '../core/BufferAttribute.js';
import { Vector3 } from '../math/Vector3.js';
// TorusKnotGeometry
function TorusKnotGeometry( radius, tube, tubularSegments, radialSegments, p, q, heightScale ) {
Geometry.call( this );
this.type = 'TorusKnotGeometry';
this.parameters = {
radius: radius,
tube: tube,
tubularSegments: tubularSegments,
radialSegments: radialSegments,
p: p,
q: q
};
if ( heightScale !== undefined ) console.warn( 'THREE.TorusKnotGeometry: heightScale has been deprecated. Use .scale( x, y, z ) instead.' );
this.fromBufferGeometry( new TorusKnotBufferGeometry( radius, tube, tubularSegments, radialSegments, p, q ) );
this.mergeVertices();
}
TorusKnotGeometry.prototype = Object.create( Geometry.prototype );
TorusKnotGeometry.prototype.constructor = TorusKnotGeometry;
// TorusKnotBufferGeometry
function TorusKnotBufferGeometry( radius, tube, tubularSegments, radialSegments, p, q ) {
BufferGeometry.call( this );
this.type = 'TorusKnotBufferGeometry';
this.parameters = {
radius: radius,
tube: tube,
tubularSegments: tubularSegments,
radialSegments: radialSegments,
p: p,
q: q
};
radius = radius || 1;
tube = tube || 0.4;
tubularSegments = Math.floor( tubularSegments ) || 64;
radialSegments = Math.floor( radialSegments ) || 8;
p = p || 2;
q = q || 3;
// buffers
var indices = [];
var vertices = [];
var normals = [];
var uvs = [];
// helper variables
var i, j;
var vertex = new Vector3();
var normal = new Vector3();
var P1 = new Vector3();
var P2 = new Vector3();
var B = new Vector3();
var T = new Vector3();
var N = new Vector3();
// generate vertices, normals and uvs
for ( i = 0; i <= tubularSegments; ++ i ) {
// the radian "u" is used to calculate the position on the torus curve of the current tubular segement
var u = i / tubularSegments * p * Math.PI * 2;
// now we calculate two points. P1 is our current position on the curve, P2 is a little farther ahead.
// these points are used to create a special "coordinate space", which is necessary to calculate the correct vertex positions
calculatePositionOnCurve( u, p, q, radius, P1 );
calculatePositionOnCurve( u + 0.01, p, q, radius, P2 );
// calculate orthonormal basis
T.subVectors( P2, P1 );
N.addVectors( P2, P1 );
B.crossVectors( T, N );
N.crossVectors( B, T );
// normalize B, N. T can be ignored, we don't use it
B.normalize();
N.normalize();
for ( j = 0; j <= radialSegments; ++ j ) {
// now calculate the vertices. they are nothing more than an extrusion of the torus curve.
// because we extrude a shape in the xy-plane, there is no need to calculate a z-value.
var v = j / radialSegments * Math.PI * 2;
var cx = - tube * Math.cos( v );
var cy = tube * Math.sin( v );
// now calculate the final vertex position.
// first we orient the extrusion with our basis vectos, then we add it to the current position on the curve
vertex.x = P1.x + ( cx * N.x + cy * B.x );
vertex.y = P1.y + ( cx * N.y + cy * B.y );
vertex.z = P1.z + ( cx * N.z + cy * B.z );
vertices.push( vertex.x, vertex.y, vertex.z );
// normal (P1 is always the center/origin of the extrusion, thus we can use it to calculate the normal)
normal.subVectors( vertex, P1 ).normalize();
normals.push( normal.x, normal.y, normal.z );
// uv
uvs.push( i / tubularSegments );
uvs.push( j / radialSegments );
}
}
// generate indices
for ( j = 1; j <= tubularSegments; j ++ ) {
for ( i = 1; i <= radialSegments; i ++ ) {
// indices
var a = ( radialSegments + 1 ) * ( j - 1 ) + ( i - 1 );
var b = ( radialSegments + 1 ) * j + ( i - 1 );
var c = ( radialSegments + 1 ) * j + i;
var d = ( radialSegments + 1 ) * ( j - 1 ) + i;
// faces
indices.push( a, b, d );
indices.push( b, c, d );
}
}
// build geometry
this.setIndex( indices );
this.addAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) );
this.addAttribute( 'normal', new Float32BufferAttribute( normals, 3 ) );
this.addAttribute( 'uv', new Float32BufferAttribute( uvs, 2 ) );
// this function calculates the current position on the torus curve
function calculatePositionOnCurve( u, p, q, radius, position ) {
var cu = Math.cos( u );
var su = Math.sin( u );
var quOverP = q / p * u;
var cs = Math.cos( quOverP );
position.x = radius * ( 2 + cs ) * 0.5 * cu;
position.y = radius * ( 2 + cs ) * su * 0.5;
position.z = radius * Math.sin( quOverP ) * 0.5;
}
}
TorusKnotBufferGeometry.prototype = Object.create( BufferGeometry.prototype );
TorusKnotBufferGeometry.prototype.constructor = TorusKnotBufferGeometry;
export { TorusKnotGeometry, TorusKnotBufferGeometry };

View File

@ -0,0 +1,223 @@
/**
* @author oosmoxiecode / https://github.com/oosmoxiecode
* @author WestLangley / https://github.com/WestLangley
* @author zz85 / https://github.com/zz85
* @author miningold / https://github.com/miningold
* @author jonobr1 / https://github.com/jonobr1
* @author Mugen87 / https://github.com/Mugen87
*
*/
import { Geometry } from '../core/Geometry.js';
import { BufferGeometry } from '../core/BufferGeometry.js';
import { Float32BufferAttribute } from '../core/BufferAttribute.js';
import { Vector2 } from '../math/Vector2.js';
import { Vector3 } from '../math/Vector3.js';
// TubeGeometry
function TubeGeometry( path, tubularSegments, radius, radialSegments, closed, taper ) {
Geometry.call( this );
this.type = 'TubeGeometry';
this.parameters = {
path: path,
tubularSegments: tubularSegments,
radius: radius,
radialSegments: radialSegments,
closed: closed
};
if ( taper !== undefined ) console.warn( 'THREE.TubeGeometry: taper has been removed.' );
var bufferGeometry = new TubeBufferGeometry( path, tubularSegments, radius, radialSegments, closed );
// expose internals
this.tangents = bufferGeometry.tangents;
this.normals = bufferGeometry.normals;
this.binormals = bufferGeometry.binormals;
// create geometry
this.fromBufferGeometry( bufferGeometry );
this.mergeVertices();
}
TubeGeometry.prototype = Object.create( Geometry.prototype );
TubeGeometry.prototype.constructor = TubeGeometry;
// TubeBufferGeometry
function TubeBufferGeometry( path, tubularSegments, radius, radialSegments, closed ) {
BufferGeometry.call( this );
this.type = 'TubeBufferGeometry';
this.parameters = {
path: path,
tubularSegments: tubularSegments,
radius: radius,
radialSegments: radialSegments,
closed: closed
};
tubularSegments = tubularSegments || 64;
radius = radius || 1;
radialSegments = radialSegments || 8;
closed = closed || false;
var frames = path.computeFrenetFrames( tubularSegments, closed );
// expose internals
this.tangents = frames.tangents;
this.normals = frames.normals;
this.binormals = frames.binormals;
// helper variables
var vertex = new Vector3();
var normal = new Vector3();
var uv = new Vector2();
var P = new Vector3();
var i, j;
// buffer
var vertices = [];
var normals = [];
var uvs = [];
var indices = [];
// create buffer data
generateBufferData();
// build geometry
this.setIndex( indices );
this.addAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) );
this.addAttribute( 'normal', new Float32BufferAttribute( normals, 3 ) );
this.addAttribute( 'uv', new Float32BufferAttribute( uvs, 2 ) );
// functions
function generateBufferData() {
for ( i = 0; i < tubularSegments; i ++ ) {
generateSegment( i );
}
// if the geometry is not closed, generate the last row of vertices and normals
// at the regular position on the given path
//
// if the geometry is closed, duplicate the first row of vertices and normals (uvs will differ)
generateSegment( ( closed === false ) ? tubularSegments : 0 );
// uvs are generated in a separate function.
// this makes it easy compute correct values for closed geometries
generateUVs();
// finally create faces
generateIndices();
}
function generateSegment( i ) {
// we use getPointAt to sample evenly distributed points from the given path
P = path.getPointAt( i / tubularSegments, P );
// retrieve corresponding normal and binormal
var N = frames.normals[ i ];
var B = frames.binormals[ i ];
// generate normals and vertices for the current segment
for ( j = 0; j <= radialSegments; j ++ ) {
var v = j / radialSegments * Math.PI * 2;
var sin = Math.sin( v );
var cos = - Math.cos( v );
// normal
normal.x = ( cos * N.x + sin * B.x );
normal.y = ( cos * N.y + sin * B.y );
normal.z = ( cos * N.z + sin * B.z );
normal.normalize();
normals.push( normal.x, normal.y, normal.z );
// vertex
vertex.x = P.x + radius * normal.x;
vertex.y = P.y + radius * normal.y;
vertex.z = P.z + radius * normal.z;
vertices.push( vertex.x, vertex.y, vertex.z );
}
}
function generateIndices() {
for ( j = 1; j <= tubularSegments; j ++ ) {
for ( i = 1; i <= radialSegments; i ++ ) {
var a = ( radialSegments + 1 ) * ( j - 1 ) + ( i - 1 );
var b = ( radialSegments + 1 ) * j + ( i - 1 );
var c = ( radialSegments + 1 ) * j + i;
var d = ( radialSegments + 1 ) * ( j - 1 ) + i;
// faces
indices.push( a, b, d );
indices.push( b, c, d );
}
}
}
function generateUVs() {
for ( i = 0; i <= tubularSegments; i ++ ) {
for ( j = 0; j <= radialSegments; j ++ ) {
uv.x = i / tubularSegments;
uv.y = j / radialSegments;
uvs.push( uv.x, uv.y );
}
}
}
}
TubeBufferGeometry.prototype = Object.create( BufferGeometry.prototype );
TubeBufferGeometry.prototype.constructor = TubeBufferGeometry;
export { TubeGeometry, TubeBufferGeometry };

View File

@ -0,0 +1,179 @@
/**
* @author mrdoob / http://mrdoob.com/
* @author Mugen87 / https://github.com/Mugen87
*/
import { BufferGeometry } from '../core/BufferGeometry.js';
import { Float32BufferAttribute } from '../core/BufferAttribute.js';
import { Vector3 } from '../math/Vector3.js';
function WireframeGeometry( geometry ) {
BufferGeometry.call( this );
this.type = 'WireframeGeometry';
// buffer
var vertices = [];
// helper variables
var i, j, l, o, ol;
var edge = [ 0, 0 ], edges = {}, e, edge1, edge2;
var key, keys = [ 'a', 'b', 'c' ];
var vertex;
// different logic for Geometry and BufferGeometry
if ( geometry && geometry.isGeometry ) {
// create a data structure that contains all edges without duplicates
var faces = geometry.faces;
for ( i = 0, l = faces.length; i < l; i ++ ) {
var face = faces[ i ];
for ( j = 0; j < 3; j ++ ) {
edge1 = face[ keys[ j ] ];
edge2 = face[ keys[ ( j + 1 ) % 3 ] ];
edge[ 0 ] = Math.min( edge1, edge2 ); // sorting prevents duplicates
edge[ 1 ] = Math.max( edge1, edge2 );
key = edge[ 0 ] + ',' + edge[ 1 ];
if ( edges[ key ] === undefined ) {
edges[ key ] = { index1: edge[ 0 ], index2: edge[ 1 ] };
}
}
}
// generate vertices
for ( key in edges ) {
e = edges[ key ];
vertex = geometry.vertices[ e.index1 ];
vertices.push( vertex.x, vertex.y, vertex.z );
vertex = geometry.vertices[ e.index2 ];
vertices.push( vertex.x, vertex.y, vertex.z );
}
} else if ( geometry && geometry.isBufferGeometry ) {
var position, indices, groups;
var group, start, count;
var index1, index2;
vertex = new Vector3();
if ( geometry.index !== null ) {
// indexed BufferGeometry
position = geometry.attributes.position;
indices = geometry.index;
groups = geometry.groups;
if ( groups.length === 0 ) {
groups = [ { start: 0, count: indices.count, materialIndex: 0 } ];
}
// create a data structure that contains all eges without duplicates
for ( o = 0, ol = groups.length; o < ol; ++ o ) {
group = groups[ o ];
start = group.start;
count = group.count;
for ( i = start, l = ( start + count ); i < l; i += 3 ) {
for ( j = 0; j < 3; j ++ ) {
edge1 = indices.getX( i + j );
edge2 = indices.getX( i + ( j + 1 ) % 3 );
edge[ 0 ] = Math.min( edge1, edge2 ); // sorting prevents duplicates
edge[ 1 ] = Math.max( edge1, edge2 );
key = edge[ 0 ] + ',' + edge[ 1 ];
if ( edges[ key ] === undefined ) {
edges[ key ] = { index1: edge[ 0 ], index2: edge[ 1 ] };
}
}
}
}
// generate vertices
for ( key in edges ) {
e = edges[ key ];
vertex.fromBufferAttribute( position, e.index1 );
vertices.push( vertex.x, vertex.y, vertex.z );
vertex.fromBufferAttribute( position, e.index2 );
vertices.push( vertex.x, vertex.y, vertex.z );
}
} else {
// non-indexed BufferGeometry
position = geometry.attributes.position;
for ( i = 0, l = ( position.count / 3 ); i < l; i ++ ) {
for ( j = 0; j < 3; j ++ ) {
// three edges per triangle, an edge is represented as (index1, index2)
// e.g. the first triangle has the following edges: (0,1),(1,2),(2,0)
index1 = 3 * i + j;
vertex.fromBufferAttribute( position, index1 );
vertices.push( vertex.x, vertex.y, vertex.z );
index2 = 3 * i + ( ( j + 1 ) % 3 );
vertex.fromBufferAttribute( position, index2 );
vertices.push( vertex.x, vertex.y, vertex.z );
}
}
}
}
// build geometry
this.addAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) );
}
WireframeGeometry.prototype = Object.create( BufferGeometry.prototype );
WireframeGeometry.prototype.constructor = WireframeGeometry;
export { WireframeGeometry };