(一)直觀了解CircleGeometry
CircleGeometry
(扇形幾何體)是Three.js
體系中最簡單的一種幾何體。可以通過閱讀它的源碼來強(qiáng)化理解Geometry的幾大要素:
- 頂點(diǎn)
- 法向量
- 紋理
- 面
一個(gè)最簡單的扇形幾何體:
這個(gè)扇形的邊緣弧度似乎不夠平滑,可以為他加入更多的三角形,來模擬一個(gè)平滑的弧度扇形。
現(xiàn)在你對(duì)
CircleGeometry
已經(jīng)有了一個(gè)直觀的了解,接下來届榄,我們來做源碼解讀。
(二)源碼解讀
1. 頂點(diǎn)(vertex)
CircleGeometry
由一定數(shù)量的三角形組成倔喂,它的幾何形狀由一下參數(shù)決定:
/**
* radius: 扇形的半徑铝条,也是三角形的等邊長度
* segments: 組成扇形的三角形的數(shù)量,segments越大滴劲,三角形越多攻晒,扇形邊緣 越平滑
* thetaStart: 扇形的起始角度
* thetaLength:扇形的圓心角,
**/
CircleBufferGeometry( radius, segments, thetaStart, thetaLength )
如何計(jì)算這行三角形的頂點(diǎn)呢班挖?
用紅色的圈標(biāo)出了所有的頂點(diǎn)鲁捏。根據(jù)傳入的segments
,可以計(jì)算出頂點(diǎn)的數(shù)量:
vertices.length = 1(圓心) + (segments + 1)
//將圓形加入頂點(diǎn)緩存中
vertices.push( 0, 0, 0 );
根據(jù)上面的示意圖萧芙,可以計(jì)算出每個(gè)頂點(diǎn)的X,Y值
//Θ等于每個(gè)三角形的所經(jīng)過的圓心角度數(shù)
Θ = thetaStart + (thetaLength / segments) * index
X = radius * cos(Θ)
Y = radius * sin(Θ)
因此给梅,在CirlcleGeometry
中會(huì)有以下代碼:
for(s =0; s<= segments;s++) {
var segment = thetaStart + s / segments * thetaLength;
vertex.x = radius * Math.cos( segment );
vertex.y = radius * Math.sin( segment );
vertex.z = 0;
vertices.push(vertex.x,vertex.y,vertex.z = 0)
}
2.面
在之前的文章中,我們知道面是頂點(diǎn)的索引双揪。在CircleGeometry
中,indices就是用來存儲(chǔ)頂點(diǎn)索引的緩存數(shù)組动羽。
//保存頂點(diǎn)索引
//(1,2,0),(2,3,0),(3,4,0)...
for ( i = 1; i <= segments; i ++ ) {
indices.push( i, i + 1, 0 );
}
3.貼圖(uv)
uvs
用于指定頂點(diǎn)對(duì)應(yīng)的貼圖坐標(biāo)。圖片和WebGL其實(shí)屬于兩個(gè)不同的坐標(biāo)系渔期,圖片坐標(biāo)系(uv坐標(biāo))的范圍是[0,1]运吓,WebGL的坐標(biāo)系范圍是[-1,1]。為了關(guān)聯(lián)起這兩種坐標(biāo)系疯趟,需要將他們進(jìn)行統(tǒng)一拘哨。
只要簡單的平移和縮放,就能將[-1,-1]坐標(biāo)系統(tǒng)一到[0,1]坐標(biāo)系中信峻。
x = (x + 1)/2
y = (y + 1)/2
for ( s = 0, i = 3; s <= segments; s ++, i += 3 ) {
var segment = thetaStart + s / segments * thetaLength;
// vertex
vertex.x = radius * Math.cos( segment );
vertex.y = radius * Math.sin( segment );
vertices.push( vertex.x, vertex.y, vertex.z );
// normal
normals.push( 0, 0, 1 );
//統(tǒng)一WebGL和貼圖坐標(biāo)系
//現(xiàn)在倦青,你應(yīng)該能理解下面代碼的含義了
uv.x = ( vertices[ i ] / radius + 1 ) / 2;
uv.y = ( vertices[ i + 1 ] / radius + 1 ) / 2;
uvs.push( uv.x, uv.y );
}
最終貼圖效果如下(為了便于展示,將扇形的圓形角調(diào)整為360):