three.js 源碼注釋(二十七)Core/BufferGeometry.js
來源:程序員人生 發布時間:2014-12-10 08:26:10 閱讀次數:6793次
商域無疆 (http://blog.csdn.net/omni360/)
本文遵守“署名-非商業用處-保持1致”創作公用協議
轉載請保存此句:商域無疆 - 本博客專注于 敏捷開發及移動和物聯裝備研究:數據可視化、GOLANG、Html5、WEBGL、THREE.JS,否則,出自本博客的文章謝絕轉載或再轉載,謝謝合作。
俺也是剛開始學,好多地兒肯定不對還請見諒.
以下代碼是THREE.JS 源碼文件中Core/BufferGeometry.js文件的注釋.
更多更新在 : https://github.com/omni360/three.js.sourcecode
/**
* @author alteredq / http://alteredqualia.com/
*/
/*
///BufferGeometry類用來和BufferAttribute配合使用,更多細節可以參考官方的樣例http://threejs.org/
/// 這個類是另外一種創建幾何體對象的方式,它將所有的數據包括頂點位置,法線,面,色彩,uv和其它的自定義屬性存在緩沖區,
/// 這樣可以減少GPU的負荷,BufferGeometry一樣也比Geometry對象復雜,增加了使用的難度,這里的屬性都是寄存在數組中,
/// 比如頂點位置不是Vector3對象,色彩也不是color對象,而是數組.需要訪問這些屬性,需要從屬性緩沖區中讀原始數據.
/// NOTE:根據BufferGeometry類特性,我們在創建1些靜態對象,實例化后不常常操作的對象時,選擇這個類.
///
///
///Example
var geometry = new THREE.BufferGeometry();
// create a simple square shape. We duplicate the top left and bottom right
// vertices because each vertex needs to appear once per triangle.
var vertexPositions = [ [⑴.0, ⑴.0, 1.0],
[ 1.0, ⑴.0, 1.0],
[ 1.0, 1.0, 1.0],
[ 1.0, 1.0, 1.0],
[⑴.0, 1.0, 1.0],
[⑴.0, ⑴.0, 1.0] ];
var vertices = new Float32Array( vertexPositions.length * 3 );
// three components per vertex
// components of the position vector for each vertex are stored
// contiguously in the buffer.
for ( var i = 0; i < vertexPositions.length; i++ ) {
vertices[ i*3 + 0 ] = vertexPositions[i][0];
vertices[ i*3 + 1 ] = vertexPositions[i][1];
vertices[ i*3 + 2 ] = vertexPositions[i][2];
}
// itemSize = 3 because there are 3 values (components) per vertex
geometry.addAttribute( 'position', new THREE.BufferAttribute( vertices, 3 ) );
var material = new THREE.MeshBasicMaterial( { color: 0xff0000 } );
var mesh = new THREE.Mesh( geometry, material );
///
///
///
*/
///<summary>BufferGeometry</summary>
///<returns type="BufferGeometry">返回在緩沖區創建的幾何體對象</returns>
THREE.BufferGeometry = function () {
this.id = THREE.GeometryIdCount ++; //BufferGeometryy對象id屬性.
this.uuid = THREE.Math.generateUUID(); //調用THREE.Math.generateUUID()方法,BufferGeometry對象uuid(通用唯1辨認碼)屬性,
this.name = ''; //BufferGeometry對象name屬性,可以為當前對象定義1個名稱,初始化為''
this.attributes = {}; //BufferGeometry對象attributes屬性,可以為當前對象定義1個名稱,初始化為{}
this.drawcalls = []; //WebGL分區塊繪制,寄存區塊的數組
this.offsets = this.drawcalls; // backwards compatibility 向后兼容
//WebGL分區塊繪制,寄存區塊的數組
this.boundingBox = null; //立方體界限,根據當前幾何體生成的立方體界限 { min: new THREE.Vector3(), max: new THREE.Vector3() }
this.boundingSphere = null; //球體界限,根據當前幾何體生成的球體界限 { radius: float }
};
/****************************************
****下面是BufferGeometry對象提供的功能函數.
****************************************/
THREE.BufferGeometry.prototype = {
constructor: THREE.BufferGeometry, //構造器,返回對創建此對象的BufferGeometry函數的援用
/*
///addAttribute方法給BufferGeometry對象添加屬性信息.
*/
///<summary>addAttribute</summary>
///<param name ="name" type="String">屬性名稱</param>
///<param name ="attribute" type="THREE.BufferAttribute">屬性對象</param>
///<returns type="Object3D">返回添加過屬性BufferGeometry對象</returns>
addAttribute: function ( name, attribute ) {
if ( attribute instanceof THREE.BufferAttribute === false ) { //如果參數attribute不是THREE.BufferAttribute對象
//提示用戶參數毛病.使用正確的對象
console.warn( 'THREE.BufferGeometry: .addAttribute() now expects ( name, attribute ).' );
this.attributes[ name ] = { array: arguments[ 1 ], itemSize: arguments[ 2 ] };
return; //直接返回
}
this.attributes[ name ] = attribute; //返回添加過屬性BufferGeometry對象
},
/*
///getAttribute方法根據屬性名(參數name)返回BufferGeometry對象的屬性信息.
*/
///<summary>getAttribute</summary>
///<param name ="name" type="String">屬性名稱</param>
///<returns type="THREE.BufferAttribute">返回BufferGeometry對象的屬性</returns>
getAttribute: function ( name ) {
return this.attributes[ name ]; //返回BufferGeometry對象的屬性
},
/*
///addDrawCall方法將使用3角面構建的BufferGeometry對象.拆分成多個部份屢次調用WebGL繪制,每次調用WebGL繪制將使用當前幾何體的頂點數組的子集來配置著色器.
///這類做法非常成心義,比如你的幾何體對象有65535個以上的頂點,WebGL將1次繪制調用的最大頂點限制為65535個.如果將對象拆分成幾部份,就不會出問題了.
///被拆分的每部份生成這樣1種結構組成的數組:{ start: Integer, count: Integer, index: Integer }
///start重新指定在繪制調用第1個頂點索引,
///count指定多少個頂點都包括在內,
///index指定1個可選的偏移。
///NOTE:使用adddrawcall添加繪制調用,而不是直接修改此數組。
*/
///<summary>addDrawCall</summary>
///<param name ="start" type="Number">start重新指定在繪制調用第1個頂點索引,</param>
///<param name ="count" type="Number">count指定多少個頂點都包括在內,</param>
///<param name ="indexOffset" type="Number">index指定1個可選的偏移。</param>
///<returns type="Array">返回{ start: Integer, count: Integer, index: Integer } 結構組成的數組</returns>
addDrawCall: function ( start, count, indexOffset ) {
this.drawcalls.push( {
start: start, //start重新指定在繪制調用第1個頂點索引,
count: count, //count指定多少個頂點都包括在內,
index: indexOffset !== undefined ? indexOffset : 0 //index指定1個可選的偏移。
} );
},
/*
///applyMatrix方法對BufferGeometry對象的vertices頂點利用矩陣變換.到達旋轉,縮放,移動的目的.
*/
///<summary>applyMatrix</summary>
///<param name ="matrix" type="Matrix4">仿射矩陣</param>
///<returns type="BufferGeometry">返回新的BufferGeometry對象</returns>
applyMatrix: function ( matrix ) {
var position = this.attributes.position;
if ( position !== undefined ) {
matrix.applyToVector3Array( position.array );
position.needsUpdate = true; // 將屬性position.needsUpdate設置為true
}
var normal = this.attributes.normal;
if ( normal !== undefined ) {
var normalMatrix = new THREE.Matrix3().getNormalMatrix( matrix );
normalMatrix.applyToVector3Array( normal.array ); //對屬性數組中的數值利用變換
normal.needsUpdate = true;
}
},
/*
///fromGeometry方法將Geometry對象轉換為BufferGeometry對象.
///NOTE:settings參數的取值范圍是THREE.NoColors || THREE.FaceColors || THREE.VertexColors
*/
///<summary>fromGeometry</summary>
///<param name ="geometry" type="Geometry">Geometry對象</param>
///<param name ="settings" type=" { 'vertexColors': THREE.NoColors || THREE.FaceColors || THREE.VertexColors}">可選參數,用來設置轉換后的對象頂點從哪里繼承色彩.</param>
///<returns type="BufferGeometry">返回新的BufferGeometry對象</returns>
fromGeometry: function ( geometry, settings ) {
settings = settings || { 'vertexColors': THREE.NoColors };
var vertices = geometry.vertices;
var faces = geometry.faces;
var faceVertexUvs = geometry.faceVertexUvs;
var vertexColors = settings.vertexColors;
var hasFaceVertexUv = faceVertexUvs[ 0 ].length > 0;
var hasFaceVertexNormals = faces[ 0 ].vertexNormals.length == 3;
var positions = new Float32Array( faces.length * 3 * 3 );
this.addAttribute( 'position', new THREE.BufferAttribute( positions, 3 ) );
var normals = new Float32Array( faces.length * 3 * 3 );
this.addAttribute( 'normal', new THREE.BufferAttribute( normals, 3 ) );
if ( vertexColors !== THREE.NoColors ) { //如果沒有設置settings參數
var colors = new Float32Array( faces.length * 3 * 3 ); //將Geometry對象的3角面的所有頂點色彩逐一轉換為BufferGeometry對象的屬性情式
this.addAttribute( 'color', new THREE.BufferAttribute( colors, 3 ) );
}
if ( hasFaceVertexUv === true ) {
var uvs = new Float32Array( faces.length * 3 * 2 );
this.addAttribute( 'uvs', new THREE.BufferAttribute( uvs, 2 ) );
}
for ( var i = 0, i2 = 0, i3 = 0; i < faces.length; i ++, i2 += 6, i3 += 9 ) { //遍歷Geometry對象的3角面數組
var face = faces[ i ];
var a = vertices[ face.a ];
var b = vertices[ face.b ];
var c = vertices[ face.c ];
positions[ i3 ] = a.x; //將位置信息轉換
positions[ i3 + 1 ] = a.y;
positions[ i3 + 2 ] = a.z;
positions[ i3 + 3 ] = b.x;
positions[ i3 + 4 ] = b.y;
positions[ i3 + 5 ] = b.z;
positions[ i3 + 6 ] = c.x;
positions[ i3 + 7 ] = c.y;
positions[ i3 + 8 ] = c.z;
if ( hasFaceVertexNormals === true ) { //將頂點法線轉換
var na = face.vertexNormals[ 0 ];
var nb = face.vertexNormals[ 1 ];
var nc = face.vertexNormals[ 2 ];
normals[ i3 ] = na.x;
normals[ i3 + 1 ] = na.y;
normals[ i3 + 2 ] = na.z;
normals[ i3 + 3 ] = nb.x;
normals[ i3 + 4 ] = nb.y;
normals[ i3 + 5 ] = nb.z;
normals[ i3 + 6 ] = nc.x;
normals[ i3 + 7 ] = nc.y;
normals[ i3 + 8 ] = nc.z;
} else {
var n = face.normal; //將3角面法線轉換
normals[ i3 ] = n.x;
normals[ i3 + 1 ] = n.y;
normals[ i3 + 2 ] = n.z;
normals[ i3 + 3 ] = n.x;
normals[ i3 + 4 ] = n.y;
normals[ i3 + 5 ] = n.z;
normals[ i3 + 6 ] = n.x;
normals[ i3 + 7 ] = n.y;
normals[ i3 + 8 ] = n.z;
}
if ( vertexColors === THREE.FaceColors ) {
var fc = face.color;
colors[ i3 ] = fc.r;
colors[ i3 + 1 ] = fc.g;
colors[ i3 + 2 ] = fc.b;
colors[ i3 + 3 ] = fc.r;
colors[ i3 + 4 ] = fc.g;
colors[ i3 + 5 ] = fc.b;
colors[ i3 + 6 ] = fc.r;
colors[ i3 + 7 ] = fc.g;
colors[ i3 + 8 ] = fc.b;
} else if ( vertexColors === THREE.VertexColors ) { //將頂點色彩轉換
var vca = face.vertexColors[ 0 ];
var vcb = face.vertexColors[ 1 ];
var vcc = face.vertexColors[ 2 ];
colors[ i3 ] = vca.r;
colors[ i3 + 1 ] = vca.g;
colors[ i3 + 2 ] = vca.b;
colors[ i3 + 3 ] = vcb.r;
colors[ i3 + 4 ] = vcb.g;
colors[ i3 + 5 ] = vcb.b;
colors[ i3 + 6 ] = vcc.r;
colors[ i3 + 7 ] = vcc.g;
colors[ i3 + 8 ] = vcc.b;
}
if ( hasFaceVertexUv === true ) { //將頂點uv轉換
var uva = faceVertexUvs[ 0 ][ i ][ 0 ];
var uvb = faceVertexUvs[ 0 ][ i ][ 1 ];
var uvc = faceVertexUvs[ 0 ][ i ][ 2 ];
uvs[ i2 ] = uva.x;
uvs[ i2 + 1 ] = uva.y;
uvs[ i2 + 2 ] = uvb.x;
uvs[ i2 + 3 ] = uvb.y;
uvs[ i2 + 4 ] = uvc.x;
uvs[ i2 + 5 ] = uvc.y;
}
}
this.computeBoundingSphere() //重新計算當前對象的球體界限
return this; //返回新的BufferGeometry對象.
},
/*
///computeBoundingBox方法重新計算當前幾何體對象的立方體界限,并更新this.boundingBox屬性.
*/
///<summary>computeBoundingBox</summary>
///<returns type="Number">返回重算立方體界限后的幾何體對象</returns>
computeBoundingBox: function () {
if ( this.boundingBox === null ) {
this.boundingBox = new THREE.Box3();
}
var positions = this.attributes[ 'position' ].array;
if ( positions ) {
var bb = this.boundingBox;
if ( positions.length >= 3 ) {
bb.min.x = bb.max.x = positions[ 0 ];
bb.min.y = bb.max.y = positions[ 1 ];
bb.min.z = bb.max.z = positions[ 2 ];
}
for ( var i = 3, il = positions.length; i < il; i += 3 ) { //取得當前位置屬性數組中的x,y,z坐標的最大最小值,得到立方體界限
var x = positions[ i ];
var y = positions[ i + 1 ];
var z = positions[ i + 2 ];
// bounding box
// 立方體界限
if ( x < bb.min.x ) {
bb.min.x = x;
} else if ( x > bb.max.x ) {
bb.max.x = x;
}
if ( y < bb.min.y ) {
bb.min.y = y;
} else if ( y > bb.max.y ) {
bb.max.y = y;
}
if ( z < bb.min.z ) {
bb.min.z = z;
} else if ( z > bb.max.z ) {
bb.max.z = z;
}
}
}
if ( positions === undefined || positions.length === 0 ) {
this.boundingBox.min.set( 0, 0, 0 );
this.boundingBox.max.set( 0, 0, 0 );
}
if ( isNaN( this.boundingBox.min.x ) || isNaN( this.boundingBox.min.y ) || isNaN( this.boundingBox.min.z ) ) {
//如果position數組沒有值,提示用戶.
console.error( 'THREE.BufferGeometry.computeBoundingBox: Computed min/max have NaN values. The "position" attribute is likely to have NaN values.' );
}
},
/*
///computeBoundingSphere方法重新計算當前幾何體對象的球體界限,并更新this.boundingSphere[]屬性.
*/
///<summary>computeBoundingSphere</summary>
///<returns type="Number">返回重算球體界限后的幾何體對象</returns>
computeBoundingSphere: function () {
var box = new THREE.Box3();
var vector = new THREE.Vector3();
return function () {
if ( this.boundingSphere === null ) {
this.boundingSphere = new THREE.Sphere();
}
var positions = this.attributes[ 'position' ].array;
if ( positions ) {
box.makeEmpty();
var center = this.boundingSphere.center;
for ( var i = 0, il = positions.length; i < il; i += 3 ) {
vector.set( positions[ i ], positions[ i + 1 ], positions[ i + 2 ] );
box.expandByPoint( vector );
}
box.center( center );
// hoping to find a boundingSphere with a radius smaller than the
// boundingSphere of the boundingBox: sqrt(3) smaller in the best case
var maxRadiusSq = 0;
for ( var i = 0, il = positions.length; i < il; i += 3 ) {
vector.set( positions[ i ], positions[ i + 1 ], positions[ i + 2 ] );
maxRadiusSq = Math.max( maxRadiusSq, center.distanceToSquared( vector ) );
}
this.boundingSphere.radius = Math.sqrt( maxRadiusSq ); //計算當前幾何體對象的球體界限并更新this.boundingSphere[]屬性.
if ( isNaN( this.boundingSphere.radius ) ) {
console.error( 'THREE.BufferGeometry.computeBoundingSphere(): Computed radius is NaN. The "position" attribute is likely to have NaN values.' );
}
}
}
}(),
computeFaceNormals: function () {
// backwards compatibility
//方法已刪除, 向后兼容
},
/*
///computeVertexNormals方法重新計算BufferGeometry對象的3角面對象頂點的法線向量,face數組中每一個元素的vertexNormal屬性,1個face3型對象有3個,1個face4型對象有4個,
/// 但是需要注意的是,被多個表面同享的頂點,其法線向量只有1個,同時遭到多個表面的影響。比如中心在原點,3組表面都垂直于軸的立方體,
/// 其第1象限中的頂點,法線向量是(1,1,1)的歸1化。雖然看上去不可思議,平面的頂點的法線竟然不是垂直于平面的,但這類指定法線的方法
/// 在利用平面摹擬曲面的時候有很好的效果。
///
/// 定義:頂點法線(Vertex Normal)是過頂點的1個矢量,用于在高洛德著色(Gouraud Shading)中的計算光照和紋理效果。在生成曲面時,
/// 通常令頂點法線和相鄰平面的法線保持等角,如圖1,這樣進行渲染時,會在平面接縫處產生1種平滑過渡的效果。如果是多邊形,
/// 則令頂點法線等于該點所屬平面(3角形)的法線,如圖2,以便在接縫處產生突出的邊沿。
///
/// 參考:http://en.wikipedia.org/wiki/Vertex_normal
/// 參考:http://blog.csdn.net/sophistcxf/article/details/9095911
/// 參考:http://www.cnblogs.com/flying_bat/archive/2007/10/13/923286.html
*/
///<summary>computeVertexNormals</summary>
///<returns type="BufferGeometry">返回重算法線向量后的幾何體對象</returns>
computeVertexNormals: function () {
if ( this.attributes[ 'position' ] ) {
var i, il;
var j, jl;
var nVertexElements = this.attributes[ 'position' ].array.length;
if ( this.attributes[ 'normal' ] === undefined ) {
this.attributes[ 'normal' ] = {
itemSize: 3,
array: new Float32Array( nVertexElements )
};
} else {
// reset existing normals to zero
// 將現有的法線向量重置為0
for ( i = 0, il = this.attributes[ 'normal' ].array.length; i < il; i ++ ) {
this.attributes[ 'normal' ].array[ i ] = 0;
}
}
var positions = this.attributes[ 'position' ].array;
var normals = this.attributes[ 'normal' ].array;
var vA, vB, vC, x, y, z,
pA = new THREE.Vector3(),
pB = new THREE.Vector3(),
pC = new THREE.Vector3(),
cb = new THREE.Vector3(),
ab = new THREE.Vector3();
// indexed elements
// 元素索引
if ( this.attributes[ 'index' ] ) {
var indices = this.attributes[ 'index' ].array;
var offsets = ( this.offsets.length > 0 ? this.offsets : [ { start: 0, count: indices.length, index: 0 } ] );
for ( j = 0, jl = offsets.length; j < jl; ++ j ) {
var start = offsets[ j ].start;
var count = offsets[ j ].count;
var index = offsets[ j ].index;
for ( i = start, il = start + count; i < il; i += 3 ) {
vA = index + indices[ i ];
vB = index + indices[ i + 1 ];
vC = index + indices[ i + 2 ];
x = positions[ vA * 3 ];
y = positions[ vA * 3 + 1 ];
z = positions[ vA * 3 + 2 ];
pA.set( x, y, z );
x = positions[ vB * 3 ];
y = positions[ vB * 3 + 1 ];
z = positions[ vB * 3 + 2 ];
pB.set( x, y, z );
x = positions[ vC * 3 ];
y = positions[ vC * 3 + 1 ];
z = positions[ vC * 3 + 2 ];
pC.set( x, y, z );
cb.subVectors( pC, pB );
ab.subVectors( pA, pB );
cb.cross( ab );
normals[ vA * 3 ] += cb.x;
normals[ vA * 3 + 1 ] += cb.y;
normals[ vA * 3 + 2 ] += cb.z;
normals[ vB * 3 ] += cb.x;
normals[ vB * 3 + 1 ] += cb.y;
normals[ vB * 3 + 2 ] += cb.z;
normals[ vC * 3 ] += cb.x;
normals[ vC * 3 + 1 ] += cb.y;
normals[ vC * 3 + 2 ] += cb.z;
}
}
// non-indexed elements (unconnected triangle soup)
// 沒有索引的元素,說明不是3角面對象.
} else {
for ( i = 0, il = positions.length; i < il; i += 9 ) {
x = positions[ i ];
y = positions[ i + 1 ];
z = positions[ i + 2 ];
pA.set( x, y, z );
x = positions[ i + 3 ];
y = positions[ i + 4 ];
z = positions[ i + 5 ];
pB.set( x, y, z );
x = positions[ i + 6 ];
y = positions[ i + 7 ];
z = positions[ i + 8 ];
pC.set( x, y, z );
cb.subVectors( pC, pB );
ab.subVectors( pA, pB );
cb.cross( ab );
normals[ i ] = cb.x;
normals[ i + 1 ] = cb.y;
normals[ i + 2 ] = cb.z;
normals[ i + 3 ] = cb.x;
normals[ i + 4 ] = cb.y;
normals[ i + 5 ] = cb.z;
normals[ i + 6 ] = cb.x;
normals[ i + 7 ] = cb.y;
normals[ i + 8 ] = cb.z;
}
}
this.normalizeNormals(); //取得當前定點的規范化法線向量
this.normalsNeedUpdate = true; //設置this.normalsNeedUpdate屬性為true
}
},
/*
///computeTangents方法重新計算BufferGeometry對象3角面對象頂點的切線空間,
///TBN切線是1個有方向的單位長度,沿著網格表面指向水平(U)紋理方向。在Three.js中切線被描寫為Vector4,包括x,y,z這些組件定義的矢量,
///如果需要,及w用來翻轉副法線。
///
/// 參考:http://blog.csdn.net/bonchoix/article/details/8619624
/// 參考:http://azykise.blog.163.com/blog/static/1730802442010431113010224/
/// 參考:http://blog.csdn.net/meegomeego/article/details/8605463
/// 參考:http://shiba.hpe.sh.cn/jiaoyanzu/wuli/showArticle.aspx?articleId=474&classId=4
///
/// NOTE:幾何體Geometry對象必須有vertex UV屬性,0層將被使用.
*/
///<summary>computeTangents</summary>
///<returns type="Vector3">返回重算切線空間后的幾何體對象</returns>
computeTangents: function () {
// based on http://www.terathon.com/code/tangent.html
// (per vertex tangents)
if ( this.attributes[ 'index' ] === undefined ||
this.attributes[ 'position' ] === undefined ||
this.attributes[ 'normal' ] === undefined ||
this.attributes[ 'uv' ] === undefined ) {
//提示用戶有index, position, normal or uv屬性,才能計算切線空間
console.warn( 'Missing required attributes (index, position, normal or uv) in BufferGeometry.computeTangents()' );
return; //退出
}
//將數組中的元素轉換成頂點,法線向量,uv等對象
var indices = this.attributes[ 'index' ].array;
var positions = this.attributes[ 'position' ].array;
var normals = this.attributes[ 'normal' ].array;
var uvs = this.attributes[ 'uv' ].array;
var nVertices = positions.length / 3;
if ( this.attributes[ 'tangent' ] === undefined ) {
var nTangentElements = 4 * nVertices;
this.attributes[ 'tangent' ] = {
itemSize: 4,
array: new Float32Array( nTangentElements )
};
}
var tangents = this.attributes[ 'tangent' ].array;
var tan1 = [], tan2 = [];
for ( var k = 0; k < nVertices; k ++ ) {
tan1[ k ] = new THREE.Vector3();
tan2[ k ] = new THREE.Vector3();
}
var xA, yA, zA,
xB, yB, zB,
xC, yC, zC,
uA, vA,
uB, vB,
uC, vC,
x1, x2, y1, y2, z1, z2,
s1, s2, t1, t2, r;
var sdir = new THREE.Vector3(), tdir = new THREE.Vector3();
/*
///handleTriangle方法重新計算3角面對象的切線空間的TB,TBN.
*/
///<summary>handleTriangle</summary>
///<param name ="a" type="Number">3角面角點a的索引</param>
///<param name ="b" type="Number">3角面角點b的索引</param>
///<param name ="c" type="Number">3角面角點c的索引</param>
function handleTriangle( a, b, c ) {
xA = positions[ a * 3 ];
yA = positions[ a * 3 + 1 ];
zA = positions[ a * 3 + 2 ];
xB = positions[ b * 3 ];
yB = positions[ b * 3 + 1 ];
zB = positions[ b * 3 + 2 ];
xC = positions[ c * 3 ];
yC = positions[ c * 3 + 1 ];
zC = positions[ c * 3 + 2 ];
uA = uvs[ a * 2 ];
vA = uvs[ a * 2 + 1 ];
uB = uvs[ b * 2 ];
vB = uvs[ b * 2 + 1 ];
uC = uvs[ c * 2 ];
vC = uvs[ c * 2 + 1 ];
x1 = xB - xA;
x2 = xC - xA;
y1 = yB - yA;
y2 = yC - yA;
z1 = zB - zA;
z2 = zC - zA;
s1 = uB - uA;
s2 = uC - uA;
t1 = vB - vA;
t2 = vC - vA;
r = 1.0 / ( s1 * t2 - s2 * t1 );
sdir.set(
( t2 * x1 - t1 * x2 ) * r,
( t2 * y1 - t1 * y2 ) * r,
( t2 * z1 - t1 * z2 ) * r
);
tdir.set(
( s1 * x2 - s2 * x1 ) * r,
( s1 * y2 - s2 * y1 ) * r,
( s1 * z2 - s2 * z1 ) * r
);
tan1[ a ].add( sdir );
tan1[ b ].add( sdir );
tan1[ c ].add( sdir );
tan2[ a ].add( tdir );
tan2[ b ].add( tdir );
tan2[ c ].add( tdir );
}
var i, il;
var j, jl;
var iA, iB, iC;
var offsets = this.offsets;
for ( j = 0, jl = offsets.length; j < jl; ++ j ) {
var start = offsets[ j ].start;
var count = offsets[ j ].count;
var index = offsets[ j ].index;
for ( i = start, il = start + count; i < il; i += 3 ) {
iA = index + indices[ i ];
iB = index + indices[ i + 1 ];
iC = index + indices[ i + 2 ];
handleTriangle( iA, iB, iC );
}
}
var tmp = new THREE.Vector3(), tmp2 = new THREE.Vector3();
var n = new THREE.Vector3(), n2 = new THREE.Vector3();
var w, t, test;
/*
///handleVertex方法重新計算幾何體對象頂點的切線空間的TB,TBN.
*/
///<summary>handleVertex</summary>
///<param name ="v" type="Number">頂點a的索引</param>
function handleVertex( v ) {
n.x = normals[ v * 3 ];
n.y = normals[ v * 3 + 1 ];
n.z = normals[ v * 3 + 2 ];
n2.copy( n );
t = tan1[ v ];
// Gram-Schmidt orthogonalize
tmp.copy( t );
tmp.sub( n.multiplyScalar( n.dot( t ) ) ).normalize();
// Calculate handedness
tmp2.crossVectors( n2, t );
test = tmp2.dot( tan2[ v ] );
w = ( test < 0.0 ) ? - 1.0 : 1.0;
tangents[ v * 4 ] = tmp.x;
tangents[ v * 4 + 1 ] = tmp.y;
tangents[ v * 4 + 2 ] = tmp.z;
tangents[ v * 4 + 3 ] = w;
}
for ( j = 0, jl = offsets.length; j < jl; ++ j ) { //遍歷頂點數組
var start = offsets[ j ].start;
var count = offsets[ j ].count;
var index = offsets[ j ].index;
for ( i = start, il = start + count; i < il; i += 3 ) {
iA = index + indices[ i ];
iB = index + indices[ i + 1 ];
iC = index + indices[ i + 2 ];
handleVertex( iA ); //設置頂點的法線向量
handleVertex( iB );
handleVertex( iC );
}
}
},
/*
///computeOffsets方法將較大的幾何體對象的頂點數限制在indexBufferSize所設置的大小,默許為65535.
*/
///<summary>computeTangents</summary>
///<returns type="Vector3">返回{ start: Integer, count: Integer, index: Integer } 結構組成的數組</returns>
/*
computeOffsets
計算偏移量
Compute the draw offset for large models by chunking the index buffer into chunks of 65k addressable vertices.
當遇到比較大的幾何體對象,根據對象的索引值將對象拆分成默許尺寸為65535的塊,供WebGL繪制圖形使用,
This method will effectively rewrite the index buffer and remap all attributes to match the new indices.
這個方法非常對拆分模型非常的游泳.
WARNING: This method will also expand the vertex count to prevent sprawled triangles across draw offsets.
注意: 這個方法還可以通過更改indexBufferSize的值,避免不完全的3角面,
indexBufferSize - Defaults to 65535, but allows for larger or smaller chunks.
indexBufferSize 屬性默許大小事65535,但可以更大或更小.
*/
computeOffsets: function ( indexBufferSize ) {
var size = indexBufferSize;
if ( indexBufferSize === undefined )
size = 65535; //WebGL limits type of index buffer values to 16-bit.
//將WebGL繪制界限限定在16位大小
var s = Date.now();
var indices = this.attributes[ 'index' ].array;
var vertices = this.attributes[ 'position' ].array;
var verticesCount = ( vertices.length / 3 );
var facesCount = ( indices.length / 3 );
/*
console.log("Computing buffers in offsets of "+size+" -> indices:"+indices.length+" vertices:"+vertices.length);
console.log("Faces to process: "+(indices.length/3));
console.log("Reordering "+verticesCount+" vertices.");
*/
var sortedIndices = new Uint16Array( indices.length ); //16-bit buffers
var indexPtr = 0;
var vertexPtr = 0;
var offsets = [ { start:0, count:0, index:0 } ];
var offset = offsets[ 0 ];
var duplicatedVertices = 0;
var newVerticeMaps = 0;
var faceVertices = new Int32Array( 6 );
var vertexMap = new Int32Array( vertices.length );
var revVertexMap = new Int32Array( vertices.length );
for ( var j = 0; j < vertices.length; j ++ ) { vertexMap[ j ] = - 1; revVertexMap[ j ] = - 1; }
/*
Traverse every face and reorder vertices in the proper offsets of 65k.
遍歷所有3角面的頂點,將頂點以65k作為界限劃分.
We can have more than 65k entries in the index buffer per offset, but only reference 65k values.
我們可以講緩沖區塊劃分出比65535跟多的頂點數,但是推薦65535
*/
for ( var findex = 0; findex < facesCount; findex ++ ) {
newVerticeMaps = 0;
for ( var vo = 0; vo < 3; vo ++ ) {
var vid = indices[ findex * 3 + vo ];
if ( vertexMap[ vid ] == - 1 ) {
//Unmapped vertice
//沒有映照的頂點
faceVertices[ vo * 2 ] = vid;
faceVertices[ vo * 2 + 1 ] = - 1;
newVerticeMaps ++;
} else if ( vertexMap[ vid ] < offset.index ) {
//Reused vertices from previous block (duplicate)
//復用之前區塊的頂點
faceVertices[ vo * 2 ] = vid;
faceVertices[ vo * 2 + 1 ] = - 1;
duplicatedVertices ++;
} else {
//Reused vertice in the current block
//在當前的區塊兒內復用頂點
faceVertices[ vo * 2 ] = vid;
faceVertices[ vo * 2 + 1 ] = vertexMap[ vid ];
}
}
var faceMax = vertexPtr + newVerticeMaps;
if ( faceMax > ( offset.index + size ) ) {
var new_offset = { start:indexPtr, count:0, index:vertexPtr };
offsets.push( new_offset );
offset = new_offset;
//Re-evaluate reused vertices in light of new offset.
//重新評估復用新區塊的頂點
for ( var v = 0; v < 6; v += 2 ) {
var new_vid = faceVertices[ v + 1 ];
if ( new_vid > - 1 && new_vid < offset.index )
faceVertices[ v + 1 ] = - 1;
}
}
//Reindex the face.
//重新索引3角面
for ( var v = 0; v < 6; v += 2 ) {
var vid = faceVertices[ v ];
var new_vid = faceVertices[ v + 1 ];
if ( new_vid === - 1 )
new_vid = vertexPtr ++;
vertexMap[ vid ] = new_vid;
revVertexMap[ new_vid ] = vid;
sortedIndices[ indexPtr ++ ] = new_vid - offset.index; //XXX overflows at 16bit
offset.count ++;
}
}
/* Move all attribute values to map to the new computed indices , also expand the vertice stack to match our new vertexPtr. */
//將新計算的索引映照到所有屬性值,并且擴大頂點堆棧匹配新的vertexPtr
this.reorderBuffers( sortedIndices, revVertexMap, vertexPtr );
this.offsets = offsets; //重新設置this.offsets屬性
/*
var orderTime = Date.now();
console.log("Reorder time: "+(orderTime-s)+"ms");
console.log("Duplicated "+duplicatedVertices+" vertices.");
console.log("Compute Buffers time: "+(Date.now()-s)+"ms");
console.log("Draw offsets: "+offsets.length);
*/
return offsets; //返回重算的offsets屬性.
},
/*
///merge方法將兩個幾何體對象或BufferGeometry里面的幾何體對象合并,將屬性數組合并.
*/
///<summary>merge</summary>
///<returns type="BufferGeometry">返回合并后的幾何體對象</returns>
merge: function () {
console.log( 'BufferGeometry.merge(): TODO' );
},
normalizeNormals: function () {
var normals = this.attributes[ 'normal' ].array;
var x, y, z, n;
for ( var i = 0, il = normals.length; i < il; i += 3 ) {
x = normals[ i ];
y = normals[ i + 1 ];
z = normals[ i + 2 ];
n = 1.0 / Math.sqrt( x * x + y * y + z * z );
normals[ i ] *= n;
normals[ i + 1 ] *= n;
normals[ i + 2 ] *= n;
}
},
/*
reoderBuffers:
Reorder attributes based on a new indexBuffer and indexMap.
indexBuffer - Uint16Array of the new ordered indices.
indexMap - Int32Array where the position is the new vertex ID and the value the old vertex ID for each vertex.
vertexCount - Amount of total vertices considered in this reordering (in case you want to grow the vertice stack).
*/
/*
///reorderBuffers方法根參數indexBuffer和參數indexMap重新排列緩沖區中的BufferGeometry對象的屬性數組
*/
///<summary>reorderBuffers</summary>
///<param name ="indexBuffer" type="Uint16Array">新順序的索引</param>
///<param name ="indexMap" type="Int32Array">每一個頂點id和新位置和值的映照表</param>
///<param name ="vertexCount" type="Number">頂點a的索引</param>
///<returns type="BufferGeometry">返回合并后的幾何體對象</returns>
reorderBuffers: function ( indexBuffer, indexMap, vertexCount ) {
/* Create a copy of all attributes for reordering. */
//創建1個所有屬性的副本用來重新排序
var sortedAttributes = {};
var types = [ Int8Array, Uint8Array, Uint8ClampedArray, Int16Array, Uint16Array, Int32Array, Uint32Array, Float32Array, Float64Array ];
for ( var attr in this.attributes ) {
if ( attr == 'index' )
continue;
var sourceArray = this.attributes[ attr ].array;
for ( var i = 0, il = types.length; i < il; i ++ ) {
var type = types[ i ];
if ( sourceArray instanceof type ) {
sortedAttributes[ attr ] = new type( this.attributes[ attr ].itemSize * vertexCount );
break;
}
}
}
/* Move attribute positions based on the new index map */
// 根據新的索引表移動屬性位置.
for ( var new_vid = 0; new_vid < vertexCount; new_vid ++ ) {
var vid = indexMap[ new_vid ];
for ( var attr in this.attributes ) {
if ( attr == 'index' )
continue;
var attrArray = this.attributes[ attr ].array;
var attrSize = this.attributes[ attr ].itemSize;
var sortedAttr = sortedAttributes[ attr ];
for ( var k = 0; k < attrSize; k ++ )
sortedAttr[ new_vid * attrSize + k ] = attrArray[ vid * attrSize + k ];
}
}
/* Carry the new sorted buffers locally */
// 更新存儲在本地緩沖區中的屬性
this.attributes[ 'index' ].array = indexBuffer;
for ( var attr in this.attributes ) {
if ( attr == 'index' )
continue;
this.attributes[ attr ].array = sortedAttributes[ attr ];
this.attributes[ attr ].numItems = this.attributes[ attr ].itemSize * vertexCount;
}
},
/*clone方法
///clone方法克隆1個幾何體對象,將屬性數組分別復制.
*/
///<summary>clone</summary>
///<returns type="Vector4">返回克隆的幾何體對象</returns>
clone: function () {
var geometry = new THREE.BufferGeometry();
var types = [ Int8Array, Uint8Array, Uint8ClampedArray, Int16Array, Uint16Array, Int32Array, Uint32Array, Float32Array, Float64Array ];
for ( var attr in this.attributes ) {
var sourceAttr = this.attributes[ attr ];
var sourceArray = sourceAttr.array;
var attribute = {
itemSize: sourceAttr.itemSize,
array: null
};
for ( var i = 0, il = types.length; i < il; i ++ ) {
var type = types[ i ];
if ( sourceArray instanceof type ) {
attribute.array = new type( sourceArray );
break;
}
}
geometry.attributes[ attr ] = attribute;
}
for ( var i = 0, il = this.offsets.length; i < il; i ++ ) {
var offset = this.offsets[ i ];
geometry.offsets.push( {
start: offset.start,
index: offset.index,
count: offset.count
} );
}
return geometry; //返回克隆的幾何體對象
},
/*dispose方法
///dispose方法從內存中刪除對象,釋放資源.
///NOTE: 當刪除幾何體對象,不要忘記調用這個方法,否則會致使內存泄漏.
*/
///<summary>dispose</summary>
dispose: function () {
this.dispatchEvent( { type: 'dispose' } ); //調度事件.
}
};
///EventDispatcher方法利用到當前Geometry對象.
THREE.EventDispatcher.prototype.apply( THREE.BufferGeometry.prototype );
商域無疆 (http://blog.csdn.net/omni360/)
本文遵守“署名-非商業用處-保持1致”創作公用協議
轉載請保存此句:商域無疆 - 本博客專注于 敏捷開發及移動和物聯裝備研究:數據可視化、GOLANG、Html5、WEBGL、THREE.JS,否則,出自本博客的文章謝絕轉載或再轉載,謝謝合作。
以下代碼是THREE.JS 源碼文件中Core/BufferGeometry.js文件的注釋.
更多更新在 : https://github.com/omni360/three.js.sourcecode
生活不易,碼農辛苦
如果您覺得本網站對您的學習有所幫助,可以手機掃描二維碼進行捐贈