WebGL三角形绘制:掌握缓冲区与基本图元

三角形图元的三种类型

在WebGL中,三角形是最基本的图元之一,但你知道吗?三角形有三种不同的绘制模式,每种都有其独特用途:

1. 基本三角形(TRIANGLES)

这是最常用的三角形绘制方式。每3个顶点构成一个独立的三角形,互不干扰。

javascript 复制代码
// 6个顶点绘制2个三角形
// [v1, v2, v3] 构成第一个三角形
// [v4, v5, v6] 构成第二个三角形
gl.drawArrays(gl.TRIANGLES, 0, 6); // 绘制2个三角形

绘制三角形数量 = 顶点数 ÷ 3

2. 三角带(TRIANGLE_STRIP)

相邻的三角形共享边,效率更高。

javascript 复制代码
// 6个顶点可以绘制4个三角形
// [v1, v2, v3], [v3, v2, v4], [v3, v4, v5], [v5, v4, v6]
gl.drawArrays(gl.TRIANGLE_STRIP, 0, 6); // 绘制4个三角形

绘制三角形数量 = 顶点数 - 2

3. 三角扇(TRIANGLE_FAN)

所有三角形都以第一个顶点为公共顶点。

javascript 复制代码
// 适用于绘制扇形或圆形
gl.drawArrays(gl.TRIANGLE_FAN, 0, 6); // 绘制4个三角形

绘制三角形数量 = 顶点数 - 2

绘制固定三角形

让我们从最简单的固定三角形开始:

着色器程序

顶点着色器:

glsl 复制代码
// 设置浮点数据类型为中级精度
precision mediump float;
// 接收顶点坐标 (x, y)
attribute vec2 a_Position;

void main(){
   gl_Position = vec4(a_Position, 0, 1);
}

片元着色器:

glsl 复制代码
// 设置浮点数据类型为中级精度
precision mediump float;
// 接收 JavaScript 传过来的颜色值(rgba)
uniform vec4 u_Color;

void main(){
   vec4 color = u_Color / vec4(255, 255, 255, 1);
   gl_FragColor = color;
}

JavaScript核心代码

javascript 复制代码
// 定义三角形的三个顶点(右下角、左上角、左下角)
var positions = [1, 0, 0, 1, 0, 0]; // 每两个数字代表一个顶点的x、y坐标

// 获取着色器变量位置
var a_Position = gl.getAttribLocation(program, 'a_Position');
var u_Color = gl.getUniformLocation(program, 'u_Color');

// 创建缓冲区
var buffer = gl.createBuffer();

// 绑定缓冲区为当前操作对象
gl.bindBuffer(gl.ARRAY_BUFFER, buffer);

// 将顶点数据写入缓冲区
// 注意:必须使用类型化数组(Float32Array)传递给WebGL
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(positions), gl.STATIC_DRAW);

// 启用顶点属性
gl.enableVertexAttribArray(a_Position);

// 配置顶点属性如何从缓冲区读取数据
var size = 2;        // 每次读取2个数据(x, y)
var type = gl.FLOAT; // 数据类型为浮点型
var normalize = false; // 不需要标准化
var stride = 0;      // 步长为0,表示数据连续存放
var offset = 0;      // 从缓冲区开始位置读取
gl.vertexAttribPointer(a_Position, size, type, normalize, stride, offset);

// 设置颜色并绘制
gl.uniform4f(u_Color, 255, 0, 0, 255); // 设置为红色

// 绘制三角形
gl.drawArrays(gl.TRIANGLES, 0, 3); // 绘制3个顶点,即1个三角形

缓冲区操作详解

WebGL中的缓冲区是向GPU传递数据的关键工具,以下是其工作流程:

1. 创建和绑定缓冲区

javascript 复制代码
// 创建缓冲区对象
var buffer = gl.createBuffer();

// 将缓冲区绑定到ARRAY_BUFFER目标
gl.bindBuffer(gl.ARRAY_BUFFER, buffer);

2. 向缓冲区写入数据

javascript 复制代码
// 使用类型化数组确保数据格式正确
var typedArray = new Float32Array([x1, y1, x2, y2, x3, y3]);
gl.bufferData(gl.ARRAY_BUFFER, typedArray, gl.STATIC_DRAW);

3. 配置顶点属性指针

javascript 复制代码
gl.enableVertexAttribArray(attributeLocation);
gl.vertexAttribPointer(
    attributeLocation, // attribute变量位置
    size,              // 每个顶点包含的分量数(2=x,y; 3=x,y,z)
    type,              // 数据类型
    normalize,         // 是否标准化
    stride,            // 步长
    offset             // 偏移量
);

重要提示: WebGL要求强类型数据,JavaScript中的普通数组必须转换为类型化数组(如Float32Array)才能传递给GPU。

动态绘制三角形

现在让我们实现一个交互式功能:点击三次鼠标绘制一个三角形。

增强版顶点着色器

glsl 复制代码
// 设置浮点数精度为中等精度
precision mediump float;
// 接收顶点坐标 (x, y)
attribute vec2 a_Position;
// 接收 canvas 的尺寸(width, height)
attribute vec2 a_Screen_Size;

void main(){
    // 将canvas坐标转换为NDC坐标(-1到1的范围)
    vec2 position = (a_Position / a_Screen_Size) * 2.0 - 1.0;
    position = position * vec2(1.0, -1.0); // 翻转Y轴
    gl_Position = vec4(position, 0, 1);
}

交互式JavaScript实现

javascript 复制代码
// 存储点击位置的数组
var positions = [];

// 绑定鼠标点击事件
canvas.addEventListener('mouseup', function(e) {
    var x = e.offsetX; // 相对于canvas的X坐标
    var y = e.offsetHeight - e.offsetY; // 转换Y坐标系统
    positions.push(x, y);
    
    // 当顶点数是6的倍数时(即3个点),绘制一个三角形
    if (positions.length % 6 === 0) {
        // 更新缓冲区数据
        gl.bindBuffer(gl.ARRAY_BUFFER, buffer);
        gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(positions), gl.DYNAMIC_DRAW);
        
        // 重新绘制所有三角形
        redraw();
    }
});

function redraw() {
    // 清空画布
    gl.clearColor(0, 0, 0, 1.0);
    gl.clear(gl.COLOR_BUFFER_BIT);
    
    // 绘制所有三角形
    gl.drawArrays(gl.TRIANGLES, 0, positions.length / 2);
}

核心概念总结

缓冲区操作流程

  1. gl.createBuffer() - 创建缓冲区对象
  2. gl.bindBuffer() - 绑定为当前操作缓冲区
  3. gl.bufferData() - 向缓冲区写入数据
  4. gl.enableVertexAttribArray() - 启用顶点属性
  5. gl.vertexAttribPointer() - 配置属性读取方式
  6. gl.drawArrays() - 执行绘制

类型化数组的重要性

  • JavaScript普通数组无法直接传递给WebGL
  • 必须使用Float32Array等类型化数组
  • 确保数据格式与GPU要求一致

坐标转换

  • Canvas坐标系:左上角(0,0),Y轴向下
  • WebGL坐标系:中心(0,0),Y轴向上
  • 需要进行坐标转换才能正确显示

掌握了三角形绘制和缓冲区操作,你就迈出了WebGL高级渲染的第一步!接下来可以尝试绘制更多有趣的图形。

相关推荐
mCell5 小时前
如何零成本搭建个人站点
前端·程序员·github
mCell6 小时前
为什么 Memo Code 先做 CLI:以及终端输入框到底有多难搞
前端·设计模式·agent
恋猫de小郭6 小时前
AI 在提高你工作效率的同时,也一直在增加你的疲惫和焦虑
前端·人工智能·ai编程
少云清6 小时前
【安全测试】2_客户端脚本安全测试 _XSS和CSRF
前端·xss·csrf
银烛木6 小时前
黑马程序员前端h5+css3
前端·css·css3
m0_607076607 小时前
CSS3 转换,快手前端面试经验,隔壁都馋哭了
前端·面试·css3
听海边涛声7 小时前
CSS3 图片模糊处理
前端·css·css3
IT、木易7 小时前
css3 backdrop-filter 在移动端 Safari 上导致渲染性能急剧下降的优化方案有哪些?
前端·css3·safari
0思必得07 小时前
[Web自动化] Selenium无头模式
前端·爬虫·selenium·自动化·web自动化
anOnion7 小时前
构建无障碍组件之Dialog Pattern
前端·html·交互设计