此篇文章的主要目的是巩固自己对于创建webgl的时候一些知识点,主要参考了《webgl编程指南》以及_Hahn_的webgl环境搭建这篇文章,在此附上链接,方便大家查看( juejin.im/post/5baaf3… )。

我会分为三篇文章进行总结,为什么不在一篇文章中写完呢?
因为我个人不太喜欢技术的文章写的很长,那样在读的时候感觉很烦。

《webgl编程指南》这本书中知识点介绍的很详细,因此我就不在此赘述那些基础的知识点了,直接上代码。

实现一个红色的长方形

最终我们要实现的效果:

相应的代码

<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>Document</title><script src="./lib/webgl-debug.js"></script><script src="./lib/webgl-utils.js"></script><script src="./lib/cuon-matrix.js"></script><script src="./lib/cuon-utils.js"></script><style>*{padding:0;margin:0;}</style>
</head>
<body onload="main()"><canvas id="canvas" width="750" height="1334"></canvas><script type="text/javascript">var VSHADER_SOURCE = `attribute vec4 a_Position;varying vec2 uv;void main(){gl_Position = vec4(vec2(a_Position), 0.0, 1.0);uv = vec2(0.5, 0.5) * (vec2(a_Position) + vec2(1.0, 1.0));}`var FSHADER_SOURCE = `precision mediump float;varying vec2 uv;void main(){gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0);}`function main(){var canvas = document.getElementById('canvas');canvas.width = 750;canvas.height = 1334;var gl = getWebGLContext(canvas);if(!gl){console.log("Failed to get the tendering context for WevGl");return;}if(!initShaders(gl, VSHADER_SOURCE, FSHADER_SOURCE)){console.log("Failed to set the vertex information");return;}//清空画布gl.clearColor(0.0, 0.0, 0.0, 1.0);gl.clear(gl.COLOR_BUFFER_BIT);var n = initVertexBuffers(gl);//绘制顶点gl.drawArrays(gl.TRIANGLE_FAN, 0, n);}function initVertexBuffers(gl){var verticesTexCoords = new Float32Array([1.0, -1.0,1.0, 1.0,-1.0, 1.0,-1.0, -1.0]);var n = 4;var vertexTexCoordBuffer = gl.createBuffer();if(!vertexTexCoordBuffer){console.log("Failed to create the buffer object");return -1;}gl.bindBuffer(gl.ARRAY_BUFFER, vertexTexCoordBuffer);gl.bufferData(gl.ARRAY_BUFFER, verticesTexCoords, gl.STATIC_DRAW);var FSIZE = verticesTexCoords.BYTES_PER_ELEMENT;var a_Position = gl.getAttribLocation(gl.program, 'a_Position');if(a_Position < 0){console.log("Failed to get the stroage location og a_Position");}gl.vertexAttribPointer(a_Position, 2, gl.FLOAT, false, FSIZE * 2, 0);gl.enableVertexAttribArray(a_Position);return n;}</script>
</body>
</html>复制代码

接下来我们做具体的理解分析。

首先我们可以看到在开始我们引用了几个js的文件,这几个文件是《webgl编程指南》中的一些辅助函数的文件,暂时我们只是应用,不深入的探究。

<script src="./lib/webgl-debug.js"></script>
<script src="./lib/webgl-utils.js"></script>
<script src="./lib/cuon-matrix.js"></script>
<script src="./lib/cuon-utils.js"></script>
复制代码

我们在DOM中可以看到一个canvas的结构,这个DOM结构就是告诉浏览器我们要一个画布。以后绘制的webgl都会出现在这个canvas中。
接下来就是js这个重点了,我们在js中首先定义了一个顶点着色器。

var VSHADER_SOURCE = `attribute vec4 a_Position;varying vec2 uv;void main(){gl_Position = vec4(vec2(a_Position), 0.0, 1.0);uv = vec2(0.5, 0.5) * (vec2(a_Position) + vec2(1.0, 1.0));}`
复制代码

什么是顶点着色器呢?

顶点着色器就是用来描述顶点的特性(例如位置、颜色等)的程序。顶点是指二维或三维空间中的一个点,比如二维或者三维图形的端点或焦点。

在上面我们首先定义了一个attribute vec4 a_Position;这个a_Position变量的作用就是js向顶点着色器传入顶点位置的入口,通俗来说就是告诉浏览器我们要在哪几个点的范围内进行“作画”,因为我们现在作画都是在二维平面上面进行的因此呢
gl_Position = vec4(vec2(a_Position), 0.0, 1.0);
这个赋值操作的第三个参数就是0.0,第四个参数我们就设置为默认的1.0。

而我们定义的uv变量就是纹理的坐标,这个uv变量一般会传入片元着色器中进行操作,你可将其理解为我们“作画”的坐标。
uv = vec2(0.5, 0.5) * (vec2(a_Position) + vec2(1.0, 1.0));
但是这个计算是什么鬼呢?
首先我们在initVertexBuffers函数中可以看到

var verticesTexCoords = new Float32Array([1.0, -1.0,1.0, 1.0,-1.0, 1.0,-1.0, -1.0
]);
复制代码

这四个坐标就是我们想要画的图像的坐标,也就是纹理坐标了。

上面红色框内就是我们的纹理坐标。

上面的蓝色框内就是我们着色器中的坐标了。
我们将红色坐标系的点带入那个计算公式(注意是逐分量计算)

A => vec2(0.5, 0.5) * (vec2(1.0, -1.0) + vec2(1.0, 1.0)) => (1.0, 0.0)

B => vec2(0.5, 0.5) * (vec2(1.0, 1.0) + vec2(1.0, 1.0)) => (1.0, 1.0)

C => vec2(0.5, 0.5) * (vec2(-1.0, -1.0) + vec2(1.0, 1.0)) => (0.0, 1.0)

D => vec2(0.5, 0.5) * (vec2(-1.0, -1.0) + vec2(1.0, 1.0)) => (0.0, 0.0)

最后的结果是红色坐标系中的点变成了蓝色坐标系中对应的点,这就是那个计算公式的作用。

OK到这里顶点着色器就研究完成了,接下来就是片元着色器了

什么是片元着色器呢?

片元着色器就是进行逐片元处理过程的程序,片元是一个webgl术语,你可以将其理解为像素。

var FSHADER_SOURCE = `precision mediump float;varying vec2 uv;void main(){gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0);}
`
复制代码

在片元着色器中我们首先定义了precision mediump float;
这句话的作用就是一个精度的规定,不加的话,片元着色器这里就会报错。
接着我们使用了和在顶点着色器中相同的varying vec2 uv;接收了来自顶点着色器中的纹理坐标信息(虽然在上面的代码中我们没有使用纹理坐标,但是你需要知道如何传入)。

重点是在main函数中我们给gl_FragColor赋值一个vec4类型的变量,这个赋值的作用就是告诉gl_FragColor使用什么样的颜色来进行渲染,vec4的四个值分别对应rgba。

js进行初始化操作

我们写好了顶点着色器和片元着色器以后浏览器并不能理解那是什么,因为对于浏览器来说那就是一些字符串,因此我们需要使用js进行一些列的操作。
首先第一步,先获取DOM中的canvas,然后设置它的宽和高。

var gl = getWebGLContext(canvas);
if(!gl){console.log("Failed to get the tendering context for WevGl");return;
}
复制代码

第二步,我们使用上面的代码将我们获取的canvas变为了gl的画布(通俗意义上你可以这么理解),并且我们做了一个差错处理

if(!initShaders(gl, VSHADER_SOURCE, FSHADER_SOURCE)){console.log("Failed to set the vertex information");return;
}
复制代码

第三步,初始化shaders,这函数就是我们引用lib文件夹下面的js文件中存在的,在此你暂时使用就可以,此函数需要将我们的“画布”也就是gl传入,同时需要传入顶点着色器变量和片元着色器变量。

//清空画布
gl.clearColor(0.0, 0.0, 0.0, 1.0);
gl.clear(gl.COLOR_BUFFER_BIT);var n = initVertexBuffers(gl);
//绘制顶点
gl.drawArrays(gl.TRIANGLE_FAN, 0, n);
复制代码

第四步,清空画布开始作画,我们使用gl的函数先将画布清空,然后使用我们自己写的initVertexBuffers函数初始化缓冲区(这个函数稍后会介绍),并且此函数会返回一个顶点的个数,最后我们使用gl的drawArrays函数开始绘制。

最后就是详解我们自己写的initVertexBuffers函数了,我们需要知道缓冲区是什么?

缓冲区对象是webgl系统中的一块存储区,你可以在缓冲区对象中保存想要绘制的所有顶点的数据。
在上面我们就说过传入纹理坐标的事情。

var verticesTexCoords = new Float32Array([1.0, -1.0,1.0, 1.0,-1.0, 1.0,-1.0, -1.0
]);
var n = 4;
复制代码

在函数开始我们首先定义了一个特殊的数组,这个数组的作用就是定义纹理的顶点坐标,并且我们定义了n变量,这个变量表示我们想要创建的顶点个数。
接下来我们需要创建出缓冲区,并且使用。

创建缓冲区对象

var vertexTexCoordBuffer = gl.createBuffer();
if(!vertexTexCoordBuffer){console.log("Failed to create the buffer object");return -1;
}
复制代码

在上面的代码中我们使用传入函数的gl的createBuffer方法将创建的缓冲区赋值给了vertexTexCoordBuffer变量,并且做了一个差错判断。

绑定缓冲区对象

gl.bindBuffer(gl.ARRAY_BUFFER, vertexTexCoordBuffer);
复制代码

在此我们使用gl的bindBuffer函数将我们创建的缓冲区进行了绑定,bindBuffer的第一个参数表示缓冲区对象中包含了顶点的数据,第二个参数就是我们之前创建的缓冲区对象。

将数据写入缓冲区对象

gl.bufferData(gl.ARRAY_BUFFER, verticesTexCoords, gl.STATIC_DRAW);
复制代码

bufferData函数的作用就是将我们在上面定义的数组verticesTexCoords写入缓冲区对象,此函数的第一个参数需要是gl.ARRAY_BUFFER或gl.ELEMENT_ARRAY_BUFFER,第一种参数和bindBufferbuffer表示的一样都是顶点的数据,第二种参数表示顶点数据的索引值,第二个参数就是我们纹理的顶点数组了,第三个参数表示程序将如何使用存储在缓冲区对象中的数据,STATIC_DRAW表示只会向缓冲区对象中写入一次数据,但需要绘制很多次。

将缓冲区对象分配给一个attribute变量

var FSIZE = verticesTexCoords.BYTES_PER_ELEMENT;var a_Position = gl.getAttribLocation(gl.program, 'a_Position');
if(a_Position < 0){console.log("Failed to get the stroage location og a_Position");
}
gl.vertexAttribPointer(a_Position, 2, gl.FLOAT, false, FSIZE * 2, 0);
复制代码

在上面的代码中我们首先定义了一下FSIZE变量,这个变量只是为了我们在赋值的时候方便操作,接着我们定义了a_Position变量,并且使用了gl的方法获取到了我们在顶点着色器中定义的attribute类型的a_Position变量,最后我们使用了vertexAttribPointer方法为这个attribute变量进行赋值。

vertexAttribPointer函数的第一个参数就是我们待分配的attribute变量的存储位置;
第二个参数是指定缓冲区每个顶点的分量个数(此处我们使用的是2);
第三个参数是指定数据的格式。
第四个参数传入true或false,表明是否将非浮点型的数据归一化。
第五个参数指定相邻两个顶点间的字节数(因为我们在数组中定义的是每两个数值表示一个顶点,所以此处传入2)。
最后一个参数表示缓冲区对象中的偏移量。

开启attribute变量

gl.enableVertexAttribArray(a_Position);
复制代码

在最后我们需要开启我们要使用的attribute变量,这样一个完整的buffer就创建完成了。

经过上面的操作,我们就得到了一个长方形了。
以上的知识都是比较基础,但确实是很重要的东西。
代码地址:gitee.com/wangtao_it_…
我本次的事例是此地址下面的basics.html文件。

webgl值得重视的基础构建相关推荐

  1. Java并发基础构建模块简介

    在实际并发编程中,可以利用synchronized来同步线程对于共享对象的访问,用户需要显示的定义synchronized代码块或者方法.为了加快开发,可以使用Java平台一些并发基础模块来开发. 注 ...

  2. Web3D编程入门总结——WebGL与Three.js基础介绍

    1 /*在这里对这段时间学习的3D编程知识做个总结,以备再次出发.计划分成"webgl与three.js基础介绍"."面向对象的基础3D场景框架编写".&quo ...

  3. SuperMap iClient3D for WebGL教程 粒子特效-基础火焰特效

    SuperMap iClient3D for WebGL教程 粒子特效-基础火焰特效 粒子特效简介 使用粒子特效 完整代码 作者: NIck Cheng 粒子特效简介 粒子特效通常使用与要表现某些动态 ...

  4. 百度优化软件值得重视

    临沂网络优化随着网络社会的发展,社会对网络的依赖越来越大,网络带来的效益让更多的懂网络不懂网络的人置身其中.个人网站,公司网站已成为必不可少的交流平台了.网站的海量增长使得优化工作变得越来越重要.但是 ...

  5. 【3D游戏编程与设计】四 游戏对象与图形基础 : 构建游戏场景+牧师与魔鬼 动作分离版

    [3D游戏编程与设计]四 游戏对象与图形基础 : 构建游戏场景+牧师与魔鬼 动作分离版 基本操作演练 下载 Fantasy Skybox FREE, 构建自己的游戏场景 下载 Fantasy Skyb ...

  6. 真的不值得重视吗?ETH Zurich博士重新审视贝叶斯深度学习先验

    ©作者 | 杜伟.力元 来源 | 机器之心 一直以来,贝叶斯深度学习的先验都不够受重视,这样真的好么?苏黎世联邦理工学院计算机科学系的一位博士生 Vincent Fortuin 对贝叶斯深度学习先验进 ...

  7. WebGL学习笔记(基础知识篇)

    WEBGL基础知识介绍 1.场景(scene) 场景如其名,即显示3D空间内物体的容器,就好比一个箱子是一个3D场景. 2.坐标系: webgl使用笛卡尔坐标系(宽度.高度和深度),我们也可以指定使用 ...

  8. Lync Server 2010标准版系列PART1:基础构建

    可能环境准备已经是老生常谈的东西了,但我们搭建环境做测试.评估,或者说在客户生产环境做部署,非常需要重视的就是细节,力求做到一丝不苟,并且快速完成部署任务.所以在测试环境的搭建中,基础环境的准备是非常 ...

  9. 在NAS上基础构建云存储系统的两种解决方案

    对于一个成功的.具有极高可扩展性的NAS存储系统来说,要想架构云存储系统解决方案需要什么? 云存储的概念始于Amazon提供的一项服务(S3),同时还伴随着其云计算产品(EC2).在Amazon的S3 ...

最新文章

  1. python基础知识资料-Python基础知识梳理 - 第02部分
  2. 【SpringBoot专题】监控健康状况
  3. python 依据某几列累加求和_Python爬虫笔记:爬取单个页面
  4. 从零开始做Vue前端架构(5)
  5. mysql 创建事件
  6. 人工智能和计算机软件,人工智能在计算机软件方面有什么应用?
  7. java 易变变量_关于java:易变变量和其他变量
  8. linux内核之时间子系统
  9. 常见音频编码格式解析
  10. android 性能测试iozone篇
  11. 博主自我介绍、当前已经成立的技术分局【专栏必读】
  12. 一文学会如何做电商数据分析(附运营分析指标框架)
  13. 谷歌SEO考虑富媒体文件
  14. ios 加载大量图片崩溃_iOS加载单张图片导致崩溃的分析
  15. UE4 Sequencer的事件调用
  16. 说话人识别中的数据预处理和数据增强
  17. visio studio code安装之后的两个错误的解决办法
  18. 解决T100设计器无法更新基础数据的幺蛾子
  19. 中国大学排名爬取代码更新
  20. STN32单片机学习笔记(五)-按键检测

热门文章

  1. linux之文件的高级命令
  2. 解决虚拟机提示VMware Workstation cannot connect to the virtual machine的问题
  3. 磁盘管理 ——RAID1+0卷+LVM
  4. 添加非oracle用户到dba, oinstall组
  5. [原]Java 正则 多子串 匹配 替换
  6. 2011清华MBA备考全记录
  7. Advanced Installer 打包程序并支持自动升级
  8. 娃哈哈信息部李钒助阵FBS2017 共探食品饮料信息化之路
  9. 时序数据库(TSDB)-为万物互联插上一双翅膀
  10. 脚本1)启动jetty的脚本