WebGL - 绘图模式

你好,未来的WebGL法师们!? 今天,我们将深入探索WebGL的绘图模式世界。作为你友好的邻里计算机老师,我将引导你完成这次旅程,即使你之前从未编写过一行代码。所以,拿起你的虚拟画笔,让我们来创作一些数字杰作吧!

WebGL - Modes of Drawing

模式参数(mode)

在我们开始绘制之前,让我们来谈谈我们节目的明星:mode参数。把它想象成魔杖,告诉WebGL如何连接点(或者在我们的例子中,顶点)来创建不同的形状和图案。

在WebGL中,当我们调用gl.drawArrays()gl.drawElements()函数时,我们需要指定一个mode参数。这个参数就像给连线谜题下达指令一样——它告诉WebGL如何连接我们定义的点。

以下是WebGL中可用的不同绘图模式的表格:

模式 描述
gl.POINTS 为每个顶点绘制一个点
gl.LINES 在每对顶点之间绘制一条线
gl.LINE_STRIP 绘制一条连续的线连接顶点
gl.LINE_LOOP 类似于LINE_STRIP,但闭合形状
gl.TRIANGLES 每三个顶点绘制一个三角形
gl.TRIANGLE_STRIP 绘制一个连接的三角形组
gl.TRIANGLE_FAN 绘制一个扇形形状的连接三角形

如果现在这些看起来很令人困惑,不用担心。我们将边走边看,用例子来探索每一个模式!

示例 - 绘制三条平行线

让我们从一个简单的例子开始:绘制三条平行线。这将帮助我们理解mode参数在实际中是如何工作的。

// 首先,让我们设置WebGL上下文
const canvas = document.getElementById('myCanvas');
const gl = canvas.getContext('webgl');

// 现在,让我们定义我们的顶点着色器
const vertexShaderSource = `
attribute vec2 a_position;
void main() {
gl_Position = vec4(a_position, 0.0, 1.0);
}
`;

// 以及我们的片段着色器
const fragmentShaderSource = `
precision mediump float;
void main() {
gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0); // 红色
}
`;

// 创建并编译着色器(别担心,我们将在未来的课程中详细解释这些)
const vertexShader = gl.createShader(gl.VERTEX_SHADER);
gl.shaderSource(vertexShader, vertexShaderSource);
gl.compileShader(vertexShader);

const fragmentShader = gl.createShader(gl.FRAGMENT_SHADER);
gl.shaderSource(fragmentShader, fragmentShaderSource);
gl.compileShader(fragmentShader);

// 创建一个程序并链接着色器
const program = gl.createProgram();
gl.attachShader(program, vertexShader);
gl.attachShader(program, fragmentShader);
gl.linkProgram(program);
gl.useProgram(program);

// 定义我们的线条位置
const positions = new Float32Array([
-0.8, -0.8,  // 线条1起点
-0.8,  0.8,  // 线条1终点
-0.3, -0.8,  // 线条2起点
-0.3,  0.8,  // 线条2终点
0.2, -0.8,  // 线条3起点
0.2,  0.8   // 线条3终点
]);

// 创建一个缓冲区并将位置放入其中
const positionBuffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, positionBuffer);
gl.bufferData(gl.ARRAY_BUFFER, positions, gl.STATIC_DRAW);

// 告诉WebGL如何读取缓冲区并将其属性分配给a_position
const positionAttributeLocation = gl.getAttribLocation(program, 'a_position');
gl.enableVertexAttribArray(positionAttributeLocation);
gl.vertexAttribPointer(positionAttributeLocation, 2, gl.FLOAT, false, 0, 0);

// 清除画布
gl.clearColor(0.0, 0.0, 0.0, 1.0);
gl.clear(gl.COLOR_BUFFER_BIT);

// 绘制线条
gl.drawArrays(gl.LINES, 0, 6);

现在,让我们分解一下:

  1. 我们设置了WebGL上下文并定义了我们的着色器。现在不要太担心这些;我们将在未来的课程中深入介绍着色器。

  2. 我们创建了一个程序并将我们的着色器链接到它。这就像准备我们的数字画笔。

  3. 我们定义了线条的位置。每条线由两个点(起点和终点)定义,每个点由两个坐标(x和y)定义。所以,我们的三条线总共有6个点。

  4. 我们创建了一个缓冲区并将我们的位置放入其中。可以把这想象成在画笔上装颜料。

  5. 我们告诉WebGL如何读取这个缓冲区并将其与顶点着色器中的a_position属性关联。

  6. 最后,我们调用gl.drawArrays(gl.LINES, 0, 6)。这就是魔法发生的地方!

  • gl.LINES是我们的模式。它告诉WebGL在顶点对之间绘制线条。
  • 0是我们位置数组中的起始索引。
  • 6是要考虑的顶点数(记得,我们有6个点组成3条线)。

运行这段代码,瞧!你应该会在黑色背景上看到三条红色的平行线。恭喜你,你刚刚创建了你的第一个WebGL绘图!?

绘图模式

既然我们已经看到了gl.LINES的实际应用,让我们探索一些其他的绘图模式。我们将使用之前的相同设置,但是更改位置和绘图模式。

gl.POINTS

让我们从最简单的模式开始:gl.POINTS。这个模式为每个顶点绘制一个点。

// ... (之前的设置代码)

const positions = new Float32Array([
-0.5, 0.5,
0.0, 0.0,
0.5, -0.5
]);

// ... (缓冲区设置代码)

gl.drawArrays(gl.POINTS, 0, 3);

这将在你画布上绘制三个红色的点。简单吧?

gl.LINE_STRIP

现在,让我们试试gl.LINE_STRIP。这个模式绘制一条连续的线,连接每个顶点到下一个。

// ... (之前的设置代码)

const positions = new Float32Array([
-0.5, 0.5,
0.0, -0.5,
0.5, 0.5
]);

// ... (缓冲区设置代码)

gl.drawArrays(gl.LINE_STRIP, 0, 3);

你应该会看到一条连接三个点的V形线。

gl.LINE_LOOP

gl.LINE_LOOPLINE_STRIP相似,但它通过连接最后一个顶点回到第一个顶点来闭合形状。

// ... (之前的设置代码)

const positions = new Float32Array([
-0.5, 0.5,
0.0, -0.5,
0.5, 0.5
]);

// ... (缓冲区设置代码)

gl.drawArrays(gl.LINE_LOOP, 0, 3);

这将绘制一个三角形轮廓。

gl.TRIANGLES

现在,让我们转到填充形状的gl.TRIANGLES。这个模式为每三个顶点绘制一个独立的三角形。

// ... (之前的设置代码)

const positions = new Float32Array([
-0.5, -0.5,
0.5, -0.5,
0.0, 0.5
]);

// ... (缓冲区设置代码)

gl.drawArrays(gl.TRIANGLES, 0, 3);

你应该会看到一个实心的红色三角形。

gl.TRIANGLE_STRIP

gl.TRIANGLE_STRIP稍微复杂一些。它绘制一个连接的三角形组,其中每个三角形与前一个三角形共享两个顶点。

// ... (之前的设置代码)

const positions = new Float32Array([
-0.5, -0.5,
0.5, -0.5,
-0.5, 0.5,
0.5, 0.5
]);

// ... (缓冲区设置代码)

gl.drawArrays(gl.TRIANGLE_STRIP, 0, 4);

这将绘制两个连接的三角形,形成一个矩形。

gl.TRIANGLE_FAN

最后,让我们看看gl.TRIANGLE_FAN。这个模式绘制一个扇形形状,其中所有三角形共享第一个顶点作为公共点。

// ... (之前的设置代码)

const positions = new Float32Array([
0.0, 0.0,    // 中心点
0.5, 0.0,    // 点1
0.35, 0.35,  // 点2
0.0, 0.5,    // 点3
-0.35, 0.35  // 点4
]);

// ... (缓冲区设置代码)

gl.drawArrays(gl.TRIANGLE_FAN, 0, 5);

这将绘制一个看起来有点像四分之一圆的形状。

就这样!我们已经探索了WebGL中的所有绘图模式。记住,掌握这些的关键是练习。尝试组合不同的模式,改变颜色,玩转顶点位置。在你意识到之前,你将能够轻松创建复杂的WebGL场景!

在下一课中,我们将更深入地研究着色器,并学习如何为我们的绘图添加颜色和纹理。在此之前,祝未来的WebGL艺术家们编程愉快!??‍??‍?

Credits: Image by storyset