商域無疆 (http://blog.csdn.net/omni360/)
本文遵循“署名-非商業用途-保持一致”創作公用協議
轉載請保留此句:商域無疆 - 本博客專注於 敏捷開發及移動和物聯設備研究:數據可視化、GOLANG、Html5、WEBGL、THREE.JS,否則,出自本博客的文章拒絕轉載或再轉載,謝謝合作。
俺也是剛開始學,好多地兒肯定不對還請見諒.
以下代碼是THREE.JS 源碼文件中extras/geometries/TubeGeometry.js文件的註釋.
更多更新在 : https://github.com/omni360/three.js.sourcecode
/**
* @author WestLangley / https://github.com/WestLangley
* @author zz85 / https://github.com/zz85
* @author miningold / https://github.com/miningold
*
* Modified from the TorusKnotGeometry by @oosmoxiecode
*
* Creates a tube which extrudes along a 3d spline
*
* Uses parallel transport frames as described in
* http://www.cs.indiana.edu/pub/techreports/TR425.pdf
*/
/*
///TubeGeometry用來在三維空間內創建一個彎管對象.
///
/// 用法:
/// var CustomSinCurve = THREE.Curve.create(
/// function ( scale ) { //custom curve constructor
/// this.scale = (scale === undefined) ? 1 : scale;
/// },
///
/// function ( t ) { //getPoint: t is between 0-1
/// var tx = t * 3 - 1.5,
/// ty = Math.sin( 2 * Math.PI * t ),
/// tz = 0;
///
/// return new THREE.Vector3(tx, ty, tz).multiplyScalar(this.scale);
/// }
/// );
///
/// var path = new CustomSinCurve( 10 );
///
/// var geometry = new THREE.TubeGeometry(
/// path, //path
/// 20, //segments
/// 2, //radius
/// 8, //radiusSegments
/// false //closed
/// );
*/
///<summary>TubeGeometry</summary>
///<param name ="path" type="THREE.Path">彎管的路徑</param>
///<param name ="segments" type="int">沿彎管路徑上的細分線段數,默認爲64</param>
///<param name ="radius" type="float">彎管的半徑,默認爲1</param>
///<param name ="radialSegments" type="int">彎管圓周方向上的細分線段數,默認爲8</param>
///<param name ="closed" type="boolean">是否連接起始點,結束點,true爲關閉.,默認爲false</param>
THREE.TubeGeometry = function ( path, segments, radius, radialSegments, closed ) {
THREE.Geometry.call( this ); //調用Geometry對象的call方法,將原本屬於Geometry的方法交給當前對象TubeGeometry來使用.
this.parameters = {
path: path, //彎管的路徑
segments: segments, //沿彎管路徑上的細分線段數,默認爲64
radius: radius, //彎管的半徑,默認爲1
radialSegments: radialSegments, //彎管圓周方向上的細分線段數,默認爲8
closed: closed //是否開口,如果設置爲true,彎管兩端沒有封頭,默認爲false
};
segments = segments || 64; //沿彎管路徑上的細分線段數,默認爲64
radius = radius || 1; //彎管的半徑,默認爲1
radialSegments = radialSegments || 8; //彎管圓周方向上的細分線段數,默認爲8
closed = closed || false; //是否連接起始點,結束點,true爲關閉.,默認爲false
var grid = [];
var scope = this,
tangent,
normal,
binormal,
numpoints = segments + 1,
x, y, z,
tx, ty, tz,
u, v,
cx, cy,
pos, pos2 = new THREE.Vector3(),
i, j,
ip, jp,
a, b, c, d,
uva, uvb, uvc, uvd;
var frames = new THREE.TubeGeometry.FrenetFrames( path, segments, closed ), //調用THREE.TubeGeometry.FrenetFrames()方法,計算弗萊納框架,得到路徑的切線,法線,副法線
tangents = frames.tangents,
normals = frames.normals,
binormals = frames.binormals;
// proxy internals
// 內部代理
this.tangents = tangents;
this.normals = normals;
this.binormals = binormals;
/*
///vert方法將x,y,z三個分量壓入圓管的頂點數組.
*/
///<summary>vert</summary>
///<param name ="x" type="float">三維向量的x分量</param>
///<param name ="y" type="float">三維向量的y分量</param>
///<param name ="z" type="float">三維向量的z分量</param>
function vert( x, y, z ) {
return scope.vertices.push( new THREE.Vector3( x, y, z ) ) - 1;
}
// consruct the grid
//構建網格
for ( i = 0; i < numpoints; i ++ ) {
grid[ i ] = [];
u = i / ( numpoints - 1 );
pos = path.getPointAt( u );
tangent = tangents[ i ];
normal = normals[ i ];
binormal = binormals[ i ];
for ( j = 0; j < radialSegments; j ++ ) {
v = j / radialSegments * 2 * Math.PI;
cx = - radius * Math.cos( v ); // TODO: Hack: Negating it so it faces outside.
cy = radius * Math.sin( v );
pos2.copy( pos );
pos2.x += cx * normal.x + cy * binormal.x;
pos2.y += cx * normal.y + cy * binormal.y;
pos2.z += cx * normal.z + cy * binormal.z;
grid[ i ][ j ] = vert( pos2.x, pos2.y, pos2.z );
}
}
// construct the mesh
// 構建曲面
for ( i = 0; i < segments; i ++ ) {
for ( j = 0; j < radialSegments; j ++ ) {
ip = ( closed ) ? (i + 1) % segments : i + 1;
jp = (j + 1) % radialSegments;
a = grid[ i ][ j ]; // *** NOT NECESSARILY PLANAR ! ***
b = grid[ ip ][ j ];
c = grid[ ip ][ jp ];
d = grid[ i ][ jp ];
uva = new THREE.Vector2( i / segments, j / radialSegments );
uvb = new THREE.Vector2( ( i + 1 ) / segments, j / radialSegments );
uvc = new THREE.Vector2( ( i + 1 ) / segments, ( j + 1 ) / radialSegments );
uvd = new THREE.Vector2( i / segments, ( j + 1 ) / radialSegments );
this.faces.push( new THREE.Face3( a, b, d ) );
this.faceVertexUvs[ 0 ].push( [ uva, uvb, uvd ] );
this.faces.push( new THREE.Face3( b, c, d ) );
this.faceVertexUvs[ 0 ].push( [ uvb.clone(), uvc, uvd.clone() ] );
}
}
this.computeFaceNormals(); //計算面的法線
this.computeVertexNormals(); //計算頂點的法線
};
/*************************************************
****下面是TubeGeometry對象的方法屬性定義,繼承自Geometry對象.
**************************************************/
THREE.TubeGeometry.prototype = Object.create( THREE.Geometry.prototype );
/*
///FrenetFrames方法計算弗萊納框架,得到路徑的切線,法線,副法線.
*/
///<summary>FrenetFrames</summary>
///<param name ="path" type="THREE.Path">彎管的路徑</param>
///<param name ="segments" type="int">沿彎管路徑上的細分線段數,默認爲64</param>
///<param name ="closed" type="boolean">是否連接起始點,結束點,true爲關閉.,默認爲false</param>
// For computing of Frenet frames, exposing the tangents, normals and binormals the spline
// 計算弗萊納框架,得到路徑的切線,法線,副法線.
THREE.TubeGeometry.FrenetFrames = function ( path, segments, closed ) {
var tangent = new THREE.Vector3(),
normal = new THREE.Vector3(),
binormal = new THREE.Vector3(),
tangents = [],
normals = [],
binormals = [],
vec = new THREE.Vector3(),
mat = new THREE.Matrix4(),
numpoints = segments + 1,
theta,
epsilon = 0.0001,
smallest,
tx, ty, tz,
i, u, v;
// expose internals
this.tangents = tangents;
this.normals = normals;
this.binormals = binormals;
// compute the tangent vectors for each segment on the path
// 計算路徑上的每條細分線段的切線向量
for ( i = 0; i < numpoints; i ++ ) {
u = i / ( numpoints - 1 );
tangents[ i ] = path.getTangentAt( u );
tangents[ i ].normalize();
}
initialNormal3();
/*
function initialNormal1(lastBinormal) {
// fixed start binormal. Has dangers of 0 vectors
normals[ 0 ] = new THREE.Vector3();
binormals[ 0 ] = new THREE.Vector3();
if (lastBinormal===undefined) lastBinormal = new THREE.Vector3( 0, 0, 1 );
normals[ 0 ].crossVectors( lastBinormal, tangents[ 0 ] ).normalize();
binormals[ 0 ].crossVectors( tangents[ 0 ], normals[ 0 ] ).normalize();
}
function initialNormal2() {
// This uses the Frenet-Serret formula for deriving binormal
var t2 = path.getTangentAt( epsilon );
normals[ 0 ] = new THREE.Vector3().subVectors( t2, tangents[ 0 ] ).normalize();
binormals[ 0 ] = new THREE.Vector3().crossVectors( tangents[ 0 ], normals[ 0 ] );
normals[ 0 ].crossVectors( binormals[ 0 ], tangents[ 0 ] ).normalize(); // last binormal x tangent
binormals[ 0 ].crossVectors( tangents[ 0 ], normals[ 0 ] ).normalize();
}
*/
/*
///initialNormal3方法選擇初始化法線向量垂直於第一條切線向量和最小切線方向的xyz分量.
*/
function initialNormal3() {
// select an initial normal vector perpenicular to the first tangent vector,
// and in the direction of the smallest tangent xyz component
// 選擇初始化法線向量垂直於第一條切線向量和最小切線方向的xyz分量
normals[ 0 ] = new THREE.Vector3();
binormals[ 0 ] = new THREE.Vector3();
smallest = Number.MAX_VALUE;
tx = Math.abs( tangents[ 0 ].x );
ty = Math.abs( tangents[ 0 ].y );
tz = Math.abs( tangents[ 0 ].z );
if ( tx <= smallest ) {
smallest = tx;
normal.set( 1, 0, 0 );
}
if ( ty <= smallest ) {
smallest = ty;
normal.set( 0, 1, 0 );
}
if ( tz <= smallest ) {
normal.set( 0, 0, 1 );
}
vec.crossVectors( tangents[ 0 ], normal ).normalize();
normals[ 0 ].crossVectors( tangents[ 0 ], vec );
binormals[ 0 ].crossVectors( tangents[ 0 ], normals[ 0 ] );
}
// compute the slowly-varying normal and binormal vectors for each segment on the path
// 爲路徑上的每條線段計算緩慢變換的法線和副法線.
for ( i = 1; i < numpoints; i ++ ) {
normals[ i ] = normals[ i-1 ].clone();
binormals[ i ] = binormals[ i-1 ].clone();
vec.crossVectors( tangents[ i-1 ], tangents[ i ] );
if ( vec.length() > epsilon ) {
vec.normalize();
theta = Math.acos( THREE.Math.clamp( tangents[ i-1 ].dot( tangents[ i ] ), - 1, 1 ) ); // clamp for floating pt errors
normals[ i ].applyMatrix4( mat.makeRotationAxis( vec, theta ) );
}
binormals[ i ].crossVectors( tangents[ i ], normals[ i ] );
}
// if the curve is closed, postprocess the vectors so the first and last normal vectors are the same
// 如果曲線路經是閉合的,處理頂點數組的最後一個頂點爲第一個頂點.
if ( closed ) {
theta = Math.acos( THREE.Math.clamp( normals[ 0 ].dot( normals[ numpoints-1 ] ), - 1, 1 ) );
theta /= ( numpoints - 1 );
if ( tangents[ 0 ].dot( vec.crossVectors( normals[ 0 ], normals[ numpoints-1 ] ) ) > 0 ) {
theta = - theta;
}
for ( i = 1; i < numpoints; i ++ ) {
// twist a little...
normals[ i ].applyMatrix4( mat.makeRotationAxis( tangents[ i ], theta * i ) );
binormals[ i ].crossVectors( tangents[ i ], normals[ i ] );
}
}
};
商域無疆 (http://blog.csdn.net/omni360/)
本文遵循“署名-非商業用途-保持一致”創作公用協議
轉載請保留此句:商域無疆 - 本博客專注於 敏捷開發及移動和物聯設備研究:數據可視化、GOLANG、Html5、WEBGL、THREE.JS,否則,出自本博客的文章拒絕轉載或再轉載,謝謝合作。
以下代碼是THREE.JS 源碼文件中extras/geometries/TubeGeometry.js文件的註釋.