WebGL3(WebGL or WebGPU?)

1 WebGL介绍

WebGL(Web Graphics Library)是一种基于OpenGL ES的JavaScript API,用于在网页浏览器中实现高性能的3D图形渲染,无需安装额外插件。它通过着色器(Shader)编程直接调用GPU能力,支持复杂的3D场景、物理模拟和实时渲染效果。

WebGL完全集成于HTML5 Canvas,可与JavaScript、CSS3和Web API无缝协作,广泛应用于游戏开发、数据可视化、虚拟/增强现实(VR/AR)、科学模拟和交互式艺术等领域,为现代Web应用带来沉浸式视觉体验。主流浏览器(如Chrome、Firefox、Safari和Edge)均提供支持,是构建跨平台3D网页内容的标准技术。

要验证当前是否支持webgl。直接打开:https://get.webgl.org/

关于图形的部分,直接可以在网页查看。chrome://gpu/

我的输入如下:

官方API手册:WebGL 2.0 Specification

另一个API手册:WebGL: 2D and 3D graphics for the web - Web APIs | MDN

单页速查手册:https://www.khronos.org/files/webgl/webgl-reference-card-1_0.pdf 

互动学习教程:WebGL2 理论基础

2 WebGL例子

2.1 三角形

代码

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>WebGL Triangle</title>
    <style>
        body { margin: 0; overflow: hidden; }
        canvas { display: block; }
    </style>
</head>
<body>
    <canvas id="glcanvas" width="400" height="400"></canvas>
<script>
const canvas = document.getElementById('glcanvas');
const gl = canvas.getContext('webgl');

const vsSource = `
  attribute vec2 a_position;
  void main() {
    gl_Position = vec4(a_position, 0.0, 1.0);
  }
`;
const fsSource = `
  void main() {
    gl_FragColor = vec4(1, 0, 0, 1);  // 红色
  }
`;

// 编译着色器
function compileShader(gl, type, source) {
  const shader = gl.createShader(type);
  gl.shaderSource(shader, source);
  gl.compileShader(shader);
  return shader;
}

const vertexShader = compileShader(gl, gl.VERTEX_SHADER, vsSource);
const fragmentShader = compileShader(gl, gl.FRAGMENT_SHADER, fsSource);

const program = gl.createProgram();
gl.attachShader(program, vertexShader);
gl.attachShader(program, fragmentShader);
gl.linkProgram(program);

// 设置顶点数据
const vertices = new Float32Array([
  0, 1,
  -1, -1,
  1, -1
]);
const buffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, buffer);
gl.bufferData(gl.ARRAY_BUFFER, vertices, gl.STATIC_DRAW);

// 启用属性
gl.useProgram(program);
const aPosition = gl.getAttribLocation(program, 'a_position');
gl.enableVertexAttribArray(aPosition);
gl.vertexAttribPointer(aPosition, 2, gl.FLOAT, false, 0, 0);

// 绘制
gl.clearColor(0, 0, 0, 1);
gl.clear(gl.COLOR_BUFFER_BIT);
gl.drawArrays(gl.TRIANGLES, 0, 3);
</script>

</body>
</html>    

 效果

2.2 渐变色

代码

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>WebGL Triangle</title>
    <style>
        body { margin: 0; overflow: hidden; }
        canvas { display: block; }
    </style>
</head>
<body>
    <canvas id="glcanvas" width="400" height="400"></canvas>
    <canvas id="glcanvas" width="400" height="400"></canvas>
    <script>
    const canvas = document.getElementById('glcanvas');
    const gl = canvas.getContext('webgl');
    
    const vs = `
      attribute vec2 a_position;
      varying vec2 v_pos;
      void main() {
        v_pos = a_position;
        gl_Position = vec4(a_position, 0, 1);
      }
    `;
    const fs = `
      precision mediump float;
      varying vec2 v_pos;
      void main() {
        gl_FragColor = vec4(v_pos * 0.5 + 0.5, 1.0, 1.0);  // x y 映射到 RGB
      }
    `;
    
    const compile = (type, src) => {
      const s = gl.createShader(type);
      gl.shaderSource(s, src);
      gl.compileShader(s);
      return s;
    };
    
    const prog = gl.createProgram();
    gl.attachShader(prog, compile(gl.VERTEX_SHADER, vs));
    gl.attachShader(prog, compile(gl.FRAGMENT_SHADER, fs));
    gl.linkProgram(prog);
    gl.useProgram(prog);
    
    const quad = new Float32Array([
      -1, -1, 1, -1, -1, 1,
      -1, 1, 1, -1, 1, 1
    ]);
    const buf = gl.createBuffer();
    gl.bindBuffer(gl.ARRAY_BUFFER, buf);
    gl.bufferData(gl.ARRAY_BUFFER, quad, gl.STATIC_DRAW);
    
    const pos = gl.getAttribLocation(prog, 'a_position');
    gl.enableVertexAttribArray(pos);
    gl.vertexAttribPointer(pos, 2, gl.FLOAT, false, 0, 0);
    
    gl.drawArrays(gl.TRIANGLES, 0, 6);
    </script>
    

</body>
</html>    

效果

2.3 旋转立方体

代码

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>WebGL Triangle</title>
    <style>
        body { margin: 0; overflow: hidden; }
        canvas { display: block; }
    </style>
</head>
<body>
    <script src="https://cdn.jsdelivr.net/npm/three@0.152.2/build/three.min.js"></script>
<canvas id="canvas"></canvas>
<script>
const scene = new THREE.Scene();
const camera = new THREE.PerspectiveCamera(75, 1, 0.1, 1000);
const renderer = new THREE.WebGLRenderer({canvas: document.getElementById("canvas")});
renderer.setSize(400, 400);

const geometry = new THREE.BoxGeometry();
const material = new THREE.MeshBasicMaterial({color: 0x00ff00, wireframe: true});
const cube = new THREE.Mesh(geometry, material);
scene.add(cube);

camera.position.z = 3;

function animate() {
  requestAnimationFrame(animate);
  cube.rotation.x += 0.01;
  cube.rotation.y += 0.01;
  renderer.render(scene, camera);
}
animate();
</script>

    

</body>
</html>    

效果

3 WebGL的实现

其实就是ANGLE,项目主页:https://github.com/google/angle

这个其实也是谷歌维护的项目,本质上,就是就是提供了一套opengl es的接口。为什么不用原生的opengl es呢?据说原因有几个,一个是opengl es的驱动一般是原厂提供,质量参差不齐。第二个是直接让webgl操作gles给的权限太大,相当于直接可以操作硬件了,最后有个中间层,可以跨Vulkan、D3D、Metal,相当于手机,苹果,PC全包,提供的兼容性更好。

对于谷歌安卓的原生应用,考虑到性能,还是直接使用的opengl es,但是Flutter现在也都是使用ANGLE了。

在windows下的库是libEGL_angle.so。

策略一览:

浏览器是否默认用 ANGLE特殊说明
Chrome(Windows/Android)✅ 默认用 ANGLE后端通常是 Vulkan 或 D3D11/12
Edge✅ 默认用 ANGLE同 Chrome
ChromeOS✅ 用 ANGLE为稳定性优化
Firefox❌ 默认直接调用 GLES(Linux/Android)或 OpenGL(桌面)可选用 ANGLE(WebRender)
Safari❌ 不用 ANGLE使用系统 Metal/OpenGL 实现(macOS/iOS)
Chromium Embedded Framework (CEF)✅ 可配置是否用 ANGLE大多默认开启

转换的内容如下:

  • Windows 平台默认将 OpenGL ES → Direct3D 11

  • macOS 平台:OpenGL ES → Metal

  • Linux 或特定构建:OpenGL ES → Vulkan(或原生 OpenGL)

以glDrawArrays()为例,在windows下的ANGLE调用的就是Direct3D,过程如下:

[ WebGL JS ] 
   ↓
[ glDrawArrays(...) ]  ← 用户 JS 层
   ↓
[ libGLESv2/libANGLE ] ← ANGLE OpenGL ES API 接口层
   ↓
[ Context::drawArrays(...) ] ← 通用 ANGLE 调度
   ↓
[ RendererD3D::drawArrays(...) ] ← 后端实现(如 D3D11)
   ↓
[ ID3D11DeviceContext::Draw(...) ] ← GPU 驱动调用
 

4 WebGPU

在上面说过,WebGL是基于ANGLE,而ANGLE是opengl es接口。那么就有一个问题,那就是opengl es是opengl的简化版,天生性能不足。

特性OpenGLOpenGL ES
定位桌面/工作站高性能图形(PC、Mac)嵌入式/移动设备(手机、平板、车载系统)
复杂度功能全面,API 较庞大精简版,移除冗余功能,保留核心渲染能力
标准组织Khronos GroupKhronos Group
派生关系OpenGL ES 是 OpenGL 的子集基于 OpenGL 裁剪,专为低功耗优化

具体限制如下:

类型是否支持说明
计算着色器(Compute Shader)❌ 不支持无法做 GPGPU 计算
几何着色器(Geometry Shader)❌ 不支持不能动态生成图元
高级渲染管线❌ 不支持无 Tessellation
延迟渲染(Deferred Shading)✅ 可模拟可用 FBO + MRT 实现
实时阴影✅ 可模拟用 shadow map 技术
后处理特效✅ 可实现用多个 FBO + shader 实现

为了提供更高的性能和功能。所以,在之后的规范中,又搞出来了WebGPU,模式和上面大差不差,规范地址:WebGPU

特性WebGLWebGPU
基于 APIOpenGL ES(老旧)Vulkan / D3D12 / Metal(现代)
浏览器实现方式通常通过 ANGLE 转译为 Vulkan/D3D/Metal直接调用系统的底层图形 API
ANGLE 依赖✅ 是核心依赖❌ 默认不依赖
性能开销较高(多一层抽象)更低,更靠近底层硬件
现代 GPU 特性支持弱,受 GLES 限制强,支持计算着色器、并行指令、精细控制等

 谷歌也提供了一个叫做Dawn的中间层。 地址是:https://github.com/google/dawn

 5 WebGPU的例子

自己看吧,比我搞的简单例子强多了。

three.js examples

WebGPU Samples

6 原生/WebGL/WebGPU性能比较

数据来自deepseek

测试场景

一个包含大量动态物体的3D场景:

  • 100,000个旋转的立方体

  • 每帧更新所有物体的变换矩阵

  • 使用相同的着色器程序

  • 相同的渲染质量设置

在配备NVIDIA GTX 1080的测试机器上,渲染100,000个立方体的帧率(FPS):

技术平均FPS特点
原生OpenGL45 FPS直接硬件访问,但每个物体单独绘制调用
原生Vulkan120 FPS多线程命令缓冲,更低的驱动开销
WebGL 2.012 FPS高绘制调用开销,JavaScript瓶颈
WebGPU85 FPS接近原生性能,支持多线程和计算着色器

 从这个测试来看,WebGPU比WebGL提升够大的,差不多7倍了。

Vulkan比OpenGL提升也够大的,差不多3倍。

WebGPU是OpenGL两倍也是没想到。。。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值