初识 WebGL | 青训营笔记

58 阅读2分钟

这是我参与【第四届青训营】笔记创作活动的第 14 天,今天学习了 WebGL 的一些知识点

1. WebGL 是什么?

GPU != WebGL != 3D

1.1 Modern Graphics System

  • 光栅(Raster): 几乎所有的线代图形系统都是基于光栅来绘制图形的,光栅就是指图像的像素阵列j。
  • 像素(Pixel): 一个像素对应图像上的一个点,它通常保存图像上的某个具体位置的颜色等信息。
  • 帧缓存(Frame Buffer): 在绘图过程中,像素信息被存放于帧缓存中,帧缓存是一块内存地址。
  • CPU(Central Processing Unit): 中央处理单元,负责逻辑计算。
  • GPU(Graphics Processing Unit): 图形处理单元,负责图形计算。

image.png

  1. 轮廓提取 / meshing
  2. 光栅化
  3. 帧缓存
  4. 渲染

image.png

1.2 The Pipeline

image.png

1.3 CPU vs GPU

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

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

每个运算单元彼此独立

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

2. WebGL & OpenGL

参考资料:web.eecs.umich.edu/~sugih/cour…

image.png

2.1 WebGl Startup

  1. 创建 WebGL 上下文
  2. 创建 WebGL program
  3. 将数据存入缓存区
  4. 将缓存区数据读取到 GPU
  5. CPU 执行 WebGL 程序,输出结果

image.png

2.1.1 Create WebGL Context

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) {
		name.unshift('webgl2')
	}
	let context = null
	for(let i = 0;i < names.length;i ++) {
		try {
			context =  canvas.getContext(name[i], options)
		} catch(e) {
			// no-empty
		}

		if(context) {
			break;
		}
	}
	return context;
}

2.1.2 The Shaders

  1. Vertex Shader
attribute vec2 position;

void main() {
	gl_PointSize = 1.0;
	gl_Position = vec4(positoin, 1.0, 1.0)
}

2 Fragment Shader

precision meduimp float;
void main() {
	gl_FranColor = vec4(1.0, 1.0, 0.0, 1.0)
}
  1. Create Program
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(fragment)

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

gl.useProgram(program)
  1. Data to Frame Buffer Axes image.png

Typed Array

const points = new Float32Array([
	-1,-1
	0,1,
	1,-1
])


const bufferId = gl.createBuffer()
gl.bindBuffer(gl.ARRAY_BUFFER, bufferId)
gl.bindData(gl.ARRAY_BUFFER, points, gl.STATIC_DRAW)

2.1.3 Frame Buffer to GPU

// 获取顶点着色器中搞得 position 变量的地址
const vPosition = gl.getAttribLoaction(program, 'position'(注意这里的postion,看下面的代码))
// 给变量设置长度和类型
gl.vertexAttribPointer(vPosition, 2, gl.FLOAT, false, 0, 0)
// 激活这个变量
gl.enableVertexAttribArray(vPosition)

上面的position

attribute vec2 position
void main(){
	gl_PointSize = 1.0
	gl_Position = vec4(position, 1.0, 1.0)
}

2.1.4 Output

l.clear(gl.COLOR_BUFFER_BIT)

gl.drawArrays(gl.TRIANGLES, 0, points.length / 2)

image.png

3. 2D vs WebGL

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()

3.1 Polygons

image.png

3.2 Triangulations

image.png

3.3 Draw Polygon with 2D triangulations

使用 Earcut 进行三角剖分 image.png

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)

4. 3D

4.1 Transforms

来学数学了!!!

4.1.1 平移

image.png

4.1.2 旋转

image.png

4.1.3 缩放

image.png

旋转 + 缩放是线性变换

image.png image.png

从线性变换到齐次矩阵 image.png

4.2 Apply Transforms

attribute vec2 position
uniform mat3 modelMatrix

void main(){
	gl_PointSize = 1.0
	vec3 pos = modelMatrix * vec3(position, 1.0)
	gl_Position = vec4(position, 1.0)
}
let tranform = gl.getUniformLocation(program, 'modelMatrix')

gl.uniformMatrix3fv(tranform, false,
					   [0.5, 0, 0,
						0, 0.5, 0,
						0, 0, 1
					   ])

4.3 3D Matrix

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

  1. 投影矩阵(Projection Matrix
  2. 模型矩阵(Model Matrix
  3. 视图矩阵(View Matrix
  4. 法向量矩阵(Normal Matrix

5. 参考资料

  1. thebookofshaders.com/
  2. Mesh.js
  3. glsl-doodle
  4. SpriteJS
  5. ThreeJS
  6. ShaderToy

总结

本文针对于 webGL 的基本概念和用法做了个简单的介绍,这部分的知识点十分的多,坑也很多,也特别难,如果想深入这方面的同学一定要多花时间去研究原理~