WebGL学习系列-第一个程序

来源:互联网 发布:淘宝下架时间显示插件 编辑:程序博客网 时间:2024/04/28 11:23

前言

本篇学习第一个WebGL程序——画一个点,通过此程序来理解WebGL程序的结构,这是所有后续知识的开端。

画一个点

先看一下效果图:
画点效果图

为了画这么一个点,在WebGL可不太简单,它会涉及到WebGL上下文以及着色器的概念,不要着急,咱们慢慢来理解。

WebGL上下文

学过Canvas的同学应该都知道,想要在浏览器中使用Canvas画图,需要先取得一个上下文,就像创建一个场景一样,有了场景才可以绘制。在WebGL中,想要进行绘制,一样需要先获取一个上下文,而且跟Canvas 2D开发上下文的获取非常的类似。

1、首先,要有一个canvas dom元素

<canvas id="webgl" width="400" height="400">    您的浏览器不支持canvas,建议使用Chrome浏览器</canvas>

2、获取上一步得到的 canvas dom元素,然后获取WebGL上下文

var canvas = document.getElementById('webgl');// 获取WebGL上下文function createWebGLContext(canvas){    var names = ["experimental-webgl", "webgl" , "webkit-3d", "moz-webgl"];    var webglContext = null;    for (var i = 0; i < names.length; i++) {        try {            webglContext = canvas.getContext(names[i]);            if(webglContext){                break;            }        } catch(e) {}    }    return webglContext;}

考虑到兼容性,所以我们尝试多种获取WebGL上下文的方式,只要任何一种获取成功即可返回WebGL上下文。

背景清除

学习WebGL开发的时候,有个非常重要的概念就是清除重绘。打个比方,我们想要在界面上画两个矩形,先画第一个,然后隔5秒后再画第二个,最终界面上显示2个矩形。那么正确的做法是先绘制第一个矩形,然后使用一个5秒的定时器,5秒后清空之前绘制的所有内容,然后绘制两个矩形。说白了,就是你所看到的东西是一次性绘制出来的,而不能先绘制一点,隔一会再绘制一点,每一次绘制都要进行整个画面的重绘。而在重绘的时候,一般我们都会设置一个重绘的默认背景颜色,设置一次即可。

// 这里指定默认背景色为黑色,不透明context.clearColor(0.0, 0.0, 0.0, 1.0);

设置完默认背景色之后,在每一次绘制之前,我们手动清除绘制区域,然后重绘整个画面。

// 清空context.clear(context.COLOR_BUFFER_BIT);

注意到这里我们使用 context.COLOR_BUFFER_BIT,其实,我们每一次绘制的时候,可能要画非常多的图形,不是说我们画一个图形就立马在浏览器上显示的,那样很可能出现闪屏,所以我们绘制其实是绘制在称为颜色缓冲区的一块内存空间来的,等全部绘制好之后,再一次性刷新到浏览器展现,这样才不会闪屏。除了COLOR_BUFFER_BIT(颜色缓冲区),以后我们还会接触context.DEPTH_BUFFER_BIT(深度缓冲区),后续篇章再解释。

绘制

有了上下文,知道了绘制的方法,接下来我们就要绘制了,本篇我们要绘制一个点,为了绘制一个点,我们要有绘制点的api,要知道点的位置,大小和颜色。

我们使用 context.drawArrays(context.POINTS, 0, 1); 来绘制一个点,drawArrays可以用于绘制点、线段、扇形等各类形状,参数简要介绍如下:

绘制基本图形:drawArrays(mode , first  , count)   mode:  绘制的形状,用于决定点是怎么连接成图形的first: 顶点开始索引count: 使用多少个顶点进行绘制

此api能够绘制的基本图形如下所示:

基本图形

有了绘制的api还不够,我们发现没有地方指定点的位置、大小、颜色之类的属性,这对于新学习的朋友一定感到很迷惑,到现在还没有看到可以设置点属性的地方,这也是WebGL比较麻烦,但也是非常精华的一部分,这一块实际上是由着色器来完成的。

先来看一张图:

着色器示意图

在WebGL中,有两类着色器,分别为顶点着色器和片元着色器,它们的作用上图已经表述得很清楚了,着色器其实就是一段代码,然后会被底层不断的调用,从而获取绘制所需要的点的一些信息。为了使用着色器,需要创建一个program对象,program对象内部再绑定顶点着色器和片元着色器对象,而着色器对象又是需要我们创建的,创建后指定代码片段字符串即可,最后在context中,使用这个program即可,drawArrays接口内部会自行跟program中的着色器通信对接。

再来看一张顶点着色器的示意图:

顶点着色器示意图

再对应到代码中就很容易理解了,片元着色器的使用流程也是一样的。

本示例中我们的顶点着色器代码片段如下:

// 顶点着色器代码(决定顶点在哪里、大小、颜色)var VSHADER_SOURCE =   'void main() {\n' +  '  gl_Position = vec4(0.0, 0.0, 0.0, 1.0);\n' + // 设置顶点的位置  '  gl_PointSize = 10.0;\n' +                    // 设置顶点的大小  '}\n';

注意,着色器的代码片段是以字符串形式存在 的,而且像其他语言一样有个main函数,顶点着色器有几个内置变量,目前我们使用了gl_Position 和 gl_PointSize ,分别表示顶点的位置和大小,而且我们在这里固化了变量的值,以后再来研究怎么实现动态变量,现在你要知道,当我们执行drawArrays的时候,底层会执行顶点着色器的代码,获取点的位置和大小。

片元着色器的代码如下:

var FSHADER_SOURCE =      'void main() {\n' +      '  gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0);\n' + // 设置顶点的颜色      '}\n';`````````

在片元着色器中,我们使用了内部属性 gl_FragColor,用于表示像素的颜色值,此代码片段在真正执行时,对于每一个像素,都会被调用一次,所以称之为片元着色器也挺符合的。

小结

经过上面的分析,我们发现在WebGL中绘制一个点确实不太容易,但是当理清了各个涉及到的知识点之后,画其他东西原理都差不多的,最主要还是要理解着色器的概念,这只是第一篇,往后随着不断学习,不断加深对着色器的理解。

源码

<!DOCTYPE html><html lang="en">  <head>    <meta charset="utf-8" />    <title>第一个WebGL程序-画一个点</title>  </head>  <body onload="main()">    <canvas id="webgl" width="400" height="400">        您的浏览器不支持canvas,建议使用Chrome浏览器    </canvas>    <script>        // 主程序入口    function main(){        var canvas = document.getElementById('webgl');        var context = createWebGLContext(canvas);        var program = createProgram(context , VSHADER_SOURCE ,FSHADER_SOURCE);        context.program = program;        context.useProgram(program);        // 每一次重绘时的背景色        context.clearColor(0.0, 0.0, 0.0, 1.0);        // 清除 <canvas>        context.clear(context.COLOR_BUFFER_BIT);        // 画一个点        context.drawArrays(context.POINTS, 0, 1);    }    // 获取WebGL上下文    function createWebGLContext(canvas){        var names = ["experimental-webgl", "webgl" , "webkit-3d", "mozwebgl"];        var webglContext = null;        for (var i = 0; i < names.length; i++) {            try {                webglContext = canvas.getContext(names[i]);                if(webglContext){                    break;                }            } catch(e) {}        }        return webglContext;    }    // 创建一个program(相当于着色器的上下文)    function createProgram(context, vshader, fshader){        var vertexShader = loadShader(context, context.VERTEX_SHADER,vshader);        var fragmentShader = loadShader(context,context.FRAGMENT_SHADER,fshader);        var program = context.createProgram();        context.attachShader(program, vertexShader);        context.attachShader(program, fragmentShader);        context.linkProgram(program);        return program;    }       function loadShader(context, type, source){        var shader = context.createShader(type);        context.shaderSource(shader, source);        context.compileShader(shader);        return 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';    </script>  </body></html>

源码下载

点击下载源码(画一个点)

0 0
原创粉丝点击