基于JavaScript的OpenGL 01 之Hello Triangle
1. 引言
本文基于JavaScript语言,描述OpenGL(即,WebGL)的绘制流程,这里描述的是OpenGL的核心模式(Core-profile)
笔者这里不过多描述每个名词、函数和细节,更详细的文档可以参考:
2. 流程综述
OpenGL的绘制流程(图形渲染管线,Graphics Pipeline)如下:
- 顶点着色(vertex shader)阶段将CPU传入的数据进行一定的变换处理
- 图元装配(shape assembly)阶段的就是上阶段的顶点数据处理成图元(如,三角形)
- 几何着色(geometry shader)阶段是根据一定规则将输入的图元变更或输出更多的图元(可选)
- 光栅化(rasterization)阶段的是将上阶段的图元进行计算得到图元占据的屏幕像素列表
- 片元着色(fragment)阶段是将上阶段生成的片元进行着色处理后
- 测试与混合阶段计算片元的深度、颜色等从而进行舍弃或保留
绘制流程繁琐,然而,我们能配置的只有三个蓝色的着色器部分。几何着色器可选,一般配置顶点着色器和片段着色器即可,即,以下步骤就是配置顶点着色器和片段着色器
3. 生成顶点数据
生成顶点缓冲对象(Vertex Buffer Objects, VBO)并加载数据:
const vertices = new Float32Array([ -0.5, -0.5, 0.0, 0.5, -0.5, 0.0, 0.0, 0.5, 0.0, ]); const vertexBuffer = gl.createBuffer(); gl.bindBuffer(gl.ARRAY_BUFFER, vertexBuffer); gl.bufferData(gl.ARRAY_BUFFER, vertices, gl.STATIC_DRAW);
4. 链接属性数据
顶点数组对象(Vertex Array Object, VAO)与VBO绑定,用于保存属性数据(先绑定VAO,再创建VBO就会绑定到VAO上):
gl.vertexAttribPointer(0, 3, gl.FLOAT, false, 0, 0); gl.enableVertexAttribArray(0)
5. 创建顶点着色器
创建顶点着色器(Vertex Shader)并编译:
const vertexShader = gl.createShader(gl.VERTEX_SHADER); gl.shaderSource(vertexShader, ` attribute vec3 aPos; void main() { gl_Position = vec4(aPos.x, aPos.y, aPos.z, 1.0); } `); gl.compileShader(vertexShader);
6. 创建片段着色器
创建片段着色器(Fragment Shader)并编译:
const fragmentShader = gl.createShader(gl.FRAGMENT_SHADER); gl.shaderSource(fragmentShader, ` #version 100 void main() { gl_FragColor = vec4(1.0, 0.5, 0.2, 1.0); } `); gl.compileShader(fragmentShader);
7. 链接着色器
着色器程序对象(Shader Program Object)是多个着色器合并之后并最终链接完成的版本:
const shaderProgram = gl.createProgram(); gl.attachShader(shaderProgram, vertexShader); gl.attachShader(shaderProgram, fragmentShader); gl.linkProgram(shaderProgram);
8. 绘制
开始绘制:
gl.clearColor(0.2, 0.3, 0.3, 1.0); gl.clear(gl.COLOR_BUFFER_BIT); gl.useProgram(shaderProgram); gl.drawArrays(gl.TRIANGLES, 0, 3);
9. 完整代码
基于浏览器以及Canvas创建OpenGL开发环境,完整代码如下:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title> </head> <body> <canvas style="width: 800px;height: 600px;"></canvas> <script> var canvas = document.querySelector('canvas'); var gl = canvas.getContext('webgl'); if (!gl) { console.log('WebGL not supported, falling back to experimental-webgl'); } const vertices = new Float32Array([ -0.5, -0.5, 0.0, 0.5, -0.5, 0.0, 0.0, 0.5, 0.0, ]); const vertexBuffer = gl.createBuffer(); gl.bindBuffer(gl.ARRAY_BUFFER, vertexBuffer); gl.bufferData(gl.ARRAY_BUFFER, vertices, gl.STATIC_DRAW); gl.vertexAttribPointer(0, 3, gl.FLOAT, false, 0, 0); gl.enableVertexAttribArray(0) const vertexShader = gl.createShader(gl.VERTEX_SHADER); gl.shaderSource(vertexShader, ` attribute vec3 aPos; void main() { gl_Position = vec4(aPos.x, aPos.y, aPos.z, 1.0); } `); gl.compileShader(vertexShader); if (!gl.getShaderParameter(vertexShader, gl.COMPILE_STATUS)) { alert('An error occurred compiling the shaders: ' + gl.getShaderInfoLog(vertexShader)); gl.deleteShader(vertexShader); } const fragmentShader = gl.createShader(gl.FRAGMENT_SHADER); gl.shaderSource(fragmentShader, ` #version 100 void main() { gl_FragColor = vec4(1.0, 0.5, 0.2, 1.0); } `); gl.compileShader(fragmentShader); if (!gl.getShaderParameter(fragmentShader, gl.COMPILE_STATUS)) { alert('An error occurred compiling the shaders: ' + gl.getShaderInfoLog(fragmentShader)); gl.deleteShader(fragmentShader); } const shaderProgram = gl.createProgram(); gl.attachShader(shaderProgram, vertexShader); gl.attachShader(shaderProgram, fragmentShader); gl.linkProgram(shaderProgram); if (!gl.getProgramParameter(shaderProgram, gl.LINK_STATUS)) { alert('Unable to initialize the shader program: ' + gl.getProgramInfoLog(shaderProgram)); } gl.clearColor(0.2, 0.3, 0.3, 1.0); gl.clear(gl.COLOR_BUFFER_BIT); gl.useProgram(shaderProgram); gl.drawArrays(gl.TRIANGLES, 0, 3); </script> </body> </html>
运行结果如下:
10. 参考资料
[1]你好,三角形 - LearnOpenGL CN (learnopengl-cn.github.io)
[2]【Learn OpenGL笔记】三角形(Triangle) - 知乎 (zhihu.com)
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 单元测试从入门到精通
· 上周热点回顾(3.3-3.9)
· winform 绘制太阳,地球,月球 运作规律