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的更多相关文章

  1. 基于Cocos2d-x学习OpenGL ES 2.0之多纹理

    没想到原文出了那么多错别字,实在对不起观众了.介绍opengl es 2.0的不多.相信介绍基于Cocos2d-x学习OpenGL ES 2.0之多纹理的,我是独此一家吧.~~ 子龙山人出了一个系列: ...

  2. 基于Cocos2d-x学习OpenGL ES 2.0系列——纹理贴图(6)

    在上一篇文章中,我们介绍了如何绘制一个立方体,里面涉及的知识点有VBO(Vertex Buffer Object).IBO(Index Buffer Object)和MVP(Modile-View-P ...

  3. JavaScript基础第01天笔记

    JavaScript基础第01天 1 - 编程语言 1.1 编程 编程: 就是让计算机为解决某个问题而使用某种程序设计语言编写程序代码,并最终得到结果的过程. 计算机程序: 就是计算机所执行的一系列的 ...

  4. artDialog是一个基于javascript编写的对话框组件,它拥有精致的界面与友好的接口

    artDialog是一个基于javascript编写的对话框组件,它拥有精致的界面与友好的接口 自适应内容 artDialog的特殊UI框架能够适应内容变化,甚至连外部程序动态插入的内容它仍然能自适应 ...

  5. DalekJS – 基于 JavaScript 实现跨浏览器的自动化测试

    在 Web 项目中,浏览器兼容以及跨浏览器测试是最重要的也是最费劲的工作.DalekJS 是一个基于 JavaScript(或 Node.js) 的免费和开源的自动化测试接口.它能够同时运行测试一组流 ...

  6. 基于JavaScript的REST客户端框架

    现在REST是一个比较热门的概念,REST已经成为一个在Web上越来越常用的应用,基于REST的Web服务越来越多,包括Twitter在内的微博客都是用REST做为对外的API,先前我曾经介绍过“基于 ...

  7. SWFObject: 基于Javascript的Flash媒体版本检测与嵌入模块

    原文地址:http://www.awflasher.com/flash/articles/swfobj.htm SWFObject: 基于Javascript的Flash媒体版本检测与嵌入模块原文:S ...

  8. WebGL是一种3D绘图标准,这种绘图技术标准允许把JavaScript和OpenGL ES 2.0结合在一起

    WebGL是一种3D绘图标准,这种绘图技术标准允许把JavaScript和OpenGL ES 2.0结合在一起,通过增加OpenGL ES 2.0的一个JavaScript绑定,WebGL可以为HTM ...

  9. 构建基于Javascript的移动web CMS——模板

    在上一篇<构建基于Javascript的移动CMS--Hello,World>讲述了墨颀 CMS的大概组成,并进行了一个简单的演示样例,即Hello,World.这一次,我们将把CMS简单 ...

  10. 正则表达式基于JavaScript的入门详解

    关于正则表达式,和很多前辈聊起这个知识点时,他们的反馈都比聊其他技术谦逊,而和很多刚入门的程序员讨论时甚至会有觉得你看不起他. 的确,正则表达式从通常的应用来看,的确不难,比如电话,邮箱等验证.语法, ...

随机推荐

  1. PyQt4编写界面的两种方式

    PyQt4编写界面的两种方式 应用PyQt4开发图形化界面有两种方式,一种是直接通过QtDesigner通过提供的窗口部件拖拽进行GUI创建,另外一种是直接进行编程实现. 第一种,QtDesigner ...

  2. Service层

    package com.neu.service; import java.util.List; import com.neu.bean.User;import com.neu.dao.UserDao; ...

  3. VmWare安装Centos后配置Net网络SSH链接问题看这一遍就够了

    1:首先安装VmWare 2:启动时在安装对应的Linux版本,网络就默认 net即可 3:都安装好了之后,注意有一个大坑,输入的账号密码都不能准确登录 最后发现是linux默认的输入法没有启用电脑键 ...

  4. week_7

    Andrew Ng 机器学习笔记 ---By Orangestar Week_7 This week, you will be learning about the support vector ma ...

  5. 10、比较Bigdecimal类型是否相等的方法

    一.Bigdecimal.equals()详解: Bigdecimal的equals方法不仅仅比较值的大小是否相等,首先比较的是scale(scale是bigdecimal的保留小数点位数),也就是说 ...

  6. docker搭建Elasticsearch、Kibana、Logstash 同步mysql数据到ES

    一.前言 在数据量大的企业级实践中,Elasticsearch显得非常常见,特别是数据表超过千万级后,无论怎么优化,还是有点力不从心!使用中,最首先的问题就是怎么把千万级数据同步到Elasticsea ...

  7. Python实验报告(第6章)

    实验6:函数 一.实验目的和要求 1.掌握函数的创建和调用: 2.了解不同的参数如何进行传递: 3.了解返回值的应用: 4.学习变量的作用域: 5.学习匿名函数(lambda). 二.实验环境 软件版 ...

  8. python基础23 之初识面向对象

    人狗大战 # 编写代码简单实现人打狗 狗咬人的小游戏 """推导步骤1:代码定义出人和狗""" person1 = { 'name': 'j ...

  9. [cocos2d-x]TextureCache和spriteFramecache

    SpriteFrameCache 主要服务于多张碎图合并出来的纹理图片.这种纹理在一张大图中包含了多张小图,直接通过TextureCache引用会有诸多不便,因而衍生出来精灵框帧的处理方式,即把截取好 ...

  10. 最最最常用的Git提交规范以及常用命令总结

    提交规范 为什么要制定提交规范? 便于对提交历史进行追溯,以及快速定位 代码改动的历史更加清晰 格式化的 Commit Message 才可以用于自动化输出 Change log 如何制定提交规范? ...