WebGL 踩坑系列-3

WebGL 踩坑系列-3

绘制球体

在 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 绘制球形

因为有导入模型的需求,开始接触 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

相关文章
相关标签/搜索