juejin.cn/post/684490… webgl2fundamentals.org/webgl/lesso…
发展史
- 2015 OpenglES 3.2
- 2018 Webgl2.0 的扩展 (基于OpenGLES 3.1)
功能增强
- 渲染管道增强:遮挡查询,变换反馈,实例渲染
- 着色语言:整数和32位浮点运算支持
- 纹理功能增强
- 浮点纹理,3D纹理, 深度纹理,顶点纹理, NPOT纹理, R/RG纹理,不可变纹理, 2D阵列纹理
- ASTC压缩:减少处理纹理的内存占用和带宽
- 使用JPG或PNG图片格式,使用texImage2D上传图片数据到GPU时会进行解压,转为位图。位图格式占用空间较大,传输时间较长。
- 使用压缩格式,则可以不进行解压,同时节省空间和时间
- WebGL1中通过扩展可以使用压缩纹理格式,但很多是要区分硬件条件的,S3TC基本上只是PC支持,PVTC只有iOS,而WebGL2中多种压缩格式都可以在任何环境下得到支持。
- WebGL2还支持了纹理数组,多个相同大小的纹理切片可以共享一个纹理单元。纹理的访问也可以支持直接选取纹素。
- 浮点渲染目标:提高高精度计操作的灵活性
- Compute Shaders,独立的顶点和片元着色器,间接绘图命令
- 几何和曲面细分着色器:有效处理GPU的复杂场景
- 无需扩展就能使用的重要特性
- 多绘制缓冲
- 多绘制缓冲,也叫做MRT(Multiple Render Targets),是促使我们迁移到WebGL2的动力之一。它可以支持在一个帧缓冲区上绑定多个颜色缓冲区,一次绘制可以在多个缓冲区中写入数据,可用于实现延迟渲染和泛光效果。运用这项技术后,光照及阴影的计算只需要在每个片元上执行一次,而且可以尽量和几何渲染过程解耦。
- Uniform缓冲对象
- Uniform Buffer Object可以让我们像attribute变量一样,把uniform变量写入缓冲区
- 使用gl.bufferData和gl.bindBufferRange两次调用替代N次gl.uniformXXX
- 当多个着色器共用一些uniform变量时,可以一次写入,多处绑定即可
WebGL1迁移WebGL2
- 上下文兼容处理:优先获取webgl2上下文
-
// 优先使用WebGL2,若不支持则降级为WebGL(Safari/QQ浏览器) let gl = canvas.getContext('webgl2', options); if (gl) { gl.isWebGL2 = true; } else { gl = canvas.getContext('webgl', options); gl.isWebGL2 = false; }
-
- 扩展兼容处理:将扩展方法复制到上下文对象
-
function getAndApplyExtension(gl, name) { const ext = gl.getExtension(name); if (!ext) { return null; } const fnSuffix = name.split("_")[0]; const enumSuffix = '_' + fnSuffix; for (const key in ext) { const value = ext[key]; const isFunc = typeof (value) === 'function'; const suffix = isFunc ? fnSuffix : enumSuffix; let name = key; // WEBGL_compressed_texture_s3tc // 和WEBGL_compressed_texture_pvrtc不是true if (key.endsWith(suffix)) { name = key.substring(0, key.length - suffix.length); } if (gl[name] !== undefined) { if (!isFunc && gl[name] !== value) { console.warn("conflict:", name, gl[name], value, key); } } else { if (isFunc) { gl[name] = function(origFn) { return function() { return origFn.apply(ext, arguments); }; }(value); } else { gl[name] = value; } } } return ext; } if (!gl.isWebGL2) { getAndApplyExtension(gl, 'ANGLE_instanced_arrays'); getAndApplyExtension(gl, 'WEBGL_depth_texture'); getAndApplyExtension(gl, 'OES_vertex_array_object'); }
-
- texImage2D的语法
-
// WebGL1: void gl.texImage2D(target, level, internalformat, width, height, border, format, type, ArrayBufferView? pixels); void gl.texImage2D(target, level, internalformat, format, type, ImageData? pixels); void gl.texImage2D(target, level, internalformat, format, type, HTMLImageElement? pixels); void gl.texImage2D(target, level, internalformat, format, type, HTMLCanvasElement? pixels); void gl.texImage2D(target, level, internalformat, format, type, HTMLVideoElement? pixels); void gl.texImage2D(target, level, internalformat, format, type, ImageBitmap? pixels); // WebGL2: void gl.texImage2D(target, level, internalformat, width, height, border, format, type, GLintptr offset); void gl.texImage2D(target, level, internalformat, width, height, border, format, type, HTMLCanvasElement source); void gl.texImage2D(target, level, internalformat, width, height, border, format, type, HTMLImageElement source); void gl.texImage2D(target, level, internalformat, width, height, border, format, type, HTMLVideoElement source); void gl.texImage2D(target, level, internalformat, width, height, border, format, type, ImageBitmap source); void gl.texImage2D(target, level, internalformat, width, height, border, format, type, ImageData source); void gl.texImage2D(target, level, internalformat, width, height, border, format, type, ArrayBufferView srcData, srcOffset);
-
- 深度纹理格式
- 在WebGL2中internalformat不可使用gl.DEPTH_COMPONENT(虽然有这个属性)
- 在WebLG1中不可使用gl.DEPTH_COMPONENT16(虽然有这个属性)
- 上传时就能统一使用gl.DEPTH_COMPONENT24
- WebGL1 internalformat和format 都是相同的
- WebGL2 对应的format都是gl.DEPTH_COMPONENT
- WebGL2 对应的internalformat 是gl.DEPTH_COMPONENT16还是gl.DEPTH_COMPONENT24、gl.DEPTH_COMPONENT32F
-
if (!gl.isWebGL2) { gl.DEPTH_COMPONENT24 = gl.DEPTH_COMPONENT; }
- 深度纹理过滤
- 这里需要设置为gl.NEAREST才能正常使用。
-
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, options.minFilter || gl.LINEAR); gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, options.magFilter || gl.LINEAR);
- 着色器无需升级
- 需要GLSL3.0 就加上#version 300 es即可