javascript基础学习系列二百九十七:WebGL 上下文

在完全支持的浏览器中,WebGL 2.0 上下文的名字叫"webgl2",WebGL 1.0 上下文的名字叫 “webgl1”。如果浏览器不支持 WebGL,则尝试访问 WebGL 上下文会返回 null。在使用上下文之前, 应该先检测返回值是否存在:

// 确保浏览器支持<canvas> if (drawing.getContext) {
  let gl = drawing.getContext("webgl");
  if (gl){
// 使用WebGL }
 }

这里把 WebGL context 对象命名为 gl。大多数 WebGL 应用和例子遵循这个约定,因为 OpenGL ES
2.0 方法和值通常以"gl"开头。这样可以让 JavaScript 代码看起来更接近 OpenGL 程序。 18.4.2 WebGL 基础
取得 WebGL 上下文后,就可以开始 3D 绘图了。如前所述,因为 WebGL 是 OpenGL ES 2.0 的 Web 版,所以本节讨论的概念实际上是 JavaScript 所实现的 OpenGL 概念。 25
可以在调用 getContext()取得 WebGL 上下文时指定一些选项。这些选项通过一个参数对象传入, 选项就是参数对象的一个或多个属性。
26 27 28
 alpha:布尔值,表示是否为上下文创建透明通道缓冲区,默认为 true。
 depth:布尔值,表示是否使用 16 位深缓冲区,默认为 true。
 stencil:布尔值,表示是否使用 8 位模板缓冲区,默认为 false。
 antialias:布尔值,表示是否使用默认机制执行抗锯齿操作,默认为 true。
 premultipliedAlpha:布尔值,表示绘图缓冲区是否预乘透明度值,默认为 true。 preserveDrawingBuffer:布尔值,表示绘图完成后是否保留绘图缓冲区,默认为 false。
建议在充分了解这个选项的作用后再自行修改,因为这可能会影响性能。

可以像下面这样传入 options 对象:

   let drawing = document.getElementById("drawing");
// 确保浏览器支持<canvas> if (drawing.getContext) {
      let gl = drawing.getContext("webgl", { alpha: false });
      if (gl) {
// 使用WebGL }
}

这些上下文选项大部分适合开发高级功能。多数情况下,默认值就可以满足要求。
如果调用 getContext()不能创建 WebGL 上下文,某些浏览器就会抛出错误。为此,最好把这个 方法调用包装在 try/catch 块中:

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

常量

如果你熟悉 OpenGL,那么可能知道用于操作的各种常量。这些常量在 OpenGL 中的名字以 GL_开 头。在 WebGL 中,context 对象上的常量则不包含 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 代码时,要记住这些约定。

准备绘图

准备使用 WebGL 上下文之前,通常需要先指定一种实心颜色清除。为此,要调用 clearColor()方法并传入 4 个参数,分别表示红、绿、蓝和透明度值。每个参数必须是 0~1 范围内的 值,表示各个组件在最终颜色的强度。比如:

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

以上代码把清理颜色缓冲区的值设置为黑色,然后调用 clear()方法,这个方法相当于 OpenGL 中的 glClear()方法。参数 gl.COLOR_BUFFER_BIT 告诉 WebGL 使用之前定义的颜色填充画布。通 常,所有绘图操作之前都需要先清除绘制区域。

视口与坐标

绘图前还要定义 WebGL 视口。默认情况下,视口使用整个区域。要改变视口,可以调用 viewport()方法并传入视口相对于元素的 x、y 坐标及宽度和高度。例如,以下代码表示要 使用整个元素:

 gl.viewport(0, 0, drawing.width,
drawing.height);

这个视口的坐标系统与网页中通常的坐标系统不一样。视口的 x 和 y 坐标起点(0, 0)表示 元素的左下角,向上、向右增长可以用点(width–1, height–1)定义(见图 18-14)。

知道如何定义视口就可以只使用元素的一部分来绘图。比如下面的例子:

// 视口是<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);

定义视口的坐标系统与视口中的坐标系统不一样。在视口中,坐标原点(0, 0)是视口的中心点。左下 角是(–1, –1),右上角是(1, 1),如图

动画与 Canvas 图形 如果绘图时使用了视口外部的坐标,则绘制结果会被视口剪切。例如,要绘制的形状有一个顶点在
(1, 2),则视口右侧的图形会被切掉。

缓冲区

在 JavaScript 中,顶点信息保存在定型数组中。要使用这些信息,必须先把它们转换为 WebGL 缓冲 区。创建缓冲区要调用 gl.createBuffer()方法,并使用 gl.bindBuffer()方法将缓冲区绑定到 WebGL 上下文。绑定之后,就可以用数据填充缓冲区了。比如:

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

调用 gl.bindBuffer()将 buffer 设置为上下文的当前缓冲区。然后,所有缓冲区操作都在 buffer 上直接执行。因此,调用 gl.bufferData()虽然没有包含对 buffer 的直接引用,但仍然是 在它上面执行的。上面最后一行代码使用一个 Float32Array(通常把所有顶点信息保存在 Float32Array 中)初始化了 buffer。如果想输出缓冲区内容,那么可以调用 drawElements()方法 并传入 gl.ELEMENT_ARRAY_BUFFER。
gl.bufferData()方法的最后一个参数表示如何使用缓冲区。这个参数可以是以下常量值。  gl.STATIC_DRAW:数据加载一次,可以在多次绘制中使用。
 gl.STREAM_DRAW:数据加载一次,只能在几次绘制中使用。
 gl.DYNAMIC_DRAW:数据可以重复修改,在多次绘制中使用。
除非是很有经验的 OpenGL 程序员,否则我们会对大多数缓冲区使用 gl.STATIC_DRAW。
缓冲区会一直驻留在内存中,直到页面卸载。如果不再需要缓冲区,那么最好调用 gl.deleteBuffer() 方法释放其占用的内存:

   gl.deleteBuffer(buffer);

错误

与 JavaScript 多数情况下不同的是,在 WebGL 操作中通常不会抛出错误。必须在调用可能失败的方 法后,调用 gl.getError()方法。这个方法返回一个常量,表示发生的错误类型。下面列出了这些常量。
 gl.NO_ERROR:上一次操作没有发生错误(0 值)。
 gl.INVALID_ENUM:上一次操作没有传入 WebGL 预定义的常量。
 gl.INVALID_VALUE:上一次操作需要无符号数值,但是传入了负数。
 gl.INVALID_OPERATION:上一次操作在当前状态下无法完成。
 gl.OUT_OF_MEMORY:上一次操作因内存不足而无法完成。
 gl.CONTEXT_LOST_WEBGL:上一次操作因外部事件(如设备掉电)而丢失了 WebGL 上下文。 每次调用 gl.getError()方法会返回一个错误值。第一次调用之后,再调用 gl.getError()可
能会返回另一个错误值。如果有多个错误,则可以重复这个过程,直到 gl.getError()返回 gl.NO_ERROR。如果执行了多次操作,那么可以通过循环调用 getError():

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

如果 WebGL 代码没有产出想要的输出结果,那么可以调用几次 getError(),这样有可能帮你找

到问题所在。

  • 6
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值