WebGL编程指南 - WebGL入门

打印 上一主题 下一主题

主题 867|帖子 867|积分 2601

初识绘图流程、缓冲区、着色器、attribute和uniform变量
  

先画一个蓝色的正方形

html代码:
  1. <!DOCTYPE html>
  2. <html lang="en">
  3.   <head>
  4.     <meta charset="UTF-8" />
  5.     <meta http-equiv="X-UA-Compatible" content="IE=edge" />
  6.     <meta name="viewport" content="width=device-width, initial-scale=1.0" />
  7.     <title>Document</title>
  8.   </head>
  9.   <body onload="main()">  //指定 onload 属性,告诉浏览器<body>元素加载完从何处开始执行
  10.     <canvas id="example" width="400" height="400">
  11.       Please use a browser that supports "canvas"
  12.     </canvas>
  13.     <script src="./js/DrawRectangle.js"></script>
  14.   </body>
  15. </html>
复制代码
JS代码:
  1. // DrawRectangle.js
  2. function main() {
  3.   // 获取<canvas>元素
  4.   let canvas = document.getElementById('example')
  5.   if (!canvas) {
  6.     console.log('Failed to retrieve the <canvas> element')
  7.     return
  8.   }
  9.   // 获取绘制二维图形的绘图上下文
  10.   let ctx = canvas.getContext('2d')
  11.   // 绘制蓝色矩形
  12.   ctx.fillStyle = 'rgba(0,0,255,1.0)'
  13.   ctx.fillRect(120, 10, 150, 150)
  14. }
复制代码
HTML5引入**标签,允许JavaScript**动态的绘制图形
   <body οnlοad=“main()”> //指定 onload 属性,告诉浏览器元素加载完从何处开始实验,作为JavaScript程序的入口
  绘制蓝色矩形的js程序的,为了在上绘制二维图形,需要颠末三个步骤:


  • 获取元素
  • 向该元素哀求二维图形的“绘制上下文”
  • 在绘图上下文上调用相应的绘图函数,绘制二维图形
   ctx对象的fillRect方法,方法的语法为 context.fillRect(x,y,width,height),x,y为矩形左上角的坐标,剩下两个是宽度和高度
  canvas 中的坐标和 OpenGL 一致

清空绘图区示例与配景致设置(初识多缓冲区模型与颜色缓冲区)

效果:

代码:
  1. <!DOCTYPE html>
  2. <html lang="en">
  3.     <head>
  4.         <meta charset="utf-8"/>
  5.         <meta http-equiv="X_UA_Compatible" content="IE=edge"/>
  6.         <meta name="viewport" content="width=device-width,inital-scale=1.0"/>
  7.         <title>Document</title>
  8.     </head>
  9.     <body onload="main()">
  10.         <canvas id="webgl" width="400" height="400">
  11.         </canvas>
  12.     <script src="HelloCanvas.js"></script>
  13.     </body>
  14. </html>
  15. // HelloCanvas.js
  16. function main() {
  17.     // 获取<canvas>元素
  18.     let canvas = document.getElementById('webgl')
  19.   
  20.     // 获取WebGL绘图上下文
  21.     // let gl = getWebGLContext(canvas) (书中的函数)
  22.     let gl = canvas.getContext('webgl')
  23.     if (!gl) {
  24.       console.log('Failed to get the rendering context for WebGL')
  25.       return
  26.     }
  27.   
  28.     // 指定清空<canvas>的颜色
  29.     gl.clearColor(0.0, 0.0, 0.0, 1.0) // 黑色
  30.   
  31.     // 清空<canvas>
  32.     gl.clear(gl.COLOR_BUFFER_BIT)
  33.   }
复制代码
因为没找到书中的函数库,所以参考了别人的代码
示例程序中 main 函数的实验流:

设置 canvas 配景致



  • 一旦指定配景致后,配景致会贮存在WebGL系统中,在下次调用**gl.clearColor()**方法之前不会改变。所以,假如未来还需要再次清空绘图区,没必要再指定一次颜色。
  • 这是挂载在**WebGLRenderingContext**对象上的方法。
gl.clear(buffer)

清空颜色缓冲区将导致 WebGL 清空页面上的 地域


   WebGL中的gl.clear()方法继续自OpenGL,基于多基本缓冲区模型
  绘制一个点 与 静态着色器

   相干内容:着色器初识、利用着色器的WebGL程序布局、初始化着色器、顶点着色器及内置变量、片元着色器及内置变量、齐次坐标、WebGL坐标系统、JavaScript程序和着色器程序的协同运行机制
相干函数:initShaders(), vec4(), gl.drawArrays()
  示例程序将在原点(0.0, 0.0, 0.0)处的10个像素大的红色的点。
因为WebGL处理的是三维图形,所以我们有必要为这个点指定三维坐标。

  1. <!DOCTYPE html>
  2. <html lang="en">
  3. <head>
  4.     <meta charset="UTF-8" />
  5.     <meta http-equiv="X-UA-Compatible" content="IE=edge" />
  6.     <meta name="viewport" content="width=device-width, initial-scale=1.0" />
  7.     <title>Draw a point (1)</title>
  8. </head>
  9. <body onload="main()">
  10.     <canvas id="webgl" width="400" height="400">
  11.         Please use the browser supporting "canvas"
  12.     </canvas>
  13.    
  14.     <script src="../libs/webgl-utils.js"></script>
  15.     <script src="../libs/webgl-debug.js"></script>
  16.     <script src="../libs/cuon-utils.js"></script>
  17.     <script src="HelloPoint1.js"></script>
  18. </body>
  19. </html>
  20. // HelloPoint1.js
  21. // 顶点着色器程序
  22. var VSHADER_SOURCE =
  23.   'void main() {
  24. ' +
  25.   ' gl_Position = vec4(0.0, 0.0, 0.0, 1.0);
  26. ' + // 设置坐标
  27.   ' gl_PointSize = 10.0;
  28. ' + // 设置尺寸
  29.   '}
  30. '
  31. // 片元着色器程序
  32. var FSHADER_SOURCE =
  33.   'void main() {
  34. ' +
  35.   ' gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0);
  36. ' + // 设置颜色
  37.   '}
  38. '
  39. // 主程序
  40. function main() {
  41.   // 获取<canvas>元素
  42.   let canvas = document.getElementById('webgl')
  43.   // 获取WebGL绘图上下文
  44.   // let gl = getWebGLContext(canvas)
  45.   let gl = canvas.getContext('webgl')
  46.   if (!gl) {
  47.     console.log('Failed to get the rendering context for WebGL')
  48.     return
  49.   }
  50.   // 初始化着色器
  51.   if (!initShaders(gl, VSHADER_SOURCE, FSHADER_SOURCE)) {
  52.     console.log('Failed to initialize shaders')
  53.     return
  54.   }
  55.   // 设置<canvas>背景色
  56.   gl.clearColor(0.0, 0.0, 0.0, 1.0)
  57.   // 清空<canvas>
  58.   gl.clear(gl.COLOR_BUFFER_BIT)
  59.   // 绘制一个点
  60.   gl.drawArrays(gl.POINTS, 0, 1)
  61. }
复制代码
着色器程序以字符串的形式嵌入在 JavaScript 文件中,在程序真正开始运行前它就已经设置好了
WebGL中有两种着色器:


  • 顶点着色器(Vertex shader):顶点着色器是用来形貌顶点特性(如位置、颜色等)的程序。顶点(vertex)是指二维或三维空间中的一个点,比如二维或三维图形的端点或交点。
  • 片元着色器(Fragment shader):举行逐片元处理过程如光照的程序。片元(fragment)是一个WebGL术语,你可以将其明白为像素(图像的单元)。
JavaScript 读取了着色器的相干信息,然后存在 WebGL 系统中以供调用

WebGL 程序的实验流程


初始化着色器

顶点着色器先实验,它对gl_Posetion变量和gl_PointSize变量举行赋值,并将他们传入片元着色器,然后片元着色器再实验。
   现实上,片元着色器并不直接吸收两个变量,而是吸收颠末光栅化处理后的片元值,这一部分会在书的第五章举行讨论
  WebGL程序包括运行在浏览器中的JavaScript和运行在WebGL系统中的着色器程序两个部分。
顶点着色器

  1. // 顶点着色器程序
  2. var VSHADER_SOURCE =
  3.   'void main() {
  4. ' +
  5.   ' gl_Position = vec4(0.0, 0.0, 0.0, 1.0);
  6. ' + // 设置坐标
  7.   ' gl_PointSize = 10.0;
  8. ' + // 设置尺寸
  9.   '}
  10. '
复制代码
顶点着色器设置了点的位置和大小。该语言本身和C语言一样,必须包含一个main()函数,main()函数前面的关键字void表现这个函数没有返回值,同时也不能指定参数。
与大多数语言一样,着色器程序利用=利用符举行赋值,将点的位置和尺寸分别赋值给gl_Positiongl_PointSize,这两个变量是内置在顶点着色器之中的:

注:**gl_Position必须被赋值,否则着色器无法正常工作;gl_PointSize**并不是必须的,默认值为1.0。

假如范例赋值错误,如10.0变成10,就会报错
gl_Position表现顶点的位置,一样寻常顶点只需要三个点即可,用内置函数**vec()**创建 vec4范例的变量
vec4(v0, v1, v2, v3):根据v0,v1,v2,v3值创建vec4对象
参数:
v0, v1, v2, v3: 指定4个浮点型分量;
返回值:
由v0, v1, v2, v3构成的vec4对象。
在示例中,我们添加了1.0作为函数第四分量。在WebGL(或者说OpenGL)中,将**gl_Positon设置为vec4范例的变量现实上是采用了齐次坐标**的方式,因为它能进步处理三维数据的服从,所以在三维图形系统中被大量利用。关于齐次坐标可以看下面的阐明:

片元着色器

顶点着色器控制点的位置和大小,片元着色器控制点的颜色。
片元着色器的作用是处理片元,使其显示在屏幕上
  1. // 片元着色器程序
  2. var FSHADER_SOURCE =
  3.   'void main() {
  4. ' +
  5.   ' gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0);
  6. ' + // 设置颜色
  7.   '}
  8. '
复制代码

绘制利用

  1.   // 绘制一个点
  2.   gl.drawArrays(gl.POINTS, 0, 1)
复制代码
建立着色器之后,与**HelloCanvas.js示例一样,举行设置配景致和清空绘制地域的利用,最后举行绘制利用。绘制利用采用的方法为gl.drawArrays()**。

当程序调用 gl.drawArrays() 时,顶点着色器将其实验 count 次,每次处理一个顶点
示例程序函数参数设置如下:


  • 因为我们绘制的是单独的点,所以设置第一个参数为gl.POINTS;
  • 设置第二个参数为0,表现从第1个顶点(虽然只有一个顶点)开始画起;
  • 第三个参数count为1,表现程序中只绘制1个点
WebGL 坐标系统

本身不是左手也不是右手,可以认为时右手坐标系
由此可见,WebGL坐标系和**<canvas>绘图区的坐标系不同,需要将前者映射到后者。在<canvas>**绘图区,WebGL坐标系统如下图所示:

绘制一个点2 与 attribute变量(动态设置顶点着色器)

   相干内容:用JavaScript程序从着色器外部向着色器传输数据(动态,而不是静态写在着色器中)、attribute变量、uniform变量
相干函数:gl.getAttribLocation()、gl.vertexAttrib3f()及其同族函数
  小结:动态设置着色器参数,重要包括以下几步:1.在着色器语言中,设置attribute或uniform变量,将变量赋值到主函数参数中;2.JavaScript程序中通过相干函数获取变量存储地址;3.通过相干函数,向该地址传输数据。
  在前一节中,点的位置是直接编(“硬编码”)写在顶点着色器中的,虽然易于明白但缺乏可扩展性;这一节中,Web程序可以将顶点的位置坐标从JavaScript传到着色器程序中,然后再对应位置上绘制点
目前而言,将位置信息从JavaScript程序中传给顶点着色器,有两种方式:attribute变量和uniform变量。



  • attribute变量:传输与顶点相干的数据
  • uniform变量:传输那些对于全部顶点都类似(或与顶点无关)的数据
两个变量都是GLSL ES变量,被用来从外部向顶点着色器内传输数据,示例中选用attribute变量,示例代码如下:
  1. <!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>Draw a point (1)</title>  </head>  <body onload="main()">    <canvas id="webgl" width="400" height="400">      Please use the browser supporting "canvas"    </canvas>    <!-- 书中的函数库 -->    <script src="./libs/webgl-utils.js"></script>    <script src="./libs/webgl-debug.js"></script>    <script src="./libs/cuon-utils.js"></script>    <script src="./js/HelloPoint2.js"></script>  </body></html>// HelloPoint2.js// 顶点着色器
  2. var VSHADER_SOURCE =
  3.   'attribute vec4 a_Position;
  4. ' +
  5.   'void main(){
  6. ' +
  7.   ' gl_Position = a_Position;
  8. ' +
  9.   ' gl_PointSize = 10.0;
  10. ' +
  11.   '}
  12. '
  13. // 片元着色器var FSHADER_SOURCE =  'void main() {' +  ' gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0);' + // 设置颜色  '}'// 主函数function main() {  // 获取<canvas>元素  let canvas = document.getElementById('webgl')  // 获取WebGL上下文  let gl = canvas.getContext('webgl')  if (!gl) {    console.log('Failed to get the rendering context for WebGL')  }  // 初始化着色器  if (!initShaders(gl, VSHADER_SOURCE, FSHADER_SOURCE)) {    console.log('Failed to initialize shaders')    return  }  // 获取attribute变量的存储位置
  14.   let a_Position = gl.getAttribLocation(gl.program, 'a_Position')
  15.   if (a_Position < 0) {
  16.     console.log('Failed to get the storage location of a_Position')
  17.   }
  18.   // 将顶点位置传输给attribute变量
  19.   gl.vertexAttrib3f(a_Position, 0.0, 0.0, 0.0)
  20.   // 设置<canvas>配景致  gl.clearColor(0.0, 0.0, 0.0, 1.0)  // 扫除<canvas>  gl.clear(gl.COLOR_BUFFER_BIT)  // 绘制一个点
  21.   gl.drawArrays(gl.POINTS, 0, 1)
  22. }
复制代码
attribute变量的声明与赋值:

在顶点着色器的第一行GLSL ES语言中声明了此变量(第3行):
  1. // 顶点着色器
  2. var VSHADER_SOURCE =
  3.   'attribute vec4 a_Position;
  4. ' +
  5.   'void main(){
  6. ' +
  7.   ' gl_Position = a_Position;
  8. ' +
  9.   ' gl_PointSize = 10.0;
  10. ' +
  11.   '}
  12. '
复制代码
为了利用 attribute 变量,需要包含一下步骤:


  • 在顶点着色器中,声明 attribute 变量
  • 将 attribute 变量赋值给 gl_Position 变量
  • 向 attribute 变量传输数据
详细利用讲解:
attribute变量的声明按照以下的格式:<存储限定符><范例><变量名>



  • 关键词attribute被称为存储限定符(storage qualifier),它表现接下来的变量(示例中是a_Position)是一个attribute变量。attribute变量必须声明玉成局变量,数据将从着色器外部传给该变量。
与一样寻常的JavaScript变量赋值不同,在WebGL系统之外向系统内的变量赋值需要知道该变量的存储地址,再通过存储地址向变量传输数据。获取attribute变量地址的部分代码如下:
  1.   // 获取attribute变量的存储位置
  2.   let a_Position = gl.getAttribLocation(gl.program, 'a_Position')
  3.   if (a_Position < 0) {
  4.     console.log('Failed to get the storage location of a_Position')
  5.   }
复制代码
  gl.getAttribLocation(program, name):获取由name参数指定的attribute变量的存储地址。
参数:
program: 指定包含顶点着色器和片元着色器的着色器
程序对象
;
name: 指定想要获取其存储地址的attribute变量的名称;
返回值:
大于即是0:attribute变量的存储地址
-1:指定的attribute变量不存在,或者其命名具有gl_或webgl_前缀
  向 attribute 变量赋值
  1.   // 将顶点位置传输给attribute变量
  2.   gl.vertexAttrib3f(a_Position, 0.0, 0.0, 0.0)
复制代码
通过存储地址向 attribute 变量赋值
   代码中我们通报了三个浮点数,而a_Position变量得数据范例时vec4,此处该方法会**默认将第四个分量设置为1.0。**颜色值得第4个分量为1.0表现该颜色完全不透明,而齐次坐标得第4个分量为1.0使齐次坐标和三维坐标对应起来,所以1.0是一个“安全”的第4分量。下一部分对其同族函数的阐明中介绍了默认填充的方式。
  

  1. //矢量版本 可以接收类型化数组 矢量版本的函数在原函数的末尾加了字母‘v’
  2. var position = new Float32Array([1.0, 2.0, 3.0, 1.0])
  3. gl.vertexAttrib4fv(a_Position, position)
  4. //对于接收数组的矢量版本,函数名中的数字代表所接收数组中的元素个数。
复制代码
也可以加一个顶点大小数据,控制绘制的大小:部分代码
  1. var VSHADER_SOURCE =
  2.     'attribute vec4 a_Position;
  3. ' +
  4.     'attribute float a_PointSize;
  5. ' +
  6.     'void main(){
  7. ' +
  8.     'gl_Position = a_Position;
  9. ' +
  10.     'gl_PointSize = a_PointSize;
  11. ' +
  12.     '}
  13. '
  14.     let a_PointSize = gl.getAttribLocation(gl.program,'a_PointSize');
  15.     if(a_Position < 0) {
  16.         console.log('Failed to get the storage location of a_Position');
  17.         return;
  18.     }
  19.     gl.vertexAttrib3f(a_Position,0.5,0.0,0.0);
  20.     gl.vertexAttrib1f(a_PointSize,50.0);
复制代码

写的太长了,网页开始卡顿了,再开一篇,这一章真的很长
参考:【《WebGL编程指南》读书笔记-WebGL入门】_getwebglcontext-CSDN博客

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

x
回复

使用道具 举报

0 个回复

正序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

天空闲话

金牌会员
这个人很懒什么都没写!

标签云

快速回复 返回顶部 返回列表