Spaces:
Running
Running
/** | |
* @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; | |
TubeBufferGeometry.prototype.toJSON = function () { | |
var data = BufferGeometry.prototype.toJSON.call( this ); | |
data.path = this.parameters.path.toJSON(); | |
return data; | |
}; | |
export { TubeGeometry, TubeBufferGeometry }; | |