基于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)
[3]Hello GLSL - Web API 接口参考 | MDN (mozilla.org)
[4]WebGL - Web API 接口参考 | MDN (mozilla.org)
基于JavaScript的OpenGL 01 之Hello Triangle的更多相关文章
- 基于Cocos2d-x学习OpenGL ES 2.0之多纹理
没想到原文出了那么多错别字,实在对不起观众了.介绍opengl es 2.0的不多.相信介绍基于Cocos2d-x学习OpenGL ES 2.0之多纹理的,我是独此一家吧.~~ 子龙山人出了一个系列: ...
- 基于Cocos2d-x学习OpenGL ES 2.0系列——纹理贴图(6)
在上一篇文章中,我们介绍了如何绘制一个立方体,里面涉及的知识点有VBO(Vertex Buffer Object).IBO(Index Buffer Object)和MVP(Modile-View-P ...
- JavaScript基础第01天笔记
JavaScript基础第01天 1 - 编程语言 1.1 编程 编程: 就是让计算机为解决某个问题而使用某种程序设计语言编写程序代码,并最终得到结果的过程. 计算机程序: 就是计算机所执行的一系列的 ...
- artDialog是一个基于javascript编写的对话框组件,它拥有精致的界面与友好的接口
artDialog是一个基于javascript编写的对话框组件,它拥有精致的界面与友好的接口 自适应内容 artDialog的特殊UI框架能够适应内容变化,甚至连外部程序动态插入的内容它仍然能自适应 ...
- DalekJS – 基于 JavaScript 实现跨浏览器的自动化测试
在 Web 项目中,浏览器兼容以及跨浏览器测试是最重要的也是最费劲的工作.DalekJS 是一个基于 JavaScript(或 Node.js) 的免费和开源的自动化测试接口.它能够同时运行测试一组流 ...
- 基于JavaScript的REST客户端框架
现在REST是一个比较热门的概念,REST已经成为一个在Web上越来越常用的应用,基于REST的Web服务越来越多,包括Twitter在内的微博客都是用REST做为对外的API,先前我曾经介绍过“基于 ...
- SWFObject: 基于Javascript的Flash媒体版本检测与嵌入模块
原文地址:http://www.awflasher.com/flash/articles/swfobj.htm SWFObject: 基于Javascript的Flash媒体版本检测与嵌入模块原文:S ...
- WebGL是一种3D绘图标准,这种绘图技术标准允许把JavaScript和OpenGL ES 2.0结合在一起
WebGL是一种3D绘图标准,这种绘图技术标准允许把JavaScript和OpenGL ES 2.0结合在一起,通过增加OpenGL ES 2.0的一个JavaScript绑定,WebGL可以为HTM ...
- 构建基于Javascript的移动web CMS——模板
在上一篇<构建基于Javascript的移动CMS--Hello,World>讲述了墨颀 CMS的大概组成,并进行了一个简单的演示样例,即Hello,World.这一次,我们将把CMS简单 ...
- 正则表达式基于JavaScript的入门详解
关于正则表达式,和很多前辈聊起这个知识点时,他们的反馈都比聊其他技术谦逊,而和很多刚入门的程序员讨论时甚至会有觉得你看不起他. 的确,正则表达式从通常的应用来看,的确不难,比如电话,邮箱等验证.语法, ...
随机推荐
- JavaScript入门⑥-WEB浏览器API
JavaScript入门系列目录 JavaScript入门①-基础知识筑基 JavaScript入门②-函数(1)基础{浅出} JavaScript入门③-函数(2)原理{深入}执行上下文 JavaS ...
- <五>function的实现原理
类模版std::function是一种通用.多态的函数封装.std::function的实例可以对任何可以调用的目标实体进行存储.复制.和调用操作,这些目标实体包括普通函数.Lambda表达式.函数指 ...
- Django框架:2、静态文件配置、form表单、request对象、pycharm链接数据库、django链接数据库、ORM框架
Django框架 目录 Django框架 一.静态文件配置 1.静态文件 2.配置方法 二.form表单 1.action属性 2.method属性 三.request对象 1.基本用法 四.pych ...
- 网络工具netstat与ss
建议使用ss命令,2001年的时候netstat 1.42版本之后就没更新了,之后取代的工具是ss.netstat命令在很多场景下比较慢.ss可以显示跟netstat类似的信息,但是速度却比netst ...
- [编程基础] Python列表解析总结
在本教程中,我们将学习使用Python列表解析(list comprehensions)相关知识 1 使用介绍 列表解析是一种基于现有列表创建列表的句法结构.列表解析提供了创建列表的简洁方法.通常需要 ...
- [python]《Python编程快速上手:让繁琐工作自动化》学习笔记7
1. 用GUI 自动化控制键盘和鼠标第18章 (代码下载) pyautogui模块可以向Windows.OS X 和Linux 发送虚拟按键和鼠标点击.根据使用的操作系统,在安装pyautogui之前 ...
- IDEA 2022.1.3 创建一个 Maven 管理的 Web 项目
新建一个空项目,用于管理模块 创建完成,如下所示 删除 src 目录 删除后,如下所示 新建一个 Maven 模块 新建完成,如下所示 右键 pro07-javaweb-begin 模块,选择 Add ...
- C Primer Plus(4.8)編程練習
/*C Primer Plus (4.7) 5*/ 1 include<stdio.h> 2 #define BOOK "War and Peace" 3 int ma ...
- 记一下Mybatis Plus遇到的现象
使用Springboot+Mybaits plus,在Controller中直接调用Service中的方法,没有配置事务,就算是在Services上加了@Transactional也是没有事务的,可以 ...
- 结构型模式 - 桥接模式Bridge
学习而来,代码是自己敲的.也有些自己的理解在里边,有问题希望大家指出. 桥接模式的定义与特点 桥接(Bridge)模式的定义如下:将抽象与实现分离,使它们可以独立变化.它是用组合关系代替继承关系来实现 ...