# webgl
WebGL仅仅是一个光栅化引擎,它可以根据你的代码绘制出点,线和三角形.
WebGL在电脑的GPU中运行。需要使用能够在GPU上运行的代码。 这样的代码需要提供成对的方法。每对方法中一个叫顶点着色器, 另一个叫片段着色器,并且使用一种和C或C++类似的强类型的语言 GLSL。 (GL着色语言)。 每一对组合起来称作一个 program(着色程序)。
顶点着色器的作用是计算顶点的位置。根据计算出的一系列顶点位置,WebGL可以对点, 线和三角形在内的一些图元进行光栅化处理。当对这些图元进行光栅化处理时需要使用片段着色器方法。 片段着色器的作用是计算出当前绘制图元中每个像素的颜色值。
对于想要绘制的每一个对象,都需要先设置一系列状态值,然后通过调用 gl.drawArrays 或 gl.drawElements 运行一个着色方法对,使得你的着色器对能够在GPU上运行。
# webgl创建一个点完整步骤
// 顶点着色器
const VertexSource = /* glsl */ `
void main() {
gl_Position = vec4(0.0, 0.0, 0.0, 1.0);
gl_PointSize = 50.0;
}
`
// 片元着色器
const FragSource = /* glsl */ `
void main() {
gl_FragColor = vec4(0.0, 0.0, 0.9, 1.0);
}
`
const canvas = document.querySelector("#c");
// 获取webgl
const gl = canvas.getContext("webgl");
// 设置 canvas 背景色(若无需变化颜色,则只需要设置一次即可)
gl.clearColor(0.0, 0.0, 0.0, 1.0);
// 清空 canvas
gl.clear(gl.COLOR_BUFFER_BIT);
// 顶点着色器
const vertexShader = gl.createShader(gl.VERTEX_SHADER);
//用于设置 WebGLShader 着色器(顶点着色器及片元着色器)的 GLSL 程序代码
gl.shaderSource(vertexShader, VertexSource);
// 编译
gl.compileShader(vertexShader);
// 片元着色器
const fragShader = gl.createShader(gl.FRAGMENT_SHADER);
gl.shaderSource(fragShader, FragSource);
gl.compileShader(fragShader);
// 创建着色器程序
const program = gl.createProgram();
// 为着色器程序赋予shader
gl.attachShader(program, vertexShader);
gl.attachShader(program, fragShader);
// 连接 顶点着色器 和 片元着色器
gl.linkProgram(program);
// 应用着色器程序
gl.useProgram(program);
// 绘制点
gl.drawArrays(gl.POINTS, 0, 1);
gl_Position的类型—— vec4 明显比 gl_PointSize 的 float 要特别。如果说需要的顶点坐标数据是 (x, y, z),那么好像也才只有 3 个浮点数,那第 4 个数是什么呢?
通常,添加 1.0 作为第四个参数 w,也就是 (x, y, z, 1.0)。由四个数组成的矢量叫做 齐次坐标,齐次坐标 (x, y, z, w) 其实等价于三维坐标 (x/w, y/w, z/w) 。抛开这么多复杂的概念,当前只需要明确一点:当使用齐次坐标表示三维顶点坐标时,最后一个值传 1.0 即可。
# webgl顶点数据获取
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1">
<title></title>
</head>
<body>
<canvas id='c' width='300' height='300'></canvas>
</body>
</html>
<script type="text/javascript">
const VertexSource = /* glsl */ `
attribute vec2 a_position ;
void main() {
gl_Position = vec4(a_position ,0.0,1.0);
gl_PointSize = 10.0;
}
`;
const FragSource = /* glsl */ `
void main() {
gl_FragColor = vec4(0.0, 0.0, 0.9, 1.0);
}
`;
const canvas = document.querySelector("#c");
const gl = canvas.getContext("webgl");
// 设置 canvas 背景色(若无需变化颜色,则只需要设置一次即可)
gl.clearColor(0.0, 0.0, 0.0, 1.0);
// 清空 canvas
gl.clear(gl.COLOR_BUFFER_BIT);
const vertexShader = gl.createShader(gl.VERTEX_SHADER);
gl.shaderSource(vertexShader, VertexSource);
gl.compileShader(vertexShader);
const fragShader = gl.createShader(gl.FRAGMENT_SHADER);
gl.shaderSource(fragShader, FragSource);
gl.compileShader(fragShader);
const program = gl.createProgram();
gl.attachShader(program, vertexShader);
gl.attachShader(program, fragShader);
gl.linkProgram(program);
gl.useProgram(program);
let a_position = gl.getAttribLocation(program, "a_position");
var vertexdata = new Float32Array([
0.5, 0.5,
-0.6,0.7,
0.8,0.9
])
//创建buffer
var vertexbuffer = gl.createBuffer();
//绑定
gl.bindBuffer(gl.ARRAY_BUFFER, vertexbuffer);
//灌入数据
gl.bufferData(gl.ARRAY_BUFFER,vertexdata,gl.STATIC_DRAW);
// 启用顶点属性
// 如果没有启用顶点属性数组(即没有调用 gl.enableVertexAttribArray),
//那么即使顶点着色器期望通过顶点属性(如 a_position)来接收数据,这些数据也不会被发送到着色器。
gl.enableVertexAttribArray(a_position);
// 它用于配置如何从当前绑定的 ARRAY_BUFFER 中读取顶点属性(attribute)数据,并将其传递给顶点着色器。
// 这个函数的参数详细说明了数据的格式、类型、步长和偏移量。
gl.vertexAttribPointer(a_position , 2, gl.FLOAT, false, 0, 0)
// a_position:这是之前通过 gl.getAttribLocation 获取的顶点属性(attribute)的位置索引。
// 它应该是对应于顶点着色器中 attribute vec2 a_position; 声明的索引。
//如果 "a_position" 是着色器中的第一个也是唯一一个属性,那么它的索引很可能是 0。
// 2:这是每个顶点属性中元素的数量。在你的例子中,每个顶点位置由两个浮点数(x和y坐标)组成,所以这里是 2。
// gl.FLOAT:这指定了数组中每个元素的数据类型。在你的例子中,数据是浮点数,所以使用 gl.FLOAT。
// false:这指定了是否应该将数据归一化到 [-1, 1] 的范围内。在例子中,由于正在处理顶点位置,这通常是不需要的,所以传递 false。
// 0:这是步长(stride),表示数组中连续顶点属性之间的字节数。
//在例子中,由于每个顶点只包含一个位置属性,并且每个位置属性占用两个浮点数(即8个字节,如果 Float32Array 被使用),
//且没有其他属性与它们交错,所以步长是 0 或者更常见的是,在这种情况下.
//可以显式地指定为 2 * Float32Array.BYTES_PER_ELEMENT(即 8),但 0 也会正常工作,
//因为WebGL能够推断出如果只有一个属性且没有其他交错,则步长应该是每个属性大小的倍数。
// 0:这是偏移量(offset),表示从当前绑定的 ARRAY_BUFFER 的开头到第一个元素起始位置的字节偏移量。
//在例子中,数据从缓冲区的开头开始,所以偏移量是 0。
//绘制
gl.drawArrays(gl.POINTS, 0, 3)
</script>
# 着色器获取数据的4种方法
- 属性(Attributes)和缓冲
缓冲是发送到GPU的一些二进制数据序列,通常情况下缓冲数据包括位置,法向量,纹理坐标,顶点颜色值等。 你可以存储任何数据。
属性用来指明怎么从缓冲中获取所需数据并将它提供给顶点着色器。 例如你可能在缓冲中用三个32位的浮点型数据存储一个位置值。 对于一个确切的属性你需要告诉它从哪个缓冲中获取数据,获取什么类型的数据(三个32位的浮点数据), 起始偏移值是多少,到下一个位置的字节数是多少。
缓冲不是随意读取的。事实上顶点着色器运行的次数是一个指定的确切数字, 每一次运行属性会从指定的缓冲中按照指定规则依次获取下一个值。
- 全局变量(Uniforms)
全局变量在着色程序运行前赋值,在运行过程中全局有效。
- 纹理(Textures)
纹理是一个数据序列,可以在着色程序运行中随意读取其中的数据。 大多数情况存放的是图像数据,但是纹理仅仅是数据序列, 你也可以随意存放除了颜色数据以外的其它数据。
- 可变量(Varyings)
可变量是一种顶点着色器给片段着色器传值的方式,依照渲染的图元是点, 线还是三角形,顶点着色器中设置的可变量会在片段着色器运行中获取不同的插值。
# WEBGL案例
无论画布有多大,裁剪空间的坐标范围永远是 -1 到 1 。
// 顶点着色器
// 一个属性值,将会从缓冲中获取数据
attribute vec4 a_position;
// 所有着色器都有一个main方法
void main() {
// gl_Position 是一个顶点着色器主要设置的变量
gl_Position = a_position;
}
// 片段着色器没有默认精度,所以我们需要设置一个精度
// mediump是一个不错的默认值,代表“medium precision”(中等精度)
precision mediump float;
void main() {
// gl_FragColor是一个片段着色器主要设置的变量
gl_FragColor = vec4(1, 0, 0.5, 1); // 返回“红紫色”
}
上方设置 gl_FragColor 为 1, 0, 0.5, 1,WebGL中的颜色值范围从 0 到 1 。
← cesiumAPI babylobjs基础 →