在 WebGL 中繪製物體時須要的頂點是以直角座標表示的,
固然了,gl_Position 是一個四維的向量,通常將頂點賦值給 gl_Position 時,最後一維會設爲 1,web
gl_Position = uMVPMatrix * vec4(aVertexPosition, 1.0);
這個時候的 aVertexPosition 三維向量就表明了頂點的直角座標。
若是咱們計算出球面上的頂點,並以直角座標的形式傳入着色器中,用合適的方式繪製,就能畫出球面了。canvas
可是,繪製球體須要用到頂點,若是直接用直角座標,並很差計算,
這時候須要用到球座標系將球面上的各個頂點表示出來,而後再將球座標表示成直角座標。數組
/** * 假設球心即爲原點,將球面座標系轉換成平面直角座標系 * @param theta 球心到頂點的連線與 Z 軸正方向的夾角爲 theta,範圍是 [0, 180] * @param beta 球心到頂點的連線在 xoy 平面上的投影與 X 軸正方向的夾角爲 beta,範圍是 [0, 360] * @param r 球半徑 * @return 頂點的座標,用三維數組表示 */ function calcVertex(theta, beta, r) { var st = Math.sin(Math.PI * theta / 180); var ct = Math.cos(Math.PI * theta / 180); var sb = Math.sin(Math.PI * beta / 180); var cb = Math.cos(Math.PI * beta / 180); var x = r * st * cb; var y = r * st * sb; var z = r * ct; return [x, y, z]; }
這個 calcVertex 函數就夠把特定角度和半徑的球座標轉換成相應的直角座標了。
如今只須要從 0 - 180 遍歷 theta,0 - 360 遍歷 beta 角,就能夠獲得球面上的全部頂點了。app
var n = 48; var vetices = []; var r = 1; for( var j = 0; j < n; j++ ) { for( var i = 0; i < n: i++ ) { vertices.push.apply( vertices, calcVertex( i * 180 / n, j * 360 / n, r ) ); // 或者用數組的 concat 方法,效果是同樣的,不過聽說 concat 方法更高效 // vertices = vertices.concat( calcVertex( i * 180 / n, j * 360 / n, r ) ); } }
接下來把獲得的頂點傳入 gl 的緩衝區中,框架
var buffer = gl.createBuffer(); gl.bindBuffer(gl.ARRAY_BUFFER, buffer); gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(vertices), gl.STATIC_DRAW);
若是隻是利用這些頂點,還不能畫出球面,藉助索引緩衝區能夠實現:函數
var index = []; for ( j = 0; j < n; j++ ) { for ( i = 0; i < n+1; i++ ) { index.push( i + j * (n+1), // 0 i+1 + j * (n+1), // 1 i+1 + (j+1) * (n+1) // n+1 ); index.push( i + j * (n+1), // 0 i+1 + (j+1) * (n+1) // n+1 i + (j+1) * (n+1) // n ); } } gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, buffer); gl.drawElements(gl.TRIANGLES, index.length, gl.UNSIGNED_SHORT, 0);
最後就能在 canvas 畫布上畫出球面了,n 越大,球面越精細,畫出的球越圓滑。webgl
因爲有導入模型的需求,開始接觸 ThreeJS,用這個框架只須要調用 SphereGeometry 的 API 生成一個球,最後把球添加到場景中並進行渲染便可。spa
sphere = new THREE.Mesh( new THREE.SphereGeometry(4, 36, 36), new THREE.MeshPhongMaterial( { opacity: 0.65, transparent: true, color: 0xeeeeee } ) ); scene.add(sphere);
儘管 ThreeJS 對底層的 WebGL 封裝的很好,可是我只須要導入 OBJ 格式的模型就好了,ThreeJS 很強大,用起來也很方便。
而要從 WebGL 寫的話,還須要去了解 GLSL 着色器語言,本身編寫着色器代碼,繁瑣不少。code