绘制基本图形:三角形与矩形
一、缓冲区对象
在WebGL中,缓冲区对象(Buffer Objects)用于存储顶点数据,这些数据可以是顶点的位置、颜色、纹理坐标等。通过将顶点数据存储在缓冲区对象中,可以高效地传递数据到GPU,从而提高渲染性能。
(一)创建和绑定缓冲区对象
缓冲区对象的创建和绑定是通过gl.createBuffer
和gl.bindBuffer
完成的。以下是一个简单的示例:
javascript
// 创建缓冲区对象
const buffer = gl.createBuffer();
// 绑定缓冲区对象
gl.bindBuffer(gl.ARRAY_BUFFER, buffer);
// 将顶点数据存储到缓冲区对象中
const vertices = [
-0.5, -0.5,
0.5, -0.5,
0.0, 0.5
];
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(vertices), gl.STATIC_DRAW);
gl.createBuffer
:创建一个新的缓冲区对象。gl.bindBuffer
:将缓冲区对象绑定到一个目标(如gl.ARRAY_BUFFER
)。gl.bufferData
:将数据存储到当前绑定的缓冲区对象中。gl.STATIC_DRAW
表示数据不会频繁更改。
二、绘制三角形
(一)设置顶点数据
绘制三角形需要定义三个顶点的位置。以下是一个完整的示例,展示如何设置顶点数据并绘制一个三角形:
html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>WebGL Triangle Example</title>
</head>
<body>
<canvas id="webglCanvas" width="800" height="600"></canvas>
<script>
const canvas = document.getElementById('webglCanvas');
const gl = canvas.getContext('webgl');
if (!gl) {
alert('Your browser does not support 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);
if (!gl.getProgramParameter(program, gl.LINK_STATUS)) {
alert('Unable to initialize the shader program: ' + gl.getProgramInfoLog(program));
}
// 使用程序
gl.useProgram(program);
// 定义顶点数据
const vertices = [
-0.5, -0.5,
0.5, -0.5,
0.0, 0.5
];
// 创建缓冲区对象
const buffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, buffer);
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(vertices), gl.STATIC_DRAW);
// 获取attribute变量的位置
const positionLocation = gl.getAttribLocation(program, 'a_position');
// 绑定缓冲区到attribute变量
gl.enableVertexAttribArray(positionLocation);
gl.vertexAttribPointer(positionLocation, 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.TRIANGLES, 0, 3);
</script>
</body>
</html>
(二)代码解析
- 顶点数据:定义了三角形的三个顶点位置。
- 缓冲区对象:将顶点数据存储到缓冲区对象中。
- 顶点着色器:将顶点位置传递到
gl_Position
。 - 片元着色器:设置片元颜色为红色。
- 绘制命令:
gl.drawArrays
用于绘制三角形。
三、绘制矩形
矩形可以通过两个三角形组成。以下是一个完整的示例,展示如何绘制一个矩形:
html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>WebGL Rectangle Example</title>
</head>
<body>
<canvas id="webglCanvas" width="800" height="600"></canvas>
<script>
const canvas = document.getElementById('webglCanvas');
const gl = canvas.getContext('webgl');
if (!gl) {
alert('Your browser does not support 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(0.0, 1.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);
if (!gl.getProgramParameter(program, gl.LINK_STATUS)) {
alert('Unable to initialize the shader program: ' + gl.getProgramInfoLog(program));
}
// 使用程序
gl.useProgram(program);
// 定义顶点数据
const vertices = [
-0.5, -0.5, // 左下
0.5, -0.5, // 右下
0.5, 0.5, // 右上
-0.5, 0.5 // 左上
];
// 创建缓冲区对象
const buffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, buffer);
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(vertices), gl.STATIC_DRAW);
// 获取attribute变量的位置
const positionLocation = gl.getAttribLocation(program, 'a_position');
// 绑定缓冲区到attribute变量
gl.enableVertexAttribArray(positionLocation);
gl.vertexAttribPointer(positionLocation, 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.TRIANGLE_FAN, 0, 4);
</script>
</body>
</html>
(二)代码解析
- 顶点数据:定义了矩形的四个顶点位置。
- 缓冲区对象:将顶点数据存储到缓冲区对象中。
- 顶点着色器:将顶点位置传递到
gl_Position
。 - 片元着色器:设置片元颜色为绿色。
- 绘制命令:
gl.drawArrays
使用gl.TRIANGLE_FAN
模式绘制两个三角形,组成一个矩形。
四、索引绘制
索引绘制是一种优化技术,通过使用索引缓冲区来减少重复的顶点数据。以下是一个完整的示例,展示如何使用索引绘制矩形:
html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>WebGL Indexed Rectangle Example</title>
</head>
<body>
<canvas id="webglCanvas" width="800" height="600"></canvas>
<script>
const canvas = document.getElementById('webglCanvas');
const gl = canvas.getContext('webgl');
if (!gl) {
alert('Your browser does not support 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(0.0, 0.0, 1.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);
if (!gl.getProgramParameter(program, gl.LINK_STATUS)) {
alert('Unable to initialize the shader program: ' + gl.getProgramInfoLog(program));
}
// 使用程序
gl.useProgram(program);
// 定义顶点数据
const vertices = [
-0.5, -0.5, // 左下
0.5, -0.5, // 右下
0.5, 0.5, // 右上
-0.5, 0.5 // 左上
];
// 创建顶点缓冲区对象
const vertexBuffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, vertexBuffer);
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(vertices), gl.STATIC_DRAW);
// 获取attribute变量的位置
const positionLocation = gl.getAttribLocation(program, 'a_position');
// 绑定缓冲区到attribute变量
gl.enableVertexAttribArray(positionLocation);
gl.vertexAttribPointer(positionLocation, 2, gl.FLOAT, false, 0, 0);
// 定义索引数据
const indices = [
0, 1, 2, // 第一个三角形
0, 2, 3 // 第二个三角形
];
// 创建索引缓冲区对象
const indexBuffer = gl.createBuffer();
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, indexBuffer);
gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, new Uint16Array(indices), gl.STATIC_DRAW);
// 清空画布
gl.clearColor(0.0, 0.0, 0.0, 1.0); // 设置背景颜色为黑色
gl.clear(gl.COLOR_BUFFER_BIT);
// 绘制矩形(使用索引绘制)
gl.drawElements(gl.TRIANGLES, indices.length, gl.UNSIGNED_SHORT, 0);
</script>
</body>
</html>
(二)代码解析
- 顶点数据:定义了矩形的四个顶点位置。
- 索引数据:定义了两个三角形的顶点索引。
- 顶点缓冲区对象:将顶点数据存储到缓冲区对象中。
- 索引缓冲区对象:将索引数据存储到缓冲区对象中。
- 顶点着色器:将顶点位置传递到
gl_Position
。 - 片元着色器:设置片元颜色为蓝色。
- 绘制命令:
gl.drawElements
使用索引缓冲区绘制两个三角形,组成一个矩形。
总结
通过缓冲区对象存储顶点数据,可以高效地将数据传递到GPU。绘制三角形和矩形是WebGL的基础操作,而索引绘制则是一种优化技术,可以减少重复的顶点数据,提高渲染性能。掌握这些基本操作后,你可以开始探索更复杂的图形渲染技术。