Geometries

Frenet Frame & Dir Tube

In three.js, Frenet Frame is used for generating TubeGeometry.

To generate a tube, the TubeGeomerty calling Curve.computeFrenetFrames() to create parallel curves, then build mesh points with indecis.

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.setAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) );
    this.setAttribute( 'normal', new Float32BufferAttribute( normals, 3 ) );
    this.setAttribute( 'uv', new Float32BufferAttribute( uvs, 2 ) );

    function generateBufferData() {
        for ( i = 0; i < tubularSegments; i ++ ) {
            generateSegment( i );
        }
        generateSegment( ( closed === false ) ? tubularSegments : 0 );
        generateUVs();
        generateIndices();
    }
}

The Three.js Curve.computeFrenetFrames() is a key function to implement tube geometry generation. Which use an other method to generate frames’ tangents:

for ( i = 0; i <= segments; i ++ ) {
    u = i / segments;
    tangents[ i ] = this.getTangentAt( u, new Vector3() );
    tangents[ i ].normalize();
}

getTangentAt: function ( u, optionalTarget ) {
    var t = this.getUtoTmapping( u );
    return this.getTangent( t, optionalTarget );
},

getUtoTmapping: function ( u, distance ) {
    ...
    var segmentFraction = ( targetArcLength - lengthBefore ) / segmentLength;
    var t = ( i + segmentFraction ) / ( il - 1 );
    return t;
},

The problem of this is that it dosn’t follow the THREE.CatmullRomCurve3 curve. See a DirTubeGeometry test resulsts. It could be optimized.

DirTubeGeometry of x-visual

TODO ...

see xmath/geom.js/computeFrenetFrames

Reference

  1. Three.js class: TubeGeometry docs & src.
  2. Three.js class: Curve.
  3. Andrew J. Hanson and Hui Ma, *Parallel Transport Approach to Curve Framing*, Department of Computer Science, Indiana University.
  4. *Frenet–Serret formulas*, wikipedia