前端学习记录
  • 前言及目录
  • 前端基础
    • HTML
    • CSS
      • CSS学习之布局
    • JavaScript
      • 跟着月影学JavaScript
      • JavaScript之对象、原型链及继承
      • JavaScript中的类
      • onclick与addEventListener区别
      • JS手撕题
    • HTTP与浏览器
      • HTTP实用指南
      • Web开发的安全之旅
    • 通用知识
      • 前端必须知道的开发调试知识
      • 前端设计模式应用
      • Web 标准与前端开发
  • 数据结构及算法
    • 数据结构
      • 1、线性表(List)
      • 2、堆栈(Stack)
      • 3、队列(Queue)
      • 4、二叉树(Binary Tree)
      • 5、二叉搜索树与平衡二叉树(BST & AVL)
      • 6、堆(Stack)& 哈夫曼树 & 并查集
      • 7、图(Graph)
        • 图论——解决最小生成树问题(Kruskal算法&Prim算法)
      • 8、排序(sort)
      • 9、散列表(hash)
      • 数据结构习题
        • 第一周:最大子列和算法、二分查找
        • 第二周:线性结构
        • 第三周:栽树(二叉树等)
        • 第四周:二叉搜索树&二叉平衡树
        • 第五周:堆&哈夫曼树&并查集
        • 第六周:图(上)连通集 、DFS&BFS
        • 第七周:图(中)Floyd算法求最短路
        • 第八周:图(下)
        • 第九周:排序(上)归并&堆排序
        • 第十周:排序(下)
        • 第十一周:散列查找 & KMP
    • CS基础
      • 编译原理 实验一 词法分析器设计
      • 编译原理 实验二 LL(1)分析法程序
    • LeetCode
      • 冲刺春招-精选笔面试 66 题大通关
        • day1:21. 合并两个有序链表、146. LRU 缓存、25. K 个一组翻转链表
        • day2:14. 最长公共前缀、3. 无重复字符的最长子串、124. 二叉树中的最大路径和
        • day3:206. 反转链表、199. 二叉树的右视图、bytedance-016最短移动距离
        • day4:1. 两数之和、15. 三数之和、42. 接雨水
        • day5:7. 整数反转、215. 数组中的第K个最大元素、23. 合并K个升序链表
        • day6:33. 搜索旋转排序数组、54. 螺旋矩阵、bytedance-006. 夏季特惠
        • day7:53. 最大子数组和、152. 乘积最大子数组、41. 缺失的第一个正数
        • day8:20. 有效的括号、200. 岛屿数量、76. 最小覆盖子串
        • day9:105. 从前序与中序遍历序列构造二叉树、103. 二叉树的锯齿形层序遍历、bytedance-010. 数组组成最大数
        • day10:94. 二叉树的中序遍历、102. 二叉树的层序遍历、394. 字符串解码
        • day11:415. 字符串相加、5. 最长回文子串、72. 编辑距离
        • day12:64. 最小路径和、300. 最长递增子序列、bytedance-004. 机器人跳跃问题
        • day13:88. 合并两个有序数组、31. 下一个排列、4. 寻找两个正序数组的中位数
        • day14:121. 买卖股票的最佳时机、56. 合并区间、135. 分发糖果
        • day15:232. 用栈实现队列、22. 括号生成、128. 最长连续序列
        • day16:bytedance-007. 化学公式解析、129. 求根节点到叶节点数字之和、239. 滑动窗口最大值
        • day17:141. 环形链表、236. 二叉树的最近公共祖先、92. 反转链表 II
        • day18:322. 零钱兑换、198. 打家劫舍、 bytedance-003. 古生物血缘远近判定
        • day19:160. 相交链表、143. 重排链表、142. 环形链表 II
        • day20:704. 二分查找、43. 字符串相乘、bytedance-002. 发下午茶
        • day21题目:69. x 的平方根、912. 排序数组、887. 鸡蛋掉落
        • day22:151. 颠倒字符串中的单词、46. 全排列、2. 两数相加
      • 剑指 Offer
        • 剑指offer day1 栈与队列(简单)
        • 剑指offer day2 链表(简单)
        • 剑指offer day3 字符串(简单)
        • 剑指offer day4 查找算法(简单)
        • 剑指offer day5 查找算法(中等)
        • 剑指offer day6 搜索与回溯算法(简单)
        • 剑指offer day7 搜索与回溯算法(简单)
        • 剑指offer day8 动态规划(简单)
        • 剑指offer day9 动态规划(中等)
        • 剑指offer day10 动态规划(中等)
        • 剑指offer day11 双指针(简单)
        • 剑指offer day12 双指针(简单)
        • 剑指offer day13 双指针(简单)
        • 剑指offer day14 搜索与回溯算法(中等)
        • 剑指offer day15 搜索与回溯算法(中等)
        • 剑指offer day16 排序(简单)
        • 剑指offer day17 排序(中等)
      • 剑指 Offer 专项突击版
  • 前端进阶
    • React
      • 响应式系统与 React
      • React学习小记
      • Redux学习之Redux三原则、createSore原理及实现
    • Vue
    • TypeScript
      • TypeScript入门
      • TypeScript 类型体操练习
        • Easy题(13/13)
        • Middle(20/72)
    • 前端工程化
      • Webpack知识体系
    • Node
    • 前端动画与绘图
      • WebGL基础
      • 前端动画简介
      • Floating UI 使用经验分享 - Popover
      • Floating UI 使用经验分享 - Dialog
      • Three.js 学习
        • 学习记录
        • 资源记录
    • 前端性能优化
    • 跨端
      • RN 学习小记之使用 Expo 创建项目
    • 开源
    • SEO 优化
      • 搜索引擎优化 (SEO) 新手指南笔记
  • 笔面试记录
    • 面经集锦
      • 2022春暑期实习MetaApp一二面面经
      • 2022春暑期实习字节前端一面凉经
    • 笔试复盘
      • 2022春暑期实习-美团前端-笔试
      • 2022春暑期实习-360前端-笔试(AK)
      • 2022春暑期实习-京东前端-笔试
      • 2022春暑期实习-网易雷火前端-笔试(AK)
      • 2022春暑期实习-网易互联网前端-暑期实习笔试
由 GitBook 提供支持
在本页
  • Why WebGL / Why GPU?
  • 现代的图像系统
  • The Pipeline
  • GPU
  • WebGL & OpenGL关系
  • WebGL绘图步骤
  • 创建WebGL上下文
  • 创建WebGL Program(The Shaders)
  • 将数据存到缓冲区中(Data to Frame Buffer)
  • 读取缓冲区数据到GPU(Frame Buffer to GPU)
  • 输出结果(Output)
  • WebGL太复杂?其他方式
  • canvas 2D
  • Mesh.js
  • Earcut
  • 3D Meshing
  • 图形变换(Transforms)
  • 平移
  • 旋转
  • 缩放
  • 线性变换(旋转+缩放)
  • 3D Matrix
  • Read more
  • 总结感想

这有帮助吗?

在GitHub上编辑
导出为 PDF
  1. 前端进阶
  2. 前端动画与绘图

WebGL基础

【第二届青训营-寒假前端场】- 「WebGL基础」,这节课老师非常详尽的讲解了WebGL的绘图及其相关库,展示了很多有意思的WebGL小项目

上一页前端动画与绘图下一页前端动画简介

最后更新于1年前

这有帮助吗?

Why WebGL / Why GPU?

  • WebGL是什么?

    • GPU ≠ WebGL ≠ 3D

  • WebGL为什么不像其他前端技术那么简单?

现代的图像系统

  • 光栅(Raster):几乎所有的现代图形系统都是基于光栅来绘制图形的,光栅就是指构成图像的像素阵列。

  • 像素(Pixel):一个像素对应图像上的一个点,它通常保存图像上的某个具体位置的颜色等信息。

  • 帧缓存(Frame Buffer):在绘图过程中,像素信息被存放于帧缓存中,帧缓存是一块内存地址。

  • CPU (Central Processing Unit):中央处理单元,负责逻辑计算。

  • GPU (Graphics Processing Unit):图形处理单元,负责图形计算。

image.png
  • 如上图,现代图像的渲染如图过程

  1. 轮廓提取/ meshing

  2. 光栅化

  3. 帧缓存

  4. 渲染

The Pipeline

GPU

  • GPU由大量的小运算单元构成

  • 每个运算单元只负责处理很简单的计算

  • 每个运算单元彼此独立

  • 因此所有计算可以并行处理

WebGL & OpenGL关系

WebGL绘图步骤

步骤

  1. 创建WebGL上下文

  2. 创建WebGL Program

  3. 将数据存入缓冲区

  4. 将缓冲区数据读取到GPU

  5. GPU执行WebGL程序,输出结果

如图,针对几个单词进行解释:

  • Raw Vertices & Primitives 原始顶点&原语

  • Vertex Processor 顶点着色器

  • 运算后送到 片元着色器 进行处理:Fragment Processor

创建WebGL上下文

const canvas = document.querySelector('canvas');
const gl = canvas.getContext('webgl');
// 创建上下文, 注意兼容
function create3DContext(canvas, options) {
    const names = ['webgl', 'experimental-webgL','webkit-3d','moz-webgl'];  // 特性判断
    if(options.webgl2) names.unshift(webgl2);
    let context = null;
    for(let ii = 0; ii < names.length; ++ii) {
        try {
            context = canvas.getContext(names[ii], options);
        } catch(e) {
            // no-empty
        }
        if(context) {
            break;
        }
    }
    return context;
}

创建WebGL Program(The Shaders)

  1. Vertex Shader(顶点着色器)

    通过类型数组position,并行处理每个顶点的位置

    attribute vec2 position;// vec2 二维向量
    void main() {
        gl_PointSize = 1.0;
        gl_Position = vec4(position, 1.0, 1.0);
    }
  2. Fragment Shader(片元着色器)

    为顶点轮廓包围的区域内所有像素进行着色

    precision mediump float;
    void main() {
        gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0);//对应rgba(255,0,0,1.0),红色
    }

其具体步骤如下:

  1. 创建顶点着色器和片元着色器代码:

    // 顶点着色器程序代码
    const vertexShaderCode = `
    attribute vec2 position;
    void main() {
        gl_PointSize = 1.0;
        gl_Position = vec4(position, 1.0, 1.0);
    }
    `;
    // 片元着色器程序代码
    const fragmentShaderCode = `
    precision mediump float;
    void main() {
        gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0);
    }
    `;
  2. // 顶点着色器
    const vertexShader = gl.createShader(gl.VERTEX_SHADER);
    gl.shaderSource(vertexShader, vertex);
    gl.compileShader(vertexShader);
    // 片元着色器
    const fragmentShader = gl.createShader(gl.FRAGMENT_SHADER);
    gl.shaderSource(fragmentShader, fragment);
    gl.compileShader(fragmentShader);
  3. // 创建着色器程序并链接
    const program = gl.createProgram();
    gl.attachShader(program, vertexShader);
    gl.attachShader(program, fragmentShader);
    gl.linkProgram(program);
    
    gl.useProgram(program);

将数据存到缓冲区中(Data to Frame Buffer)

  • 坐标轴:webGL的坐标系统是归一化的,浏览器和canvas2D的坐标系统是以左上角为坐标原点,y轴向下,x轴向右,坐标值相对于原点。而webGL的坐标系是以绘制画布的中心点为原点,正常的笛卡尔坐标系。

// 顶点数据
const points = new Float32Array([
    -1, -1,
    0, 1,
    1, -1,
]);
// 创建缓冲区
const bufferId = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, bufferId);
gl.bufferData(gl.ARRAY_BUFFER, points, gl.STATIC_DRAW);

读取缓冲区数据到GPU(Frame Buffer to GPU)

const vPosition = gl.getAttribLocation(program, 'position'); // 获取顶点着色器中的position变量的地址
gl.vertexAttribPointer(vPosition, 2, gl.FLOAT, false, 0, 0); // 给变量设置长度和类型
gl.enableVertexAttribArray(vPosition); // 激活这个变量

输出结果(Output)

// output
gl.clear(gl.COLOR_BUFFER_BIT);  //清除缓冲的数据
gl.drawArrays(gl.TRIANGLES, 0, points.length / 2);

WebGL太复杂?其他方式

canvas 2D

看看人家canvas2D,绘制同样的三角形:

// canvas 简单粗暴,都封装好了
const canvas = document.querySelector('canvas');
const ctx = canvas.getContext('2d');
ctx.beginPath();
ctx.moveTo(250, 0);
ctx.lineTo(500, 500);
ctx.lineTo(0, 500);
ctx.fillStyle = 'red';
ctx.fill();

Mesh.js

const {Renderer, Figure2D, Mesh2D} = meshjs;
const canvas = document.querySelector ('canvas');
const renderer = new Renderer(canvas);

const figure = new Figure2D();
figurie.beginPath();
figure.moveTo(250, 0);
figure.lineTo(500,500);
figure.lineTo(0, 500);
const mesh = new Mesh2D(figure, canvas);
mesh.setFill({
    color: [1, 0, 0, 1],
});
renderer.drawMeshes([mesh]);

Earcut

const vertices = [
    [-0.7, 0.5],
    [-0.4, 0.3],
    [-0.25, 0.71],
    [-0.1, 0.56],
    [-0.1, 0.13],
    [0.4, 0.21],
    [0, -0.6],
    [-0.3, -0.3],
    [-0.6, -0.3],
    [-0.45, 0.0],
];
const points = vertices.flat();
const triangles = earcut(points)

3D Meshing

由设计师导出给我们,再提取

图形变换(Transforms)

这就是数字图像处理相关的知识了(学过的都还回来了.jpg)

平移

旋转

缩放

线性变换(旋转+缩放)

从线性变换到齐次矩阵

3D Matrix

3D标准模型的四个齐次矩阵(mat4)

  1. 投影矩阵Projection Matrix(正交投影和透视投影)

  2. 模型矩阵Model Matrix (对顶点进行变换Transform)

  3. 视图矩阵View Matrix(3D的视角,想象成一个相机,在相机的视口下)

  4. 法向量矩阵Normal Matrix(垂直于物体表面的法向量,通常用于计算物体光照)

Read more

总结感想

这节课老师非常详尽的讲解了WebGL的绘图及其相关库,展示了很多有意思的WebGL小项目~

本文引用的大部分内容来自月影老师的课和MDN!月影老师,tql!

image.png

image.png
image.png

使用 创建着色器对象

使用 设置着色器的程序代码

使用 编译一个着色器

使用**** 创建 对象

使用 往 添加一个片段或者顶点着色器。

使用 ****链接给定的,从而完成为程序的片元和顶点着色器准备GPU代码的过程。

使用 将定义好的 对象添加到当前的渲染状态

通过一个顶点数组表示其顶点,使用 创建并初始化一个用于储存顶点数据或着色数据的对象并返回bufferId,然后使用 将给定的 bufferId 绑定到目标并返回,最后使用****,将数据绑定至buffer中。

返回了给定对象中某属性的下标指向位置。

告诉显卡从当前绑定的缓冲区(bindBuffer()指定的缓冲区)中读取顶点数据。

可以打开属性数组列表中指定索引处的通用顶点属性数组。

从向量数组中绘制图元

image.png

使用进行三角剖分

image.png
image.png
image.png
image.png
image.png
image.png

老师的又一个栗子:

(介绍片元着色器,非常好玩的)

(底层库,欸嘿)

(片元着色器的一个轻量库,有很多小demo)

(月影老师写的开源库orz)

(很多有意思的游戏项目)

(很多有意思的项目)

OpenGL, OpenGL ES, WebGL, GLSL, GLSL ES API Tables (umich.edu)
createShader()
shaderSource()
compileShader()
createProgram()
WebGLProgram
attachShader()
WebGLProgram
linkProgram()
WebGLProgram
useProgram()
WebGLProgram
createBuffer()
WebGLBuffer
bindBuffer()
bufferData()
getAttribLocation()
WebGLProgram
vertexAttribPointer()
enableVertexAttribArray()
Output
drawArrays()
mesh-js/mesh.js: A graphics system born for visualization 😘. (github.com)
Earcut
SpriteJS/next - The next generation of spritejs.
Apply Transforms
The Book of Shaders
Mesh.js
Glsl Doodle
SpriteJS
Three.js
Shadertoy BETA