《WebGL入门指南》——第1章,第1.3节WebGL原生API

1.3 WebGL原生API
WebGL入门指南
计算机图形学中的基本概念在过去的数年中从未发生过变化。但图形技术却不断进化,特别是最近几年,伴随着设备和操作系统的多样化。这些百花齐放的图形技术的根基则是诞生于20世纪80年代末期的OpenGL。OpenGL作为行业规范已经存在了非常长的时间,并且成功经受住了来自微软的DirectX的竞争考验,无可争辩的成为了3D图形编程的领衔者。

但是并非所有的OpenGL都是一样的。根据不同平台的不同特征,包括台式电脑、智能电视、手机和平板电脑等,人们开发了不同版本的OpenGL。OpenGL ES(Embedded System,即嵌入式系统)就是其中的一个版本,专门用于运行在较小的设备上,例如智能电视和手机。也许当初OpenGL ES的设计者们并未料到,正是它成为了WebGL的理想核心。OpenGL ES小而精悍,这并不只是说它足够小因此可以集成到浏览器中,还意味着不同的浏览器厂商都可以使用这套规范。这样的话,WebGL应用就可以顺利的运行在所有的不同浏览器中。

但所有这些高性能和便携性的背后都有代价。WebGL精悍的本质其实是将责任压在了应用开发者的肩上,他们必须自己去处理所有的模型、场景、显示列表和其他构架;当然,在资深图形开发者看来,这都是理所当然的。最值得关注的是,对于一般的Web开发者,WebGL的学习之路陡峭而崎岖,WebGL看起来好像天书。而好消息则是目前已经有很多开源的WebGL框架,可以大大简化WebGL开发的工作量。说个有些粗糙的比喻,这些框架就好像是jQuery和Prototype.js一样。在本书中我们会花几页的篇幅讨论其中一个框架Three.js。但在这之前,我们还是快速地浏览一下WebGL的底层原理。

1.3.1 WebGL应用结构剖析
从本质上来讲,WebGL只是一个绘制库——一个增强型的绘制库,使用WebGL你可以绘制出惊人的图形,并可以在当前大部分机器上充分利用强大的GPU硬件能力。但也可以把WebGL理解成另一种画布,类似于HTML5浏览器中的2D Canvas。实际上,WebGL也正是使用了HTML5中的 元素来在浏览器页面中显示3D图形。

想要使用WebGL把图形渲染到页面中,一个应用至少需要执行如下步骤。
1.创建一个画布元素。
2.获取画布的上下文。
3.初始化视口。
4.创建一个或多个包含渲染数据的数组(通常是顶点数组)。
5.创建一个或多个矩阵,将顶点数组变换到屏幕空间中。
6.创建一个或多个着色器来实现绘制算法。
7.使用参数初始化着色器。
8.绘制。

在本小节中我们会详细介绍上述的每一个步骤,各步骤的代码片段来源于一个完整的示例,在这个示例中我们用WebGL绘制了一个白色的正方形。你可以从文件Chapter 1/example1-1.html中找到完整的代码。

1.3.2 画布元素与绘制上下文
所有的WebGL渲染都发生在一个上下文(context)中,这是一个JavaScript DOM对象,可以提供完整的WebGL API。这个结构类似于HTML5中 元素的2D绘制上下文。想要使用WebGL,只需要创建一个元素,然后获取与它关联的DOM对象(使用document.getElementById()),最后再为其获得一个WebGL上下文即可。示例1-1展示了如何从画布的DOM对象中获得WebGL上下文。

示例1-1 从Canvas中获取WebGL上下文

function initWebGL(canvas) {
    var gl;
    try
    {
        gl = canvas.getContext("experimental-webgl");
    }
    catch (e)
    {
        var msg = "Error creating WebGL Context!: " + e.toString();
        alert(msg);
        throw Error(msg);
    }
    return gl;
}

图片 3 请注意示例代码中的try/catch这一部分。这一部分非常重要,因为目前一些浏览器依然不支持WebGL,或者即使支持了,但是用户并没有安装包含WebGL支持的最新版本的浏览器。另外,即使浏览器支持WebGL,但因为用户使用的是老旧的硬件,因此并不能成功的获得上下文。所以示例1-1中这一部分的检测代码将会帮助你做一个回滚,比如回滚到2D画布,或者至少能让你的应用礼貌地选择退出。

1.3.3 视口
一旦成功的从画布中获得了WebGL的绘制上下文,你就可以告诉它在哪里绘制矩形了。在WebGL中,这被称为视口(vewport),在WebGL中设置视口非常简单,只需要调用上下文的viewport()方法即可(参见示例1-2)。

示例1-2 设置WebGL视口

function initViewport(gl, canvas)
{
    gl.viewport(0, 0, canvas.width, canvas.height);
}

让我们回忆一下,gl对象是在initWebGL()函数中创建的。在这个示例中,我们初始化的WebGL的视口占据了整个画布的显示区域。

1.3.4 Buffer、ArrayBuffer和类型化数组
现在我们获取到了上下文并设置好了视口,可以准备开始绘制了。这和2D Canvas还是很像的。

WebGL的绘制是由图元(primitive)组成的,图元的种类包括三角形(三角形数组)、三角形带(triangle strip,稍后我们会讲到)、点和线。图元使用的数据数组被称为Buffer,它定义了顶点的位置。示例1-3展示了如何创建一个大小为1×1的正方形的顶点数组。返回的JavaScript对象存储了顶点数组信息、数组中每个顶点所占的尺寸(在这个示例中,包含三个浮点数来存储x, y, z的值)、需要绘制的顶点的数量,以及用于绘制正方形的图元的类型。(在这个示例中,我们使用了三角形带。三角形带是一种基本的渲染图元,它是指使用前三个顶点画出第一个三角形,然后再用这前三个顶点中的后两个与下一个顶点结合再绘制一个三角形,依次类推。)

示例1-3 创建顶点数组

// 创建用于绘制正方形的顶点数据
function createSquare(gl) {
    var vertexBuffer;
    vertexBuffer = gl.createBuffer();
    gl.bindBuffer(gl.ARRAY_BUFFER, vertexBuffer);
    var verts = [
         .5,  .5,  0.0,
         -.5,  .5,  0.0,
         .5, -.5,  0.0,
         -.5, -.5,  0.0
   ];
    gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(verts),
        gl.STATIC_DRAW);
    var square = {buffer:vertexBuffer, vertSize:3, nVerts:4,
        primtype:gl.TRIANGLE_STRIP};
    return square;
}

请注意我们使用了一个叫做Float32Array的数据类型。这是一种为了WebGL而专门引入浏览器中的新数据类型。Float32Array是ArrayBuffer的一种,也被称为类型化数组(typed array),用于在JavaScript中存储二进制数据。在JavaScript中访问类型化数组可以使用与传统数组相同的语法,但是速度更快并且占用更少的内存。在对性能要求很高的场合下,使用它来处理二进制数据是非常理想的选择。类型化数组还可以用于很多其他的场合,但是它最开始是因为WebGL才被引入的。你可以在科纳斯组织的官方网站上找到类型化数组的规范全文(http://www.khronos.org/registry/ typedarray/specs/latest/)。

1.3.5 矩阵
在绘制正方形之前,我们必须建立两个矩阵。首先,我们需要一个矩阵来定义正方形在3D坐标系中相对于相机的位置。这个矩阵也称为模型视图矩阵(modelview matrix),因为它综合了模型的变换和相机之间的关系。在这个示例中,我们对模型的变换就是将正方形沿着负z轴进行平移(即远离相机-3.333个单位)。

我们需要的第二个矩阵就是投影矩阵(projection matrix),这个矩阵将被用于在着色器中将相机空间中模型的3D坐标转换为绘制的视口的2D坐标。在这个示例中,投影矩阵定义了一个45°的相机视野。投影矩阵非常难以想象,几乎没有人会手动编写计算投影矩阵的代码,而都是由框架来自动完成。在这里我推荐一个非常好用的开源框架,叫做glMatrix(https://github.com/toji/glmatrix),它专门用来在JavaScript中进行矩阵运算。glMatrix是由Brandon Jones编写的,他同时也是一些精彩的WebGL作品的作者,他复刻了Quake和其他几个著名游戏的WebGL版本。

示例1-4 设置模型视图矩阵和投影矩阵

function initMatrices()
{
   // 正方形的变换矩阵——相对于相机沿着z轴稍微后移一些
   modelViewMatrix = new Float32Array(
           [1, 0, 0, 0,
            0, 1, 0, 0,
            0, 0, 1, 0,
            0, 0, −3.333, 1]);
   // 变换矩阵(45度视野)
       projectionMatrix = new Float32Array(
           [2.41421, 0, 0, 0,
            0, 2.41421, 0, 0,
            0, 0, −1.002002, −1,
            0, 0, −0.2002002, 0]);
}

1.3.6 着色器
我们离最终的绘制越来越近了。最后还剩一个非常重要的步骤需要设置:着色器。像我们之前所说的一样,着色器其实就是一小段程序,是由高等级的类C语言编写而成,它定义了如何将3D物体的像素切实地绘制在屏幕上。WebGL要求开发者为每个需要绘制的物体提供着色器。一个着色器可以同时应用于多个物体。所以在实际情况下,我们经常只提供一个着色器来满足整个应用程序,然后每次用不同的参数多次复用这个着色器。

着色器是由两个部分组成的:顶点着色器(vertex shader)和片元着色器(fragment shader),后者也被称为像素着色器(pixel shader)。顶点着色器负责将物体的坐标转换到2D空间;片元着色器负责生成最后的颜色输出到每个转换后的顶点像素,而颜色的输入则可以是纯色、纹理、光源或者材质。在这个简单的示例中,顶点着色器综合了modelViewMatrix和projectionMatrix的值,通过计算转换了每一个顶点;而片元着色器则只是简单的输出了白色。

在WebGL中,设置着色器必须遵循一定的步骤,首先编译着色器的各个部分,然后将它们链接到一起。因为篇幅有限,我们在这里只展示两个简单的着色器代码(使用GLSL ES语言,参考示例1-5),而并不写出所有的设置代码。你可以在完整的示例中看到如何设置着色器。

示例1-5 顶点着色器和片元着色器

var vertexShaderSource =
    "    attribute vec3 vertexPos;\n" +
    "    uniform mat4 modelViewMatrix;\n" +
    "    uniform mat4 projectionMatrix;\n" +
    "    void main(void) {\n" +
    "        // 返回变换并投影后的顶点数据\n" +
    "        gl_Position = projectionMatrix  modelViewMatrix  \n" +
                    vec4(vertexPos, 1.0);\n" +
    "    }\n";
var fragmentShaderSource =
    "    void main(void) {\n" +
    "    // 返回像素颜色:永远输出白色\n" +
    "    gl_FragColor = vec4(1.0, 1.0, 1.0, 1.0);\n" +
    "}\n";

1.3.7 绘制图元
现在我们终于万事俱备,可以开始绘制正方形了(参考示例1-6)。我们建立了上下文,设置了视口,顶点数组、矩阵和着色器也已经设置并初始化完成。我们定义了一个函数draw(),在这个函数中将接管WebGL上下文和我们之前建立的矩形对象。首先,函数会先清理一下画布并用黑色作为背景颜色。然后将顶点数组绑定到上下文中,使用着色器,并把顶点数组和矩阵作为输入传递给着色器。最后我们调用了WebGL的drawArrays()方法来绘制正方形。我们简单地告诉它,图元的类型和图元中有多少顶点;WebGL会自动根据我们在上下文中设置的其他值(顶点、矩阵、着色器)完成绘制。

示例1-6 绘制代码

function draw(gl, obj) {
     // 用黑色清空背景
     gl.clearColor(0.0, 0.0, 0.0, 1.0);
     gl.clear(gl.COLOR_BUFFER_BIT);
     // 设置顶点数组
     gl.bindBuffer(gl.ARRAY_BUFFER, obj.buffer);
     // 设置着色器
     gl.useProgram(shaderProgram);
     // 设置着色器参数:点点坐标、投影矩阵和模型视图矩阵
     gl.vertexAttribPointer(shaderVertexPositionAttribute,
        obj.vertSize, gl.FLOAT, false, 0, 0);
     gl.uniformMatrix4fv(shaderProjectionMatrixUniform, false,
        projectionMatrix);
     gl.uniformMatrix4fv(shaderModelViewMatrixUniform, false,
        modelViewMatrix);
     // 绘制物体
     gl.drawArrays(obj.primtype, 0, obj.nVerts);
}

最终完成绘制的结果如图1-5所示。

图1-5 使用WebGL绘制的正方形

时间: 2024-11-08 18:08:46

《WebGL入门指南》——第1章,第1.3节WebGL原生API的相关文章

《WebGL入门指南》——第2章,第2.4节一个真实的3D示例

2.4 一个真实的3D示例 WebGL入门指南 到目前为止,你也许在想"真是个还不错的正方形",然后开始怀疑我们什么时候开始画一些真正的3D图形.好吧,那就现在吧!在示例2-2中我们将会用更有趣的物体来代替正方形,我们将会完成一个看起来还不错.并且展示了大部分WebGL主要特性.同时还保持代码简洁的页面. 图2-2就是页面的最终效果.其中我们设置了标题文字,添加了一个表面贴有图片的立方体,然后在页面底部也添加了文字.另外值得一提的是,这个页面是可以交互的:点击画布元素,立方体就会开始或

《WebGL入门指南》——第1章,第1.4节本章小结

1.4 本章小结 WebGL入门指南 这样我们就结束了WebGL基础知识之旅.噢!东西可真多啊!现在你也许在想,仅仅在屏幕上画一个正方形就如此兴师动众.而且,这还不是一个真正的3D物体!好吧,我部分同意你的意见.WebGL编程,在这个等级上的编程,是相当困难的.标准的设计者做出这样一个决定还是相当清醒的,他们用这样一个既小巧又简单的标准,换取了WebGL强大的能力,而付出的代价是开发者必须要在应用程序端编写大量的代码. 显然,在大部分情况下,我们不会使用WebGL来绘制2D物体.HTML5的2D

《WebGL入门指南》——第2章,第2.3节一个简单的Three.js网页

2.3 一个简单的Three.js网页 WebGL入门指南 好了,我想现在是时候来编写你的第一个 WebGL 程序了.在这一节中,你会看到上手Three.js是一件相当简单的事情.示例2-1实际上是第1章中的那个绘制正方形示例的翻版,但是将代码从150行精简到30行.由此可见,在使用Three.js之后对代码的压缩量之大. 示例2-1 一个简单的Three.js网页 <!DOCTYPE html> <html> <head> <title>A Simple

《WebGL入门指南》——第2章,第2.5节本章小结

2.5 本章小结 WebGL入门指南 本章介绍了第一个真实示例.我必须要说,这其实还是很轻松的.仅仅使用了很少的代码,我们就可以创建一个包含3D内容的HTML网页,装扮它,用动画赋予它生命,然后让它可以交互.你要意识到在过去这是根本不可能的.感谢WebGL,让这一切都变成了现实.而又有了Three.js,可以让你在开发前不必先去考取一个计算机图形学的学位. 我们已经构建和运行起来了WebGL,剩下的就都是细节了.

《WebGL入门指南》——第1章,第1.2节3D图形学——入门

1.2 3D图形学--入门 WebGL入门指南 "数学太难了啦!" --芭比娃娃 也许有点不太好听,但是我必须得说,当我写3D图形的代码的时候,我会和芭比一样,有强烈的欲望想要用疯狂购物来放纵一下自己.因为3D图形编程通常很难,而且需要大量的数学知识.幸运的是,你不需要先成为数学大师再来写WebGL应用:我们会使用各种框架来代替我们去做其中大部分的复杂工作.尽管如此,理解底层的工作原理依然是非常重要的,因此下面我尝试在几页的篇幅内总结出整个3D图形学的基础知识. 1.2.1 3D坐标系

《WebGL入门指南》——第2章,第2.1节Three.js——一个JavaScript 3D引擎

2.1 Three.js--一个JavaScript 3D引擎 WebGL入门指南 需求是创新之母.每个开发者在项目之初都必须不厌其烦的使用WebGL原生API来编写代码,直到可以建立一个自己的代码库,以用于随后的通用3D编程.事实上,已经有很多人完成了这项工作.现在有很多不错的WebGL开源框架,例如GLGE(http://www.glge.org/).SceneJS(http://www.scenejs.org/).CubicVR(http://www.cubicvr.org/)等.每个框架

《WebGL入门指南》——第1章,第1.1节WebGL——一个技术定义

1.1 WebGL--一个技术定义 WebGL入门指南 WebGL 标准是由科纳斯组织(Khronos Group)开发和维护的,该组织还是管理着 OpenGL.COLLADA等其他你也许早有耳闻的规范的标准组织.以下是科纳斯组织的网站上对WebGL的官方描述: WebGL是免授权费的,跨平台的应用程序接口API,它将OpenGL ES 2.0作为在HTML网页内的3D绘图环境,作为低级别文档对象模型接口开放.它使用OpenGL渲染语言GLSL ES,并可被整洁地与其他3D内容上层或下层的网页内

《WebGL入门指南》——第2章,第2.2节建立Three.js运行环境

2.2 建立Three.js运行环境 WebGL入门指南 你要做的第一件事情就是从GitHub上获取到最新版的Three.js包.Three.js在GitHub上的地址是https://github.com/mrdoob/three.js/.复制到本地之后,你可以在build/Three.js目录找到打包好的库文件.另外,Three.js的全部源代码都在src文件夹中.而API文档则是直接连接到GitHub网站,但这份文档相当简陋,你最好还是对照源代码来上手. Three.js使用了Google

《WebGL入门指南》——导读

目 录第1章 WebGL简介 1.1 WebGL--一个技术定义 1.2 3D图形学--入门 1.3 WebGL原生API 1.4 本章小结 第2章 你的第一个WebGL程序 2.1 Three.js--一个JavaScript 3D引擎 2.2 建立Three.js运行环境 2.3 一个简单的Three.js网页2.4 一个真实的3D示例 2.5 本章小结 第3章 图形 第4章 动画 第5章 交互 第6章 2D与3D的整合 第7章 实战WebGL 第8章 你的第一个WebGL游戏 后记 附录A