《Javascript 高级程序设计(第三版)》笔记0x1C 使用 Canvas 绘图:WebGL

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/funkstill/article/details/85055823

目录

WebGL

    类型化数组

        视图

        类型化视图

WebGL上下文

    常量

    方法命名 

    准备绘图

    视口与坐标

    缓冲区

    错误

    着色器

    编写着色器

    编写着色器程序

    为着色器传入值

    调试着色器和程序

    绘图

    纹理

    读取像素


WebGL

    类型化数组

    WebGL 涉及的复杂计算需要提前知道数值的精度,而标准的 JavaScript 数值无法满足需要。为此,WebGL 引入了一个概念,叫类型化数组(typed arrays)。类型化数组也是数组,只不过其元素被设置为特定类型的值。
    类型化数组的核心就是一个名为 ArrayBuffer 的类型。每个 ArrayBuffer 对象表示的只是内存中指定的字节数,但不会指定这些字节用于保存什么类型的数据。通过 ArrayBuffer 所能做的,就是为了将来使用而分配一定数量的字节。

        视图

    使用 ArrayBuffer(数组缓冲器类型)的一种特别的方式是用它创建数组缓冲器视图。最常见的视图是 DataView,通过它可以选择 ArrayBuffer 中一小段字节。为此,可以在创建 DataView实例的时候传入一个 ArrayBuffer、一个可选的字节偏移量(从该字节开始选择)和一个可选的要选择的字节数。 

//基于整个缓冲器创建一个新视图
var view = new DataView(buffer);
//创建一个开始于字节 9 的新视图
var view = new DataView(buffer, 9);
//创建一个从字节 9 开始到字节 18 的新视图
var view = new DataView(buffer, 9, 10);

alert(view.byteOffset);//字节偏移量
alert(view.byteLength);//字节长度

var buffer = new ArrayBuffer(20),
view = new DataView(buffer),
value;
view.setUint16(0, 25);
view.setUint16(2, 50); //不能从字节 1 开始,因为 16 位整数要用 2B
value = view.getUint16(0);

var buffer = new ArrayBuffer(20),
	view = new DataView(buffer),
	value;
view.setUint16(0, 25);//存25即0000 0000 0001 1001
value = view.getInt8(0);//读 0000 0000 即0
alert(value); //0

        类型化视图

    类型化视图一般也被称为类型化数组,因为它们除了元素必须是某种特定的数据类型外,与常规的数组无异。类型化视图也分几种,而且它们都继承了 DataView。
      Int8Array:表示 8 位二补整数。
      Uint8Array:表示 8 位无符号整数。
      Int16Array:表示 16 位二补整数。
      Uint16Array:表示 16 位无符号整数。
      Int32Array:表示 32 位二补整数。
      Uint32Array:表示 32 位无符号整数。
      Float32Array:表示 32 位 IEEE 浮点值。
      Float64Array:表示 64 位 IEEE 浮点值。

WebGL上下文

Insert IconMargin [download]var drawing = document.getElementById("drawing"),gl;
//确定浏览器支持<canvas>元素
if (drawing.getContext){
	try {
		gl = drawing.getContext("experimental-webgl");
	} catch (ex) {
		//什么也不做
	}
	if (gl){
		//使用 WebGL
	} else {
		alert("WebGL context could not be created.");
	}
}
WebGLExample01.ht

    常量

    常量在 OpenGL 中都带前缀GL_ 。 在WebGL中 ,保存在上下文对象中的这些常量都没有GL_ 前缀 。比如说,GL_COLOR_BUFFER_BIT 常量在 WebGL 上下文中就是 gl.COLOR_BUFFER_BIT。 WebGL 以这种方式支持大多数 OpenGL 常量。

    方法命名 

    OpenGL(以及 WebGL)中的很多方法都试图通过名字传达有关数据类型的信息。如果某方法可以接收不同类型及不同数量的参数,看方法名的后缀就可以知道。方法名的后缀会包含参数个数(1 到 4)和接收的数据类型(f 表示浮点数, i 表示整数)。例如, gl.uniform4f()意味着要接收 4 个浮点数,而 gl.uniform3i()则表示要接收 3 个整数。
    也有很多方法接收数组参数而非一个个单独的参数。这样的方法其名字中会包含字母 v(即 vector,矢量)。因此, gl.uniform3iv()可以接收一个包含 3 个值的整数数组。

    准备绘图

    在实际操作 WebGL 上下文之前,一般都要使用某种实色清除<canvas>,为绘图做好准备。首先必须使用clearColor()方法来指定要使用的颜色值,该方法接收 4 个参数:红、绿、蓝和透明度。每个参数必须是一个 0 到 1 之间的数值,表示每种分量在最终颜色中的强度。 

gl.clearColor(0,0,0,1); //black
gl.clear(gl.COLOR_BUFFER_BIT);

    视口与坐标

    开始绘图之前,通常要先定义 WebGL 的视口(viewport)。

//视口是<canvas>左下角的四分之一区域
gl.viewport(0, 0, drawing.width/2, drawing.height/2);
//视口是<canvas>左上角的四分之一区域
gl.viewport(0, drawing.height/2, drawing.width/2, drawing.height/2);
//视口是<canvas>右下角的四分之一区域
gl.viewport(drawing.width/2, 0, drawing.width/2, drawing.height/2);

    缓冲区

    顶点信息保存在 JavaScript 的类型化数组中,使用之前必须转换到 WebGL 的缓冲区。

var buffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, buffer);
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([0, 0.5, 1]), gl.STATIC_DRAW);

gl.deleteBuffer(buffer);

    错误

    JavaScript 与 WebGL 之间的一个最大的区别在于, WebGL 操作一般不会抛出错误。为了知道是否有错误发生,必须在调用某个可能出错的方法后,手工调用 gl.getError()方法。这个方法返回一个表示错误类型的常量。

var errorCode = gl.getError();
while(errorCode){
    console.log("Error occurred: " + errorCode);
    errorCode = gl.getError();
}

    着色器

    着色器(shader)是 OpenGL 中的另一个概念。WebGL中有两种着色器:顶点着色器和片段(或像素)着色器。顶点着色器用于将 3D 顶点转换为需要渲染的2D点。片段着色器用于准确计算要绘制的每个像素的颜色。 WebGL 着色器的独特之处也是其难点在于,它们并不是用 JavaScript 写的。这些着色器是使用 GLSL(OpenGL Shading Language,OpenGL 着色语言)写的, GLSL 是一种与 C 和 JavaScript完全不同的语言。

    编写着色器

    GLSL 是一种类 C 语言,专门用于编写 OpenGL 着色器。因为 WebGL 是 OpenGL ES 2.0 的实现,所以 OpenGL 中使用的着色器可以直接在 WebGL 中使用。这样就方便了将桌面图形应用移植到浏览器中。
    每个着色器都有一个 main()方法,该方法在绘图期间会重复执行。为着色器传递数据的方式有两种: Attribute 和 Uniform。通过 Attribute 可以向顶点着色器中传入顶点信息,通过 Uniform 可以向任何着色器传入常量值。 Attribute 和 Uniform 在 main()方法外部定义,分别使用关键字 attribute 和uniform。在这两个值类型关键字之后,是数据类型和变量名。 

    编写着色器程序

    浏览器不能理解 GLSL 程序,因此必须准备好字符串形式的 GLSL 程序,以便编译并链接到着色器程序。为便于使用,通常是把着色器包含在页面的<script>标签内,并为该标签指定一个自定义的 type属性。由于无法识别 type 属性值,浏览器不会解析<script>标签中的内容,但这不影响你读写其中的代码。

    为着色器传入值

    为了给着色器传入这个值,必须先找到要接收这个值的变量。对于 Uniform 变量,可以使用 gl.getUniformLocation(),这个方法返回一个对象,表示Uniform 变量在内存中的位置。然后可以基于变量的位置来赋值。 

    调试着色器和程序

    与 WebGL 中的其他操作一样,着色器操作也可能会失败,而且也是静默失败。如果你想知道着色器或程序执行中是否发生了错误,必须亲自询问 WebGL 上下文。 

    绘图

    WebGL 只能绘制三种形状:点、线和三角。其他所有形状都是由这三种基本形状合成之后,再绘制到三维空间中的。执行绘图操作要调用 gl.drawArrays()或 gl.drawElements()方法,前者用于数组缓冲区,后者用于元素数组缓冲区。  

    纹理

    WebGL 的纹理可以使用 DOM 中的图像。要创建一个新纹理,可以调用 gl.createTexture(),然后再将一幅图像绑定到该纹理。如果图像尚未加载到内存中,可能需要创建一个 Image 对象的实例,以便动态加载图像。图像加载完成之前,纹理不会初始化,因此,必须在 load 事件触发后才能设置纹理。 

    读取像素

    与 2D 上下文 类似,通过 WebGL 上下文也能读取像素值。读取像素值的方法 readPixels()与OpenGL 中的同名方法只有一点不同,即最后一个参数必须是类型化数组。像素信息是从帧缓冲区读取的,然后保存在型化数组中。 readPixels()方法的参数有: x、 y、宽度、高度、图像格式、数据类型和类型化数组。前 4 个参数指定读取哪个区域中的像素。图像格式参数几乎总是 gl.RGBA。数据类型参数用于指定保存在类型化数组中的数据的类型。 

猜你喜欢

转载自blog.csdn.net/funkstill/article/details/85055823