封装一套 WebGL 渲染引擎是一个既有挑战又充满乐趣的项目。下面将为你提供一个基础教程,介绍如何从头开始构建一个简单的 WebGL 渲染引擎。这个引擎将实现基本的图形渲染功能,并逐步扩展功能,最终支持三维模型、材质和光照等内容。
GitHub 地址:github.com/FrankWangMi…
跪求 Star 哈哈哈
1. 环境准备
确保你有一个支持 WebGL 的浏览器(例如 Google Chrome 或 Firefox),并且你已经具备 HTML 和 JavaScript 的基础知识。你可以使用任何文本编辑器来编写代码,比如 VS Code。
2. 创建 HTML 文件
首先,创建一个基础的 HTML 文件来包含我们的 WebGL 渲染引擎:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>WebGL 渲染引擎</title>
<style>
body, html {
margin: 0;
height: 100%;
display: flex;
justify-content: center;
align-items: center;
}
canvas {
border: 1px solid black;
}
</style>
</head>
<body>
<canvas id="webgl-canvas"></canvas>
<script src="engine.js"></script>
</body>
</html>
在这个文件中,我们创建了一个 canvas 元素,它将用于渲染 WebGL 内容。接下来,我们将在 engine.js 中编写 WebGL 渲染引擎的代码。
3. 设置 WebGL 环境
接下来,我们将初始化 WebGL 上下文,并设置一些基本的渲染配置。
// engine.js
const canvas = document.getElementById('webgl-canvas');
const gl = canvas.getContext('webgl');
if (!gl) {
alert('WebGL 未被支持!');
}
// 设置画布大小
canvas.width = window.innerWidth;
canvas.height = window.innerHeight;
// 清除屏幕,设置背景色
gl.clearColor(0.0, 0.0, 0.0, 1.0); // 黑色背景
gl.clear(gl.COLOR_BUFFER_BIT);
在这段代码中,我们首先通过 getContext('webgl') 获取 WebGL 上下文,然后设置画布的尺寸,最后使用 clearColor 和 clear 函数清除画布并设置背景色。
4. 创建着色器
WebGL 需要着色器(Shader)来定义如何渲染对象。我们将创建一个简单的顶点着色器和一个片段着色器。
顶点着色器(Vertex Shader)
const vertexShaderSource = `
attribute vec4 a_position;
void main(void) {
gl_Position = a_position;
}
`;
片段着色器(Fragment Shader)
const fragmentShaderSource = `
void main(void) {
gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0); // 红色
}
`;
5. 编译着色器和创建程序
接下来,我们需要编译着色器,并将它们链接成一个程序。
// 编译着色器
function compileShader(source, type) {
const shader = gl.createShader(type);
gl.shaderSource(shader, source);
gl.compileShader(shader);
if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS)) {
console.error("Shader 编译失败:", gl.getShaderInfoLog(shader));
gl.deleteShader(shader);
return null;
}
return shader;
}
// 创建着色器程序
const vertexShader = compileShader(vertexShaderSource, gl.VERTEX_SHADER);
const fragmentShader = compileShader(fragmentShaderSource, gl.FRAGMENT_SHADER);
const program = gl.createProgram();
gl.attachShader(program, vertexShader);
gl.attachShader(program, fragmentShader);
gl.linkProgram(program);
if (!gl.getProgramParameter(program, gl.LINK_STATUS)) {
console.error("程序链接失败:", gl.getProgramInfoLog(program));
}
gl.useProgram(program);
6. 创建一个简单的矩形
为了测试渲染效果,我们可以创建一个简单的矩形。
// 创建顶点数据
const vertices = new Float32Array([
-0.5, 0.5,
-0.5, -0.5,
0.5, 0.5,
0.5, -0.5,
]);
// 创建缓冲区并将数据传递到 WebGL
const vertexBuffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, vertexBuffer);
gl.bufferData(gl.ARRAY_BUFFER, vertices, gl.STATIC_DRAW);
// 获取 a_position 属性位置并启用
const positionAttribLocation = gl.getAttribLocation(program, "a_position");
gl.vertexAttribPointer(positionAttribLocation, 2, gl.FLOAT, false, 0, 0);
gl.enableVertexAttribArray(positionAttribLocation);
7. 渲染图形
最后,调用 drawArrays 函数来渲染矩形。
gl.clear(gl.COLOR_BUFFER_BIT);
gl.drawArrays(gl.TRIANGLE_STRIP, 0, 4);
8. 完整代码
将上面所有步骤合并到一起,你将得到一个简单的 WebGL 渲染引擎,它可以渲染一个红色的矩形。
// engine.js
const canvas = document.getElementById('webgl-canvas');
const gl = canvas.getContext('webgl');
if (!gl) {
alert('WebGL 未被支持!');
}
canvas.width = window.innerWidth;
canvas.height = window.innerHeight;
gl.clearColor(0.0, 0.0, 0.0, 1.0); // 黑色背景
gl.clear(gl.COLOR_BUFFER_BIT);
// 顶点着色器
const vertexShaderSource = `
attribute vec4 a_position;
void main(void) {
gl_Position = a_position;
}
`;
// 片段着色器
const fragmentShaderSource = `
void main(void) {
gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0); // 红色
}
`;
// 编译着色器
function compileShader(source, type) {
const shader = gl.createShader(type);
gl.shaderSource(shader, source);
gl.compileShader(shader);
if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS)) {
console.error("Shader 编译失败:", gl.getShaderInfoLog(shader));
gl.deleteShader(shader);
return null;
}
return shader;
}
// 创建着色器程序
const vertexShader = compileShader(vertexShaderSource, gl.VERTEX_SHADER);
const fragmentShader = compileShader(fragmentShaderSource, gl.FRAGMENT_SHADER);
const program = gl.createProgram();
gl.attachShader(program, vertexShader);
gl.attachShader(program, fragmentShader);
gl.linkProgram(program);
if (!gl.getProgramParameter(program, gl.LINK_STATUS)) {
console.error("程序链接失败:", gl.getProgramInfoLog(program));
}
gl.useProgram(program);
// 创建顶点数据
const vertices = new Float32Array([
-0.5, 0.5,
-0.5, -0.5,
0.5, 0.5,
0.5, -0.5,
]);
// 创建缓冲区并将数据传递到 WebGL
const vertexBuffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, vertexBuffer);
gl.bufferData(gl.ARRAY_BUFFER, vertices, gl.STATIC_DRAW);
// 获取 a_position 属性位置并启用
const positionAttribLocation = gl.getAttribLocation(program, "a_position");
gl.vertexAttribPointer(positionAttribLocation, 2, gl.FLOAT, false, 0, 0);
gl.enableVertexAttribArray(positionAttribLocation);
// 渲染图形
gl.clear(gl.COLOR_BUFFER_BIT);
gl.drawArrays(gl.TRIANGLE_STRIP, 0, 4);
9. 后续扩展
- 加载模型: 可以添加支持加载 3D 模型的功能(如 .obj 或 .glTF 格式)。
- 光照和材质: 实现不同的光照模型(如 Phong 光照)和支持材质贴图。
- 相机和投影: 实现相机和视图变换功能。
- 性能优化: 优化渲染性能,比如使用 VAO(Vertex Array Object)和 VBO(Vertex Buffer Object)进行批量渲染。
这只是一个基础的框架,你可以根据需求逐步扩展它,加入更多功能和优化。