📄 TubeGeometry.js
¶
📊 Analysis Summary¶
Metric | Count |
---|---|
🔧 Functions | 7 |
🧱 Classes | 1 |
📦 Imports | 4 |
📊 Variables & Constants | 16 |
📚 Table of Contents¶
🛠️ File Location:¶
📂 src/geometries/TubeGeometry.js
📦 Imports¶
Name | Source |
---|---|
BufferGeometry |
../core/BufferGeometry.js |
Float32BufferAttribute |
../core/BufferAttribute.js |
Vector2 |
../math/Vector2.js |
Vector3 |
../math/Vector3.js |
Variables & Constants¶
Name | Type | Kind | Value | Exported |
---|---|---|---|---|
vertex |
Vector3 |
let/var | new Vector3() |
✗ |
normal |
Vector3 |
let/var | new Vector3() |
✗ |
uv |
Vector2 |
let/var | new Vector2() |
✗ |
P |
Vector3 |
let/var | new Vector3() |
✗ |
vertices |
any[] |
let/var | [] |
✗ |
normals |
any[] |
let/var | [] |
✗ |
uvs |
any[] |
let/var | [] |
✗ |
indices |
any[] |
let/var | [] |
✗ |
N |
any |
let/var | frames.normals[ i ] |
✗ |
B |
any |
let/var | frames.binormals[ i ] |
✗ |
v |
number |
let/var | j / radialSegments * Math.PI * 2 |
✗ |
cos |
number |
let/var | - Math.cos( v ) |
✗ |
a |
number |
let/var | ( radialSegments + 1 ) * ( j - 1 ) + ( i - 1 ) |
✗ |
b |
number |
let/var | ( radialSegments + 1 ) * j + ( i - 1 ) |
✗ |
c |
number |
let/var | ( radialSegments + 1 ) * j + i |
✗ |
d |
number |
let/var | ( radialSegments + 1 ) * ( j - 1 ) + i |
✗ |
Functions¶
TubeGeometry.copy(source: any): this
¶
Parameters:
source
any
Returns: this
Calls:
super.copy
Object.assign
Code
TubeGeometry.toJSON(): any
¶
Returns: any
Calls:
super.toJSON
this.parameters.path.toJSON
Code
TubeGeometry.fromJSON(data: any): TubeGeometry
¶
JSDoc:
/**
* Factory method for creating an instance of this class from the given
* JSON object.
*
* @param {Object} data - A JSON object representing the serialized geometry.
* @return {TubeGeometry} A new instance.
*/
Parameters:
data
any
Returns: TubeGeometry
Calls:
new Curves[ data.path.type ]().fromJSON
Internal Comments:
// This only works for built-in curves (e.g. CatmullRomCurve3).
// User defined curves or instances of CurvePath will not be deserialized.
Code
static fromJSON( data ) {
// This only works for built-in curves (e.g. CatmullRomCurve3).
// User defined curves or instances of CurvePath will not be deserialized.
return new TubeGeometry(
new Curves[ data.path.type ]().fromJSON( data.path ),
data.tubularSegments,
data.radius,
data.radialSegments,
data.closed
);
}
generateBufferData(): void
¶
Returns: void
Calls:
generateSegment
generateUVs
generateIndices
Internal Comments:
// if the geometry is not closed, generate the last row of vertices and normals (x3)
// at the regular position on the given path (x3)
// (x3)
// if the geometry is closed, duplicate the first row of vertices and normals (uvs will differ) (x3)
// uvs are generated in a separate function. (x3)
// this makes it easy compute correct values for closed geometries (x3)
// finally create faces (x3)
Code
function generateBufferData() {
for ( let 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();
}
generateSegment(i: any): void
¶
Parameters:
i
any
Returns: void
Calls:
path.getPointAt
Math.sin
Math.cos
normal.normalize
normals.push
vertices.push
Internal Comments:
// we use getPointAt to sample evenly distributed points from the given path (x3)
// retrieve corresponding normal and binormal (x2)
// generate normals and vertices for the current segment
// normal (x4)
// vertex (x4)
Code
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
const N = frames.normals[ i ];
const B = frames.binormals[ i ];
// generate normals and vertices for the current segment
for ( let j = 0; j <= radialSegments; j ++ ) {
const v = j / radialSegments * Math.PI * 2;
const sin = Math.sin( v );
const 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 );
}
}
generateIndices(): void
¶
Returns: void
Calls:
indices.push
Internal Comments:
Code
function generateIndices() {
for ( let j = 1; j <= tubularSegments; j ++ ) {
for ( let i = 1; i <= radialSegments; i ++ ) {
const a = ( radialSegments + 1 ) * ( j - 1 ) + ( i - 1 );
const b = ( radialSegments + 1 ) * j + ( i - 1 );
const c = ( radialSegments + 1 ) * j + i;
const d = ( radialSegments + 1 ) * ( j - 1 ) + i;
// faces
indices.push( a, b, d );
indices.push( b, c, d );
}
}
}
generateUVs(): void
¶
Returns: void
Calls:
uvs.push
Code
Classes¶
TubeGeometry
¶
Class Code
class TubeGeometry extends BufferGeometry {
/**
* Constructs a new tube geometry.
*
* @param {Curve} [path=QuadraticBezierCurve3] - A 3D curve defining the path of the tube.
* @param {number} [tubularSegments=64] - The number of segments that make up the tube.
* @param {number} [radius=1] -The radius of the tube.
* @param {number} [radialSegments=8] - The number of segments that make up the cross-section.
* @param {boolean} [closed=false] - Whether the tube is closed or not.
*/
constructor( path = new Curves[ 'QuadraticBezierCurve3' ]( new Vector3( - 1, - 1, 0 ), new Vector3( - 1, 1, 0 ), new Vector3( 1, 1, 0 ) ), tubularSegments = 64, radius = 1, radialSegments = 8, closed = false ) {
super();
this.type = 'TubeGeometry';
/**
* Holds the constructor parameters that have been
* used to generate the geometry. Any modification
* after instantiation does not change the geometry.
*
* @type {Object}
*/
this.parameters = {
path: path,
tubularSegments: tubularSegments,
radius: radius,
radialSegments: radialSegments,
closed: closed
};
const frames = path.computeFrenetFrames( tubularSegments, closed );
// expose internals
this.tangents = frames.tangents;
this.normals = frames.normals;
this.binormals = frames.binormals;
// helper variables
const vertex = new Vector3();
const normal = new Vector3();
const uv = new Vector2();
let P = new Vector3();
// buffer
const vertices = [];
const normals = [];
const uvs = [];
const indices = [];
// create buffer data
generateBufferData();
// build geometry
this.setIndex( indices );
this.setAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) );
this.setAttribute( 'normal', new Float32BufferAttribute( normals, 3 ) );
this.setAttribute( 'uv', new Float32BufferAttribute( uvs, 2 ) );
// functions
function generateBufferData() {
for ( let 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
const N = frames.normals[ i ];
const B = frames.binormals[ i ];
// generate normals and vertices for the current segment
for ( let j = 0; j <= radialSegments; j ++ ) {
const v = j / radialSegments * Math.PI * 2;
const sin = Math.sin( v );
const 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 ( let j = 1; j <= tubularSegments; j ++ ) {
for ( let i = 1; i <= radialSegments; i ++ ) {
const a = ( radialSegments + 1 ) * ( j - 1 ) + ( i - 1 );
const b = ( radialSegments + 1 ) * j + ( i - 1 );
const c = ( radialSegments + 1 ) * j + i;
const d = ( radialSegments + 1 ) * ( j - 1 ) + i;
// faces
indices.push( a, b, d );
indices.push( b, c, d );
}
}
}
function generateUVs() {
for ( let i = 0; i <= tubularSegments; i ++ ) {
for ( let j = 0; j <= radialSegments; j ++ ) {
uv.x = i / tubularSegments;
uv.y = j / radialSegments;
uvs.push( uv.x, uv.y );
}
}
}
}
copy( source ) {
super.copy( source );
this.parameters = Object.assign( {}, source.parameters );
return this;
}
toJSON() {
const data = super.toJSON();
data.path = this.parameters.path.toJSON();
return data;
}
/**
* Factory method for creating an instance of this class from the given
* JSON object.
*
* @param {Object} data - A JSON object representing the serialized geometry.
* @return {TubeGeometry} A new instance.
*/
static fromJSON( data ) {
// This only works for built-in curves (e.g. CatmullRomCurve3).
// User defined curves or instances of CurvePath will not be deserialized.
return new TubeGeometry(
new Curves[ data.path.type ]().fromJSON( data.path ),
data.tubularSegments,
data.radius,
data.radialSegments,
data.closed
);
}
}
Methods¶
copy(source: any): this
¶
Code
toJSON(): any
¶
Code
fromJSON(data: any): TubeGeometry
¶
Code
static fromJSON( data ) {
// This only works for built-in curves (e.g. CatmullRomCurve3).
// User defined curves or instances of CurvePath will not be deserialized.
return new TubeGeometry(
new Curves[ data.path.type ]().fromJSON( data.path ),
data.tubularSegments,
data.radius,
data.radialSegments,
data.closed
);
}