WebGL 101

  • 简介

---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

WebGL是什么?WebGL是一项利用JavaScript API呈现3D计算机图形的技术,有别于过往需加装浏览器插件,通过WebGL的技术,只需要编写网页代码即可实现3D图像的展示。

在详细了解WebGL之前,先看看WebGL为我们带来的3D视觉震撼吧。

  1. Lights  在 Lights 中,黄色的“闪光线”会随着鼠标的左右点击而左右摆动,当“气泡”出现时,点击它们会出现焰火般的炫丽景象。而其背景音乐是英国歌手 Ellie Goulding 制作的一个互动音乐体验,同时随着音乐节拍界面会有呼吸状的闪光。
  2. 经典鱼缸测试这是一个经典的网页速度测试,电脑网速越快,鱼游的速度就越快,另外有多个场景可以切换,鱼的数量也可以设置。
  3. WebGL Water展示了使用WebGL模拟水的效果,可以通过操作水中的球体来感受水体的变化。

要看到上面这些绚烂的效果,你需要确保你的浏览器支持WebGL,目前支持WebGL的浏览器众多,包括:

  • 开发环境搭建

---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

开发WebGL的环境十分简单,你甚至只需要支持WebGL的浏览器和文本编辑器就可以了。通过我的简单测试,推荐使用Google的Chrome浏览器进行开发和调试。WebGL属于3D开发,因此有以下的编程基础可能对你熟练掌握WebGL大有裨益,包括:

  1. OpenGL的相关知识,WebGL是基于OpenGL ES 2.0作为技术蓝本的,而OpenGL ES 2.0又是以OpenGL 2.0为基础。

                                                                     Fig 1  OpenGL和WebGL
  2. Shader尤其是GLSL的编程经验。
    推荐的GLSL学习材料:
    • LightHouse GLSL Tutorial (国内局域网有时候可能访问不了,o(╯□╰)o)
    • OpenGL Shading Language(橙宝书,目前到第三版,网上很容易找到电子版)
    • racehorse的CSDN Blog(lighthouse3d的翻译版)
  3. JavaScript相关编程经验
  • Hello,WebGL

---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

在学习一门新的技术时,如果可以有一个完整的框架,不需要每次都从头开始,对初学者是非常有益的。本文以下部分提供一个完整的WebGL程序,并通过对该程序的解读让读者对如何使用WebGL开发有一个完整的认识。相关内容来自WebGL Programming Guide一书。

  1. 首先创建我们的WebGL第一个示例的Html文件,在任意文件夹中建立名为HelloWebGL.html的文件,用文本编辑器打开,键入以下Html
    <!DOCTYPE html>
    <HTML>
    <HEAD>
    <META NAME="GENERATOR" Content="Microsoft Visual Studio">
    <TITLE>Hello WebGL!</TITLE>
    </HEAD>
    <BODY οnlοad="main()">
    
        <canvas id="webgl" width="400" height="400">
            Your Browser doesn't support WebGL
        </canvas>
       
        <script src="HelloWebGL.js"></script>
    
    </BODY>
    </HTML>
    
    可以看到WebGL绘图的区域是在浏览器中canvas标签之下进行的,canvas标签是Html5引入的一个新的标签,可以在canvas区域绘制2D和3D图形。为了代码的清晰,将WebGL代码的编写部分放在了HelloWebGL.js文件中,也可以将WebGL的代码放在Html中。
  2. 在同一文件夹中建立HelloWebGL.js的文件,开始在其中编写WebGL相关代码
    首先我们需要在代码中写一些GLSL的代码,关于GLSL的编写参看以上GLSL的推荐材料,一般来说GLSL分为两种类型,顶点Shader和片元Shader。在写好Shader之后需要将Shader进行如C语言一样的编译、链接、运行的过程。流程如下:

                                                Fig 2  Shader使用过程
    var VSHADER_SOURCE =
        'void main() {\n' +
        '   gl_Position = vec4(0.0, 0.0, 0.0, 1.0); \n' +
        '   gl_PointSize = 10.0;\n' +
        '}\n';
    var FSHADER_SOURCE =
        'void main() {\n' +
        '   gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0);\n' +
        '}\n';

    以上就是我们写好的Shader,十分的简单,设置顶点位置在(0.0, 0.0, 0.0)处,顶点的大小为10.0,顶点栅格化之后的像素颜色是红色(1.0,0.0,0.0)

    写好Shader之后我们开始写Html中提到加载需要的main函数,代码如下
    function main()
    {
        //获取画布
        var canvas = document.getElementById('webgl');
        //得到WebGL渲染的上下文
        var gl = canvas.getContext('experimental-webgl');
        if (!gl) {
            console.log("Failed to initialize WebGL Context");
            return;
        }
        //初始化Shader
        initializeShader(gl);
        //设置清除背景颜色(此处是黑色)
        gl.clearColor(0.0, 0.0, 0.0, 1.0);
        //清除背景
        gl.clear(gl.COLOR_BUFFER_BIT);
        //绘制点(GL_POINTS)
        gl.drawArrays(gl.POINTS, 0, 1);
    }

    在main函数中我们通过得到canvas的图形渲染上下文gl,之后所有的WebGL调用都是在gl上下文中进行的,main函数中调用的初始化shader的函数如下:
    function initializeShader(gl)
    {
        //创建一个顶点Shader
        var vertexShader = gl.createShader(gl.VERTEX_SHADER);
        if (!vertexShader) {
            console.log("Unable to create Vertex Shader");
            return;
        }
        //读入顶点Shader的内容
        gl.shaderSource(vertexShader, VSHADER_SOURCE);
        //编译顶点Shader
        gl.compileShader(vertexShader);
        var compiledVertexShader = gl.getShaderParameter(vertexShader, gl.COMPILE_STATUS);
        if (!compiledVertexShader) {
            var error = gl.getShaderInfoLog(vertexShader);
            console.log('Failed to compile vertex shader: ' + error);
            gl.deleteShader(vertexShader);
            return;
        }
    
        //创建一个片元Shader
        var fragShader = gl.createShader(gl.FRAGMENT_SHADER);
        if (!fragShader) {
            console.log("Unable to create Fragment Shader");
            return;
        }
        //读入片元Shader的内容
        gl.shaderSource(fragShader, FSHADER_SOURCE);
        //编译片元Shader
        gl.compileShader(fragShader);
        var compiledFragmentShader = gl.getShaderParameter(fragShader, gl.COMPILE_STATUS);
        if (!compiledFragmentShader) {
            var error = gl.getShaderInfoLog(fragShader);
            console.log('Failed to compile fragment shader: ' + error);
            gl.deleteShader(fragShader);
            return;
        }
    
        //创建Program
        var program = gl.createProgram();
        if (!program) {
            return;
        }
        //将编译好的顶点Shader和片元Shader链接到Program之中
        gl.attachShader(program, vertexShader);
        gl.attachShader(program, fragShader);
        gl.linkProgram(program);
    
        var linked = gl.getProgramParameter(program, gl.LINK_STATUS);
        if (!linked) {
            var error = gl.getProgramInfoLog(program);
            console.log('Failed to link program: ' + error);
            gl.deleteProgram(program);
            gl.deleteShader(fragShader);
            gl.deleteShader(vertexShader);
            return;
        }
        //使用(运行)Program
        gl.useProgram(program);
    }

    这一过程还是十分清晰的,流程就是参考了Fig2中的描述。以上就完成了所有的代码
  3. 用Chrome浏览器打开HelloWebGL.html,可以看到
    使用WebGL绘制的一个红色的像素点

    由于每一个WebGL的程序都需要initializeShader这一步骤,因此本文提供一个js文件,使用其中的initShaders函数,传入顶点和片元Shader字符实现shader的初始化过程。

    // cuon-utils.js (c) 2012 kanda and matsuda
    /**
     * Create a program object and make current
     * @param gl GL context
     * @param vshader a vertex shader program (string)
     * @param fshader a fragment shader program (string)
     * @return true, if the program object was created and successfully made current 
     */
    function initShaders(gl, vshader, fshader) {
      var program = createProgram(gl, vshader, fshader);
      if (!program) {
        console.log('Failed to create program');
        return false;
      }
    
      gl.useProgram(program);
      gl.program = program;
    
      return true;
    }
    
    /**
     * Create the linked program object
     * @param gl GL context
     * @param vshader a vertex shader program (string)
     * @param fshader a fragment shader program (string)
     * @return created program object, or null if the creation has failed
     */
    function createProgram(gl, vshader, fshader) {
      // Create shader object
      var vertexShader = loadShader(gl, gl.VERTEX_SHADER, vshader);
      var fragmentShader = loadShader(gl, gl.FRAGMENT_SHADER, fshader);
      if (!vertexShader || !fragmentShader) {
        return null;
      }
    
      // Create a program object
      var program = gl.createProgram();
      if (!program) {
        return null;
      }
    
      // Attach the shader objects
      gl.attachShader(program, vertexShader);
      gl.attachShader(program, fragmentShader);
    
      // Link the program object
      gl.linkProgram(program);
    
      // Check the result of linking
      var linked = gl.getProgramParameter(program, gl.LINK_STATUS);
      if (!linked) {
        var error = gl.getProgramInfoLog(program);
        console.log('Failed to link program: ' + error);
        gl.deleteProgram(program);
        gl.deleteShader(fragmentShader);
        gl.deleteShader(vertexShader);
        return null;
      }
      return program;
    }
    
    /**
     * Create a shader object
     * @param gl GL context
     * @param type the type of the shader object to be created
     * @param source shader program (string)
     * @return created shader object, or null if the creation has failed.
     */
    function loadShader(gl, type, source) {
      // Create shader object
      var shader = gl.createShader(type);
      if (shader == null) {
        console.log('unable to create shader');
        return null;
      }
    
      // Set the shader program
      gl.shaderSource(shader, source);
    
      // Compile the shader
      gl.compileShader(shader);
    
      // Check the result of compilation
      var compiled = gl.getShaderParameter(shader, gl.COMPILE_STATUS);
      if (!compiled) {
        var error = gl.getShaderInfoLog(shader);
        console.log('Failed to compile shader: ' + error);
        gl.deleteShader(shader);
        return null;
      }
    
      return shader;
    }
    
    /** 
     * Initialize and get the rendering for WebGL
     * @param canvas <cavnas> element
     * @param opt_debug flag to initialize the context for debugging
     * @return the rendering context for WebGL
     */
    function getWebGLContext(canvas, opt_debug) {
      // Get the rendering context for WebGL
      var gl = WebGLUtils.setupWebGL(canvas);
      if (!gl) return null;
    
      // if opt_debug is explicitly false, create the context for debugging
      if (arguments.length < 2 || opt_debug) {
        gl = WebGLDebugUtils.makeDebugContext(gl);
      }
    
      return gl;
    }
    




  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值