zoukankan      html  css  js  c++  java
  • WebGL 踩坑系列-3

    WebGL 踩坑系列-3

    绘制球体

    在 WebGL 中绘制物体时需要的顶点是以直角坐标表示的,
    当然了,gl_Position 是一个四维的向量,一般将顶点赋值给 gl_Position 时,最后一维会设为 1,

    gl_Position = uMVPMatrix * vec4(aVertexPosition, 1.0);
    

    这个时候的 aVertexPosition 三维向量就代表了顶点的直角坐标。
    如果我们计算出球面上的顶点,并以直角坐标的形式传入着色器中,用合适的方式绘制,就能画出球面了。

    但是,绘制球体需要用到顶点,如果直接用直角坐标,并不好计算,
    这时候需要用到球坐标系将球面上的各个顶点表示出来,然后再将球坐标表示成直角坐标。

    /**
     * 假设球心即为原点,将球面坐标系转换成平面直角坐标系
     * @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 角,就可以得到球面上的所有顶点了。

    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 越大,球面越精细,画出的球越圆滑。

    ThreeJS 绘制球形

    由于有导入模型的需求,开始接触 ThreeJS,用这个框架只需要调用 SphereGeometry 的 API 生成一个球,最后把球添加到场景中并进行渲染即可。

    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 着色器语言,自己编写着色器代码,繁琐很多。

    本博客由 BriFuture 原创,并在个人博客(WordPress构建) BriFuture's Blog 上发布。欢迎访问。
    欢迎遵照 CC-BY-NC-SA 协议规定转载,请在正文中标注并保留本人信息。
  • 相关阅读:
    new Date在不同浏览器识别问题
    22. Generate Parentheses dfs填表
    迪杰斯特拉+优先队列实现
    1062 最简分数 (20 分)
    1091 N-自守数 (15 分)
    1054 求平均值 (20 分)
    1045 快速排序 (25 分)
    1086 就不告诉你 (15 分)
    1076 Wifi密码 (15 分)
    1081 检查密码 (15 分)
  • 原文地址:https://www.cnblogs.com/brifuture/p/8331727.html
Copyright © 2011-2022 走看看