Loading [MathJax]/jax/output/CommonHTML/config.js
前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >快速入门 WebGL

快速入门 WebGL

作者头像
羽月
发布于 2022-11-11 10:50:10
发布于 2022-11-11 10:50:10
2.8K00
代码可运行
举报
文章被收录于专栏:羽月技术羽月技术
运行总次数:0
代码可运行

WebGL 是 Web 3D 渲染引擎的基础,它作为非常底层的 API,学习上手难度非常大,这是因为 WebGL 要求的背景知识比较多。而网上的教程一般没有过多介绍直接就介绍 API 开始渲染了,容易让人云里雾里,很容易被劝退,就算学到了 API 使用,也是只懂表面知识,没有了解背后的原理,很容易就忘记了。

《从 0 实现 3D 渲染引擎》系列教程将从最基本知识开始,渐进的讲解 WebGL 使用和 WebGL 背后原理还有必不可少的数学知识,真正的从 0 开始,只要了解 JS 就行,不需要要任何图形学或者数学基础。学完之后除了能够自己从 0 实现自己的 3D 渲染引擎还能熟悉 three.js 的源码,因为本系列文章实现的 3D 渲染引擎和 three.js 很相似。

什么是 WebGL?

WebGL(Web Graphics Library)是一个 Web 标准 JavaScript API,通过 HTML5 的 canvas 元素进行暴露,无需使用插件,即可在浏览器中渲染高性能的交互式 3D 和 2D 图形。目前是由非营利 Khronos Group 设计和维护。

使用 WebGL 的方式和 canvas 2d 类似,都是通过 getContext 方法获取渲染上下文,如下所示。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
const canvas = document.createElement('canvas')const gl = (
  canvas.getContext('webgl2') ||
  canvas.getContext('webgl') ||
  canvas.getContext('experimental-webgl')
)

上面代码中是按照 webgl2webglexperimental-webgl 的顺序获取 WebGL 渲染上下文。webgl2 是最新版本,它几乎完全兼容 WebGL1。experimental-webgl 用来兼容老浏览器,如 IE 11。

兼容性

大多数浏览器都支持 WebGL1。也有很多现代浏览器支持 WebGL2,但是苹果还不支持 WebGL2,所以编写 WebGL 程序时,需要向下降级到 WebGL1。

OpenGL

在深入 WebGL 之前,我们还需要先了解 OpenGL,因为 WebGL 是基于 OpenGL 的。OpenGL(Open Graphics Library) 是用于渲染2D、3D矢量图形的跨语言、跨平台的应用程序编程接口,常用于CAD、虚拟现实、科学可视化程序和电子游戏开发。OpenGL 通常是显卡生产商根据规范来实现的。

OpenGL 前身是 SGI 的 IRIS GL API 它在当时被认为是最先进的科技并成为事实上的行业标准,后由 SGI 转变为一项开放标准 OpenGL。1992年 SGI 创建 OpenGL架构审查委员会,2006年将 OpenGL API 标准的控制权交给 Khronos Group。

OpenGL 是跨平台的,在移动设备上是使用 OpenGL ES(OpenGL for Embedded Systems), 它是 OpenGL 的子集。下图展示了 OpenGL 和 OpenGL ES 的时间线。

WebGL 基于 OpenGL,是 OpenGL 的子集。WebGL1 基于 OpenGL ES 2.0。WebGL2 基于 OpenGL ES 3.0。

GPU

WebGL 性能高的原因是它使用到了 GPU。GPU 和 CPU 针对的是两种不同的应用场景,大家可以把 CPU 想象为一个切图专家,而 GPU 是一群初级切图仔,现在有一大堆非常简单的页面,大街上随便抓个人都能切。那么对于这个任务不用想就知道一群初级切图仔更快,切图专家当然厉害,但是也奈不了对面人多。所以对于大量简单计算 GPU 的执行速度是远大于 CPU 的。

上面图片中,第一个是 CPU,第二是 GPU,CPU 只有一杆枪,而 GPU 有一大捆枪。CPU 要一下一下的打,就像切图专家一个一个的切,而 GPU 一次性全打了,就像一群初级切图仔,没人切一个,一次性全切完了。

上图是显卡 3090 的配置参数,我们可以看到它有 1 万多个核心,24G 显存。支持 3D API,DirectX 12 Ultimate 和 OpenGL 4.6 (DirectX 是微软的图形 API)。

坐标系

WebGL 的坐标系和 canvas 2d 中的是不太一样的。因为 WebGL 是 OpenGL 子集,所以 WebGL 坐标系和 OpenGL 坐标系性值一样。

canvas 2d 中的坐标系如下所示。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
const canvas = document.createElement('canvas')const ctx = canvas.getContext('2d')

canvas 2d 的坐标原点在左上角,X 轴和 Y 轴的正值分别向右和向下。

而 WebGL 的坐标系和 OpenGL 一样,它更符合我们的常识一点。

原点在正中间,右边为 X 轴正方向,上面为 Y 轴正方向,就和数学中的一样。

需要注意的是 WebGL 中坐标值的范围是 -11,而 canvas 2d 是根据 canvas 的宽高大小来的。如果 canvas 宽度为 500,那么 WebGL 中的 1 就相当于 5000.5 就相当于 250,这样的好处是我们无需关心 canvas 的宽高,无论 canvas 多大对于渲染图形来说范围都是 -11

当然 WebGL 中还有一个 Z 轴。Z 轴有两种形式,一种是正值朝外,另一种是正值朝内。

当 Z 轴正值朝外时,我们称为右手坐标系,当 Z 轴正值朝内时称为左手坐标系。可以伸出双手像下图一样比划下,就知道为什么称为左手坐标系和右手坐标系了。

那么 WebGL 是左手坐标系还是右手坐标系呢?答案为都不是。但是在实际开发中是使用 右手坐标系,当然并不是右手坐标系比左手坐标系好,而是右手坐标系是 OpenGL 的惯例。例如微软的 DirectX 中惯用的是左手坐标系。

这里为什么说 WebGL 既不是左手坐标系也不是右手坐标系,原因将在后续文章中讲解,现在只用知道 WebGL 中使用的是右手坐标系,也就是 Z 轴正值朝外。

三角形

WebGL 算是比较底层的图形 API,不同于 canvas 2d,WebGL 只能用它来渲染点,线和三角形。那些复杂的 3D 模型其实都是由一个个三角形组成。

比如上方这辆汽车模型,它其实是由 267300 个三角形组成。

点击这个链接查看模型详情https://sketchfab.com/3d-models/the-argonaut-4982efe9a03e42e6a867c33afd863ca5

可能有同学会问了,为什么就是三角形,而不是 5 边形,6 边形呢?

因为三角形有很多的优势,比如三角形一定在一个平面上,任何多边形都可以使用三角形组成等性值。

渲染一个三角形

了解了这么多背景知识,现在让我们来实际使用 WebGL 来渲染一个最简单的三角形吧。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
const canvas = document.createElement('canvas')
canvas.width = canvas.height = 300document.body.append(canvas)const gl = canvas.getContext('webgl')

gl.viewport(0, 0, gl.canvas.width, gl.canvas.height)// 设置 webgl 视口,将 -1 到 1 映射为 canvas 上的坐标const vertexShader = gl.createShader(gl.VERTEX_SHADER) // 创建一个顶点着色器gl.shaderSource(vertexShader, `
  attribute vec4 a_position;

  void main() {
    gl_Position = a_position; // 设置顶点位置
  }
`) // 编写顶点着色器代码gl.compileShader(vertexShader) // 编译着色器const fragmentShader = gl.createShader(gl.FRAGMENT_SHADER) // 创建一个片元着色器gl.shaderSource(fragmentShader, `
  precision mediump float;
  uniform vec4 u_color;

  void main() {
    gl_FragColor = u_color; // 设置片元颜色
  }
`) // 编写片元着色器代码gl.compileShader(fragmentShader) // 编译着色器const program = gl.createProgram() // 创建一个程序gl.attachShader(program, vertexShader) // 添加顶点着色器gl.attachShader(program, fragmentShader) // 添加片元着色器gl.linkProgram(program) // 连接 program 中的着色器gl.useProgram(program) // 告诉 webgl 用这个 program 进行渲染const colorLocation = gl.getUniformLocation(program, 'u_color') // 获取 u_color 变量位置gl.uniform4f(colorLocation, 0.93, 0, 0.56, 1) // 设置它的值const positionLocation = gl.getAttribLocation(program, 'a_position') 
// 获取 a_position 位置const positionBuffer = gl.createBuffer() 
// 创建一个顶点缓冲对象,返回其 ID,用来放三角形顶点数据,gl.bindBuffer(gl.ARRAY_BUFFER, positionBuffer) 
// 将这个顶点缓冲对象绑定到 gl.ARRAY_BUFFER// 后续对 gl.ARRAY_BUFFER 的操作都会映射到这个缓存gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([    0, 0.5,    0.5, 0,
    -0.5, -0.5]),  // 三角形的三个顶点
     // 因为会将数据发送到 GPU,为了省去数据解析,这里使用 Float32Array 直接传送数据gl.STATIC_DRAW // 表示缓冲区的内容不会经常更改)// 将顶点数据加入的刚刚创建的缓存对象gl.enableVertexAttribArray(positionLocation);// 开启 attribute 变量,使顶点着色器能够访问缓冲区数据gl.vertexAttribPointer( // 告诉 OpenGL 如何从 Buffer 中获取数据
    positionLocation, // 顶点属性的索引
    2, // 组成数量,必须是1,2,3或4。我们只提供了 x 和 y
    gl.FLOAT, // 每个元素的数据类型
    false, // 是否归一化到特定的范围,对 FLOAT 类型数据设置无效
    0, // stride 步长 数组中一行长度,0 表示数据是紧密的没有空隙,让OpenGL决定具体步长
    0 // offset 字节偏移量,必须是类型的字节长度的倍数。)

gl.clearColor(0, 1, 1, 1) // 设置清空颜色缓冲时的颜色值gl.clear(gl.COLOR_BUFFER_BIT) // 清空颜色缓冲区,也就是清空画布gl.drawArrays( // 从数组中绘制图元
    gl.TRIANGLES, // 渲染三角形
    0,  // 从数组中哪个点开始渲染
    3   // 需要用到多少个点,三角形的三个顶点)

渲染结果如下所示。

可以发现 WebGL 的代码非常复杂繁琐,一个非常简单的三角形就需要编写这么多的代码。

上面实例代码中有详细的注释,不过相信大家看了也还是满头问号。我们再来看看 WebGL 渲染的整个流程,一般 WebGL 程序是 JS 提供数据(在 CPU 中运行),然后将数据发送到显存中,交给 GPU 渲染,我们可以使用着色器控制 GPU 渲染管线部分阶段。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
// CPUconst vertexShader = `shader source code` // 顶点着色器代码const fragmentShader = `shader source code` // 片段着色器代码const points = [{ x: 1, y: 1, z: 1 }/* ... */]  // 准备数据gl.draw(points, vertexShader, fragmentShader) // 将数据和着色器发送给 GPU// GPUconst positions = data.map(point => vertexShader(point)) // 运行顶点着色器const frags = Rasterization(positions) // 光栅化const colors = frags.map(frag => fragmentShader(frag)) // 运行片段着色器Display(colors) // 渲染到屏幕

上面的伪代码,简单展示了 WebGL 程序的执行流程。OpenGL 中着色器是使用 GLSL 编写,WebGL 中也是使用的 GLSL 着色器语言,它的语法有点类似 C 语言,我们可以通过顶点着色器和片段着色器控制 GPU 渲染的部分环节。

WebGL 中有两个着色器分别是顶点着色器和片段(也可称为“片元”)着色器。顶点着色器用于处理图形的每个点,也就是上面例子中三角形的三个顶点。处理完毕后会进行光栅化,大家可以把光栅化理解成把图形变成一个个像素,我们显示器屏幕是一个个像素组成的,要显示图形就需要计算出图形中的每个像素点。片段着色器可以先理解成像素着色器,也就是将光栅化中的每个像素拿过来,给每个像素计算一个颜色。整个流程如下所示。

上图中顶点数据传送给 GPU 后,顶点着色器计算出每个点的位置,光栅化计算出图形的每个像素,片段着色器计算出每个像素的颜色,然后就可以渲染到显示器上了。(可以忽略上图的几何着色器,WebGL 中没有这个着色器)着色器先简单介绍到这里,还不了解着色器也没有关系,下篇文章会更加详细的讲解。

其实 WebGL 是一个非常大的状态机,它提供的方法都是改变 WebGL 的某个状态。我们需要在 CPU 中使用 JS 设置 WebGL 的状态,准备数据和着色器程序,然后发送给 GPU 执行。

上方代码可以分为如下几步。

  1. 因为 WebGL 的坐标是 -1 到 1,所以首先我们使用 viewport 设置视口大小信息。
  2. 创建顶点和片段着色器(关于着色器情况下篇文章),然后创建一个程序,来连接顶点和片段着色器。
  3. 然后获取着色器中的变量,设置如何将值传递给着色器。三角形是由 3 个顶点组成,所以准备了 3 个点的坐标。
  4. 设置清屏颜色,并清屏,和坐标类似,WebGL 中的颜色是 0 到 1,而不是 0 到 255。
  5. 将数据发送给 GPU 来渲染三角形

例子

上面这个简单的三角形一点都不炫酷,其实 WebGL 可以做出非常炫酷的效果,下面列举一些不错例子,大家感兴趣可以看一看。

ThreeJS

https://threejs.org/

WebGL Samples

http://webglsamples.org/

Experiments with Google

https://experiments.withgoogle.com/

Adult Swim

https://www.adultswim.com/etcetera/

Evan Wallace

http://madebyevan.com/

总结

这篇文章讲解了什么是 WebGL,了解了 WebGL 的大致轮廓,并且完成了一个最简单的 WebGL 应用。

如果觉得不错欢迎点赞转发分享。

系列文章目录:《从 0 实现 3D 渲染引擎》

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2022-10-10,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 羽月技术 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
【愚公系列】2023年08月 WEBGL专题-canvas和webgl的区别 | 技术创作特训营第一期
本文是专题类文章,主要是针对数字孪生和WEB 3D可视化展开,下面是数字孪生相关概念。
愚公搬代码
2023/08/27
7420
学废了系列 - WebGIS vs WebGL图形编程
目前工作中有不少涉及到地图的项目,我参加了几次技术评审,前端伙伴们在 WebGIS 方面的知识储备稍有不足,这次分享的主要目的是科普一些在前端领域比较常用的 WebGIS 知识。另外,我之前的工作中积攒了一些从零开始搭建 WebGL 地图引擎的微薄经验,虽然最终遗憾没有上线,但在其中学到的一些WebGL知识还是值得分享一下。WebGL 可以说是前端可视化技术领域难度最大的一项图形编程技术,所以今天就结合 WebGIS 这个话题顺带分享一些 WebGL 的相关知识,不会太深入,很细节的技术点在后续文章里再讲解。
寒月十八
2021/06/21
1.9K0
学废了系列 - WebGIS vs WebGL图形编程
【WebGL】初探WebGL,我了解到这些
WebGL基于OpenGL ES(嵌入式系统) 一种广泛用于在各种平台上渲染2D和3D图形的标准。它允许开发人员使用JavaScript与用户设备的GPU(图形处理单元)交互,实现硬件加速渲染。
且陶陶
2023/10/16
4440
【WebGL】初探WebGL,我了解到这些
从关键概念开始,万字带你轻松入门 WebGL
只要理解了 WebGL 背后的概念,学习 WebGL 并没有那么难。很多 WebGL 入门文章并没有介绍这些重要的概念,直接使用 WebGL 复杂的 API 开始渲染图形,很轻松就把入坑文变成了劝退文。这篇文章将会着重讲解这些概念,并一步步探究 WebGL 是如何渲染图片到屏幕的,理解这些重要的概念,将会大大降低学习曲线。
羽月
2022/10/08
2.1K0
从关键概念开始,万字带你轻松入门 WebGL
1.opengl绘制三角形
下面,你会看到一个图形渲染管线的每个阶段的抽象展示。要注意蓝色部分代表的是我们可以注入自定义的着色器的部分。
诺谦
2020/09/27
1.2K0
1.opengl绘制三角形
【Android 音视频开发打怪升级:OpenGL渲染视频画面篇】一、初步了解OpenGL ES
提到OpenGL,想必很多人都会说,我知道这个东西,可以用来渲染2D画面和3D模型,同时又会说,OpenGL很难、很高级,不知道怎么用。
开发的猫
2020/04/01
2K0
【Android 音视频开发打怪升级:OpenGL渲染视频画面篇】一、初步了解OpenGL ES
最简WebGL教程,仅需 75 行代码
现代 OpenGL(以及名为WebGL的扩展)与我过去学习的传统 OpenGL 有很大不同。我了解栅格化的工作原理,所以对这些概念很满意。但是我所阅读的每篇教程都介绍了抽象和辅助函数,这使我很难理解哪些部分是 OpenGL API 的真正核心。
疯狂的技术宅
2020/07/16
2K0
最简WebGL教程,仅需 75 行代码
OpenGL 图形渲染流程入门
1、什么是 shader shader 中文名为着色器,全称为着色器程序,是专门用来渲染图形的一种技术。通过 shader,我们可以自定义显卡渲染画面的算法,使画面达到我们想要的效果。小到每一个像素点,大到整个屏幕。通常来说,程序是运行在 CPU 中的,但是着色器程序比较特殊,它是运行在 GPU 中的,所以当我们在编写 shader 程序的时候,实际上也是在编写 GPU 程序。在 OpenGL 中,对应的着色器语言是 GLSL(OpenGL Shading Language)。通过 shader 编程,我们
用户1097444
2022/06/29
2.3K0
OpenGL 图形渲染流程入门
进阶 | webgl性能优化初尝
作者|vorshen 原文|http://www.alloyteam.com/2017/05/webgl-performance-optimizations-first-taste/ 上次文章介绍了如何用webgl快速创建一个自己的小世界,在我们入门webgl之后,并且可以用原生webgl写demo越来越复杂之后,大家可能会纠结一点:就是我使用webgl的姿势对不对。因为webgl可以操控shader加上超底层API,带来了一个现象就是同样一个东西,可以有多种的实现方式,而此时我们该如何选择呢?这篇文章将稍
用户1097444
2022/06/29
1.2K0
进阶 | webgl性能优化初尝
可视化导学-图形基础
关于 HTML/CSS、SVG、Canvas2D 和 WebGL 这四种图形系统。
Cellinlab
2023/05/17
1.1K0
可视化导学-图形基础
几个简单的小例子手把手带你入门webgl
各位同学们大家好,又到了周末写文章的时间,之前群里有粉丝提问, 就是shader不是很理解。然后今天他就来了, 废话不多说,读完今天的这篇文章你可以学到以下几点:
coder_koala
2021/09/18
1.4K0
几个简单的小例子手把手带你入门webgl
OpenGL 系列---基础绘制流程
OpenGL 是一种应用程序编程接口,它是一种可以对图形硬件设备特性进行访问的软件库。
音视频开发进阶
2019/07/26
1.9K0
OpenGL现代编程第二课——第一个多边形
https://learnopengl-cn.github.io/01%20Getting%20started/04%20Hello%20Triangle/
用户5908113
2020/01/02
7450
【前端可视化】 OpenGL / WebGL 入门和实践
OpenGL 是一套规范,不是接口,学习这套规范,就可以在支持 OpenGL 的机器上正常使用这些规范,在显示器上看到绘制的结果。
ConardLi
2019/10/24
4.7K1
Android多媒体之GL-ES战记第一集--勇者集结
前言 1.本系列借花献佛,结合了很多前人的文章以及书籍,我尽可能去总结并用我的思想进行加工 2.OpenGL一直是我的心结,也是时候去解开了,本系列称不上原创,但每行代码都有着我思考的痕迹 3.本系列所有的图片都是[张风捷特烈]所画,如果有什么错误还请指出,定会最快改正 4.本系列文章允许转载、截取、公众号发布,请保留前言部分,希望广大读者悉心指教 ---- NPC:开场词 传说,在这片代码大陆上,存在一个古老的种族,它们拥有无尽的力量,却罕有人能够驾驭 多媒体王国中存在一个隐蔽的角落
张风捷特烈
2019/02/25
1.7K0
Android多媒体之GL-ES战记第一集--勇者集结
解剖 WebGL & Three.js 工作原理
本文主要介绍了WebGL和Three.js的渲染流程,从加载模型到生成纹理和片元着色器,再到进行矩阵计算和坐标转换,最终完成3D渲染。
万技师
2017/05/03
9.9K2
解剖 WebGL & Three.js 工作原理
WebGL基础笔记
片元着色器(Fragment Shader):顶点之间的轮廓中的所有像素都会经过片元着色器处理。(并行处理)
赤蓝紫
2023/01/02
1.2K0
WebGL基础笔记
Android OpenGL ES 基础原理
由于5G的发展,现在音视频越来越流行,我们的生活已经完全被抖音、视频号、B站等视频应用所包围。从这一点也能看到音视频的重要性。
Rouse
2023/02/14
1K0
Android OpenGL ES 基础原理
WebGL基础 - 笔记
光栅(Raster):几乎所有的现代图形系统都是基于光栅来绘制图形的,光栅就是指构成图像的像素阵列。
TagBug
2023/03/17
7680
WebGL基础 - 笔记
实用 WebGL 图像处理入门
技术社区里有种很有意思的现象,那就是不少人们口耳相传中的强大技术,往往因为上手难度高而显得曲高和寡。从这个角度看来,WebGL 和函数式编程有些类似,都属于优势已被论证了多年,却一直较为不温不火的技术。但是,一旦这些技术的易用性跨越了某个临界点,它们其实并没有那么遥不可及。这次我们就将以 WebGL 为例,尝试降低它的入门门槛,讲解它在前端图像处理领域的应用入门。
ConardLi
2020/02/23
3.2K0
相关推荐
【愚公系列】2023年08月 WEBGL专题-canvas和webgl的区别 | 技术创作特训营第一期
更多 >
领券
💥开发者 MCP广场重磅上线!
精选全网热门MCP server,让你的AI更好用 🚀
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
本文部分代码块支持一键运行,欢迎体验
本文部分代码块支持一键运行,欢迎体验