《WebGL编程指南》基础篇

Posted 肥肠负能量

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了《WebGL编程指南》基础篇相关的知识,希望对你有一定的参考价值。

WegGL编程指南》这本书是每个做3D开发的人必读的一本书,看了很多遍,每次对WebGL的渲染都会有进一步的理解,今天小编就从三个方面对《WebGL编程指南》这本书做一个简单介绍。

 

WebGL采用html5中新引入的<canvas>元素来定义网页上的绘图区域,<canvas>元素可以灵活的支持二维图形和三维图形,但是它不直接提供绘图方法,而是提供一种叫上下文的机制来进行绘图。WebGL的绘制流程可以简单的如图所示:

要使用WebGL绘图就必须使用着色器,着色器程序是以字符串的形式嵌入到javascript文件中的,而且是运行在WebGL系统中的。一个WebGL程序是由运行在浏览器中的JavaScript程序和运行在WebGL系统中的着色器程序构成的。

 

WebGL中的着色器有两个:顶点着色器和片元着色器,顶点着色器是用来描述顶点特性的程序,片元着色器是进行逐片元处理过程的程序。提到顶点着色器,我们不得不提跟顶点相关的缓冲区对象,缓冲区对象是WebGL系统中的一块存储区,通过在缓冲区对象中保存想要绘制的顶点数据,可以一次性的向顶点着色器传入多个顶点数据。


(一)WebGL的缓冲区对象


WebGL中与顶点有关的缓冲区对象根据其用途可以分为两类,一种表示缓冲区对象包含的顶点数据,gl.ARRAY_BUFFER表示;一种表示缓冲区中包含的顶点索引值,用gl.ELEMENT_ARRAY_BUFFER表示。


1.   gl.ARRAY_BUFFER

首先我们看一下包含顶点数据的缓冲区对象,在使用该对象之前,我们首先需要创建缓冲区对象:


var vertexBuffer= gl.createBuffer()


然后将缓冲区对象绑定到WebGL系统中的“目标”上,这里的“目标”表示缓冲区对象的用途。


gl.bindBuffer(gl.ARRAY_BUFFER,buffer)


接下来需要向缓冲区对象中写入数据,这里不能直接向缓冲区对象写入数据,而是向“目标”写入数据,所以,在写入数据之前,必须先将缓冲区对象绑定到“目标上”。


gl.bufferData(gl.ARRAY_BUFFER,data)


注意这里的data不是普通的数组,而是类型化数组, JavaScript中的数组中的元素可以是不同类型的,没有对“大量元素都是同一类型”的情况进行优化,WebGL为了能够提高效率,引入了类型化数组,Float32Array就是其中之一。类型化数组不支持pushpop,只能通过new创建。

 

接下来需要将缓冲区对象分配给attribute变量,实际上是将缓冲区的引用或指针分配给attribute变量。


gl.vertexAttributePointer(location,size,type,normalized,stride,offset)


location指待分配attribute变量的存储位置

size指定缓冲区中每个顶点的分量个数(14

type指定数据的格式

normalized指定是否将非浮点型数据归一化

stride指定相邻两个顶点之间的字节数,默认0

offset指定缓冲区对象的偏移量

 

最后我们需要开启attribute变量,使得这次分配生效。


gl.enableVertexAttribArray(location)


流程图如下所示:

《WebGL编程指南》基础篇

在我们绘制的过程中,通过gl.drawArray()方法指定绘制方式去读取缓冲区的数据,进行各种形状的绘制,任何复杂的图形都可以通过若干个小的三角面进行绘制完成。绘制方式包括:

gl.POINTSgl.LINESgl.LINE_STRIPgl.LINE_LOOPgl.TRIANGLESgl.TRIANGLE-STRIPgl.TRIANGLE-FAN


但是在绘制三维图形的时候,例如立方体,每个顶点包含在不止一个三角面中,这时候我们再使用gl.drawArray方法进行绘制时,需要对同一个顶点进行多次的存储,为了不对同一个顶点进行重复存储,我们可以通过gl.drawElements()方法进行绘制,该方法通过读取ELEMENT_ARRAY_BUFFER中的顶点索引来进行绘制。


2. gl.ELEMENT_ARRAY_BUFFER

通过将顶点索引写入缓冲区,并绑定到gl.ELEMENT_ARRAY_BUFFER上,来管理具有索引结构的三维模型数据,其绘制方式与gl.drawArray一样,存储格式如下图所示:

《WebGL编程指南》基础篇


通过以上方法,我们就完成了对顶点着色器的操作,接下来我们还需要对片元着色器进行操作,但是在顶点着色器和片元着色器之间,我们还有非常重要的一步,就是图元装配和光栅化。图元装配是指顶点根据绘制方式被结合成完整的图元,例如,三角形绘制需要三个点构成一个图元。而光栅化主要负责将矢量图的几何图形转变为栅格化的片元,如下图所示:

《WebGL编程指南》基础篇


这里需要注意,顶点着色器和片元着色器不是直接传递数据的,而是通过插值得到的数据传入了片元着色器,如此我们通过指定顶点的颜色信息,能够得到一副具有平滑过渡效果的彩色图像。当然我们还可以通过纹理映射的方式,将一副图像“贴在”我们要绘制的图形表面。纹理映射的作用,就是根据纹理图像,为光栅化的每个片元,涂上合适的颜色,接下来我们将看看如何将一副图像进行纹理映射的操作。


(二)WebGL的纹理对象


在这之前,我们需要先了解一下图像坐标系,纹理坐标系,WebGL坐标系。图像坐标系的坐标原点在左上角,纹理坐标系的原点在左下角,WebGL坐标系的原点在中心,在进行纹理映射的时候,需要将图像坐标系转换为纹理坐标系,再转换为WebGL坐标系。

《WebGL编程指南》基础篇


WebGL系统中,纹理是以纹理对象的形式被访问的,首先,我们需要创建纹理对象。


gl.createTexture()


接下来我们需要把图像坐标转换为纹理坐标,这里我们需要对图像的Y轴进行翻转。


gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL,1)


WebGL通过纹理单元机制来使用多张纹理,每个纹理单元来管理一张纹理图像,WebGL至少支持8个纹理单元。所以,我们需要激活纹理单元。


gl.activeTexture(gl.TEXTURE0)


与缓冲区对象一样,我们需要将我们的纹理对象绑定到纹理单元上。这一步主要完成了两步,开启纹理对象,将纹理对象绑定到纹理单元上。


gl.bindTexture(gl.TEXTURE_2D,texture)


注意在WebGL中,你没法直接操作纹理对象,必须通过将纹理对象绑定到纹理单元上,通过纹理单元来操作纹理对象。

 

接下来我们可以配置纹理对象的参数,来设置如何根据纹理坐标获取纹素颜色,按哪种方式重复填充纹理等等。


gl.texParameteri(gl.TEXTIRE_2D,pname,param)


最后,我们需要将纹理图像分配给纹理对象


gl.texImage2D(gl.texture_2D,0,gl.RGBA,gl.UNSIGNED_BYTE,image)


其示意图如下:

《WebGL编程指南》基础篇


在片元着色器中,我们通过samper2D这种数据类型来描述纹理对象数据,与attribute变量类似,我们通过gl.uniform1i(u_samper,0)0号纹理单元的数据传递给片元着色器中的取样器变量。

示意性代码如下:



(三)WebGL的光照

WebGL中的光照类型主要有点光源,平行光和环境光,物体表面的反射方式主要有漫反射和环境反射两种。漫反射的反射光在各个方向上都是均匀的,反射光的颜色取决于入射光颜色、表面基地色和入射光与表明形成的角度。针对平行光和点光源而言的,由于平行光具有入射方向,点光源具有光源位置,他们的漫反射都跟入射角度有关,其漫反射是用如下公式计算:


<漫反射光颜色>= <入射光颜色> × <表面基地色> × cosθ


θ表示光线方向与物体表面的法线方向的夹角,如下图所示:


这里需要注意光线方向是入射方向的反方向。由于每个平面都有正面和背面,两个面各有一个法向量,在三维图形学中,表面的正面和背面取决于绘制表面时顶点的顺序,当你从正面观察一个屏幕的时候,其顶点的绘制顺序是顺时针的。


针对环境光而言,由于环境光没有方向,在各个方向上都是均匀的,所以其环境反射的计算公式如下:


<环境反射光颜色> = <入射光颜色> × <表面基地色>

 

一个物体表面的反射光最后为


<反射光颜色>= <漫反射光颜色>+ <环境反射光颜色>

 

 

了解了顶点缓冲区对象,纹理对象以及光照后,我们现在基本上能够使用WebGL绘制出一个具有真实场景效果的画面,这也是WebGL最基本的内容,接下来一期小编会针对WebGL的高级特性进行详细介绍。

 


以上是关于《WebGL编程指南》基础篇的主要内容,如果未能解决你的问题,请参考以下文章

WebGL编程指南pdf

[笔记]《webGL编程指南》- WebGL入门

WebGL《WebGL编程指南》读书笔记——第五章

WebGL编程指南.ZC

WebGL《WebGL编程指南》读书笔记——第六章

WebGL《WebGL编程指南》读书笔记——第四章