您的位置:首页 > 其它

WebGL学习系列-第一个程序

2017-02-18 14:21 417 查看

前言

本篇学习第一个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>


源码下载

点击下载源码(画一个点)
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  webgl