WebGL 初始化着色器

news2024/11/25 0:07:43

目录

前言

初始化着色器的7个步骤

创建着色器对象(gl.createShader()) 

gl.createShader()规范

gl.deleteShader()规范

 指定着色器对象的代码(gl.shaderSource())

gl.shaderSource()规范

编译着色器(gl.compileShader()) 

gl.compileShader()规范​编辑

gl.getShaderParameter()规范

gl.getShaderInfoLog()规范

创建程序对象(gl.createProgram())

gl.createProgram()规范

为程序对象分配着色器对象(gl.attachShader()) 

gl.attachShader()规范

gl.detachShader()规范

连接程序对象(gl.linkProgram()) 

gl.getProgramPara-meters()规范

gl.getProgramInfoLog()规范

告知WebGL系统所使用的程序对象(gl.useProgram()) 

gl.usePorgram()规范

initShaders()函数的内部流程

initShaders()函数

createProgram()函数

loadShader()函数


前言

本章来研究一下以前一直使用的辅助函数initShaders()。以前的所有程序都使用了这个函数,它隐藏了建立和初始化着色器的细节。但如果你确实很想知道WebGL原生API是如何将字符串形式的GLSL ES代码编译为显卡中运行的着色器程序,那么这一节的内容将大大满足你的好奇心。

初始化着色器的7个步骤

initShaders()函数的作用是,编译GLSL ES代码,创建和初始化着色器供WebGL使用。具体地,分为以下7个步骤:

1. 创建着色器对象(gl.createShader())。

2. 向着色器对象中填充着色器程序的源代码(gl.shaderSource())。

3. 编译着色器(gl.compileShader())。

4. 创建程序对象(gl.createProgram())。

5..为程序对象分配着色器(gl.attachShader())。

6. 连接程序对象(gl.linkProgram())。

7. 使用程序对象(gl.useProgram())。

虽然每一步看上去都比较简单,但是放在一起显得复杂了,我们将逐条讨论。首先,你需要知道这里出现了两种对象:着色器对象(shader object)和程序对象(program object)。 

着色器对象

着色器对象管理一个顶点着色器或一个片元着色器。每一个着色器都有一个着色器对象。

程序对象

程序对象是管理着色器对象的容器。WebGL中,一个程序对象必须包含一个顶点着色器和一个片元着色器。 

着色器对象和程序对象的关系图

 

下面就来逐个讨论上述7个步骤。 

创建着色器对象(gl.createShader()) 

所有的着色器对象都必须通过调用gl.createShader()来创建。

gl.createShader()规范

gl.createShader()函数根据传入的参数创建一个顶点着色器或者片元着色器。如果不再需要这个着色器,可以使用gl.deleteShader()函数来删除着色器。

gl.deleteShader()规范

 注意,如果着色器对象还在使用(也就是说已经使用gl.attachShader()函数使之附加在了程序对象上,我们马上就会讨论该函数),那么gl.deleteShader()并不会立刻删除着色器,而是要等到程序对象不再使用该着色器后,才将其删除。 

 指定着色器对象的代码(gl.shaderSource())

通过gl.shaderSource()函数向着色器指定GLSL ES源代码。在JavaScript程序中,源代码以字符串的形式存储

gl.shaderSource()规范

编译着色器(gl.compileShader()) 

向着色器对象传入源代码之后,还需要对其进行编译才能够使用。GLSL ES语言和JavaScript不同而更接近C或C++,在使用之前需要编译成二进制的可执行格式,WebGL系统真正使用的是这种可执行格式。使用gl.compileShader()函数进行编译。注意,如果你通过调用gl.shaderSource(),用新的代码替换掉了着色器中旧的代码,WebGL系统中的用旧的代码编译出的可执行部分不会被自动替换,你需要手动地重新进行编译。

gl.compileShader()规范

当调用gl.compileShader()函数时,如果着色器源代码中存在错误,那么就会出现编译错误。可以调用gl.getShaderParameter()函数来检查着色器的状态。

gl.getShaderParameter()规范

 调用gl.getShaderParameter()并将参数pname指定为gl.COMPILE_STATUS,就可以检查着色器编译是否成功。 

如果编译失败,gl.getShaderParameter()会返回false,WebGL系统会把编译错误的具体内容写入着色器的信息日志(information log),我们可以通过gl.getShaderInfoLog()来获取之。

gl.getShaderInfoLog()规范

虽然日志信息的具体格式依赖于浏览器对WebGL的实现,但大多数WebGL系统给出的错误信息都会包含代码出错行的行号。比如,如果你试图编译如下这样的一个着色器:

 代码的第2行出错了(应该是gl_而不是gl.),Chrome浏览器给出的编译错误信息如图9.11所示(cuon-utils.js将错误信息字符串打印在控制台上):

可见,错误信息告诉我们:第2行的变量gl未被定义。

cuon-utils.js:88表示这条错误是在JavaScript文件cuon-utils.js的第88行,即定义initShaders()函数之处检测到的,该函数调用了gl.getShaderInfolog()函数。 

创建程序对象(gl.createProgram())

如前所述,程序对象包含了顶点着色器和片元着色器,可以调用gl.createProgram()来创建程序对象。事实上,之前使用程序对象,gl.getAttribLocation()函数和gl.getUniformLocation()函数的第1个参数,就是这个程序对象。

gl.createProgram()规范

类似地,可以使用gl.deleteProgram()函数来删除程序对象。

 一旦程序对象被创建之后,需要向程序附上两个着色器。 

为程序对象分配着色器对象(gl.attachShader()) 

WebGL系统要运行起来,必须要有两个着色器:一个顶点着色器和一个片元着色器。可以使用gl.attachShader()函数为程序对象分配这两个着色器。

gl.attachShader()规范

着色器在附给程序对象前,并不一定要为其指定代码或进行编译(也就是说,把空的着色器附给程序对象也是可以的)。类似地,可以使用gl.detachShader()函数来解除分配给程序对象的着色器。 

gl.detachShader()规范

连接程序对象(gl.linkProgram()) 

在为程序对象分配了两个着色器对象后,还需要将(顶点着色器和片元)着色器连接起来。使用gl.linkProgram()函数来进行这一步操作。

程序对象进行着色器连接操作,目的是保证:(1)顶点着色器和片元着色器的varying变量同名同类型,且一一对应;(2)顶点着色器对每个varying变量赋了值;(3)顶点着色器和片元着色器中的同名uniform变量也是同类型的(无需一一对应,即某些uniform变量可以出现在一个着色器中而不出现在另一个中);(4)着色器中的attribute变量、uniform变量和varying变量的个数没有超过着色器的上限,等等。 

在着色器连接之后,应当检查是否连接成功。通过调用gl.getProgramPara-meters()函数来实现。

gl.getProgramPara-meters()规范

如果程序已经成功连接,我们就得到了一个二进制的可执行模块供WebGL系统使用。如果连接失败了,也可以通过调用gl.getProgramInfoLog()从信息日志中获取连接出错信息。 

gl.getProgramInfoLog()规范

告知WebGL系统所使用的程序对象(gl.useProgram()) 

最后,通过调用gl.usePorgram()告知WebGL系统绘制时使用哪个程序对象。

gl.usePorgram()规范

 这个函数的存在使得WebGL具有了一个强大的特性,那就是在绘制前准备多个程序对象,然后在绘制的时候根据需要切换程序对象。

这样,建立和初始化着色器的任务就算完成了。如你所见,initShaders()函数隐藏了大量的细节,我们可以放心地使用该函数来创建和初始化着色器,而不必考虑这些细节。本质上,在该函数顺利执行后,顶点着色器和片元着色器就已经就位了,只需要调用gl.drawArrays()或gl.drawElements()来使整个WebGL系统运行起来。

现在,你对上述诸多WebGL原生API函数已经有了不错的理解,下面来看一下cuon-utils.js中initShaders()函数的内部流程。

initShaders()函数的内部流程

initShaders()函数将调用createProgram()函数,后者负责创建一个连接好的程序对象;createProgram()函数则又会调用loadShader()函数,后者负责创建一个编译好的着色器对象;这3个函数被依次定义在cuon-utils.js文件中。initShaders()函数定义在该文件的顶部,如下所示

initShaders()函数

function initShaders(gl, vshader, fshader) {
  // 创建程序对象
  var program = createProgram(gl, vshader, fshader);
  if (!program) {
    console.log('Failed to create program');
    return false;
  }

  gl.useProgram(program);
  gl.program = program;

  return true;
}

initShaders()函数本身很简单,首先调用createProgram()函数创建一个连接好的程序对象,然后告诉WebGL系统来使用这个程序对象,最后将程序对象设为gl对象的program属性。

createProgram()函数

 createProgram()函数通过调用loadShader()函数,创建顶点着色器和片元着色器的着色器对象(第31和32行)。loadShader()函数返回的着色器对象已经指定过源码并已经成功编译了。

createProgram()函数自己负责创建程序对象(第38行),然后将前面创建的顶点着色器和片元着色器分配给程序对象(第44和45行)。

接着,该函数连接程序对象(第48行),并检查是否连接成功(第51行)。如果连接成功,就返回程序对象(第60行)。

最后看一下loadShader()函数,如下所示。该函数被createProgram()函数调用。

loadShader()函数

loadShader()函数首先创建了一个着色器对象(第72行),然后为该着色器对象指定源代码(第79行),并进行编译(第82行),接着检查编译是否成功(第85行),如果成功编译,没有出错,就返回着色器对象。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1029394.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

大二层—多链接透明互联协议如何工作

大二层就引入了 TRILL(Transparent Interconnection of Lots of Link),即多链接透明互联协议。它的基本思想是,二层环有问题,三层环没有问题,那就把三层的路由能力模拟在二层实现。 运行 TRILL 协议的交换…

23062QTday5

完成登录界面的注册功能 头文件 #ifndef WIDGET_H #define WIDGET_H#include <QWidget> #include <QApplication> #include <iostream> #include <QMessageBox> #include <QtDebug> #include <QIcon> #include<QPushButton> #incl…

Leetcode—— 20.有效的括号

20. 有效的括号 给定一个只包括 ‘(’&#xff0c;‘)’&#xff0c;‘{’&#xff0c;‘}’&#xff0c;‘[’&#xff0c;‘]’ 的字符串 s &#xff0c;判断字符串是否有效。 有效字符串需满足&#xff1a; 左括号必须用相同类型的右括号闭合。 左括号必须以正确的顺序闭…

【LeetCode-中等题】 222. 完全二叉树的节点个数

文章目录 题目方法一&#xff1a;把该题当做一个普通的二叉树来做&#xff08;任何遍历都可以&#xff09;方法二&#xff1a;利用完全二叉树的性质来做 题目 方法一&#xff1a;把该题当做一个普通的二叉树来做&#xff08;任何遍历都可以&#xff09; 例如&#xff1a;二叉树…

如何选择一只股票,待完善。

目录 ROE(盈利能力)增长率(成长能力)收现比(营收质量)总资产周转率(经营能力)增长率(成长能力)商誉净资产比(排雷)流动比率(排雷) ROE(盈利能力) 什么是ROE? ROE 全名叫 Return of Equity&#xff0c;翻成中文叫“股东回报率”&#xff0c;也叫"净资产收益率"。 …

token登录的实现

token登录的实现 我这种token只是简单的实现token&#xff0c;就是后端利用UUID 生成简单随机码&#xff0c;利用随机码作为在Redis中的键&#xff0c;然后存储的用户信息作为值&#xff0c;在每次合理请求的时候对token的有效时间进行刷新&#xff08;利用拦截器&#xff09;&…

常见的文件格式

一、C:\fakepath\新建文本文档.txt [object String] 实现方式&#xff1a; <input onchange"test(this.value)" type"file"></input><script>function test(e){console.log(e,Object.prototype.toString.call(e))}</script> 二、…

js 数组对象转为 key对应的数组

1、将要转换的格式 2、 转换后格式 3、代码处理 可以使用forEach循环遍历原始数组&#xff0c;并将每个对象的属性值分别存储在一个新的对象中。然后&#xff0c;使用Object.values()方法获取这些属性值的数组。 console.log(result--, result);let dealRes {};result.forEac…

10.12广州见 | 第十六届智慧城市大会报名通道全面开启

第十六届中国智慧城市大会 将于10月12日至13日 在广州举办 智慧城市是数字中国、智慧社会的核心载体&#xff0c;是数字时代城市发展的高级形态。由中国服务贸易协会、中国测绘学会、中国遥感委员会主办的第十六届中国智慧城市大会&#xff0c;将以“数实融合开放创新智引未…

“降本”是关键,FCU1104打造低成本工商业储能EMS

在不久前举行的EESA中国国际储能展上&#xff0c;“工商业储能”成为了热度最高的话题之一&#xff0c;几乎每家展出工商业储能系统的展商都收获了大量观众的驻足围观&#xff0c;热度非凡。究竟是怎样的原因让工商业储能如此瞩目呢&#xff1f; 通过与多家储能厂家沟通并查阅…

群晖管家+内网穿透实现公网远程访问本地黑群晖

白嫖怪狂喜&#xff01;黑群晖也能使用群晖管家啦&#xff01; 文章目录 白嫖怪狂喜&#xff01;黑群晖也能使用群晖管家啦&#xff01;1.使用环境要求&#xff1a;2.下载安装群晖管家app3.随机地址登陆群晖管家app4.固定地址登陆群晖管家app 自己组装nas的白嫖怪们虽然也可以通…

IP转地理位置:探讨技术与应用

IP地址是互联网上设备的唯一标识符&#xff0c;而将IP地址转换为地理位置信息是网络管理、安全监控和市场定位等领域中的一项重要任务。本文将深入探讨IP转地理位置的技术原理和各种应用场景。 IP地址与地理位置 IP地址&#xff08;Internet Protocol Address&#xff09;是一…

一、八大排序(sort)

文章目录 一、时间复杂度&#xff08;一&#xff09;定义&#xff1a;常数操作 二、空间复杂度&#xff08;一&#xff09;定义&#xff1a; 三、排序&#xff08;一&#xff09;选择排序1.定义2.代码3.特性 &#xff08;二&#xff09;冒泡排序1.定义2.代码3.特性 &#xff08…

樱花(筛素数+约数)

题目 给定一个整数 n&#xff0c;求有多少正整数数对 (x,y) 满足 1/x1/y1/n!。 输入格式 一个整数 n。 输出格式 一个整数&#xff0c;表示满足条件的数对数量。 答案对 1e97取模。 数据范围 1≤n≤106 输入样例&#xff1a; 2输出样例&#xff1a; 3样例解释 共有…

中华崛起,科技强国!这三款充满科技风的科技模板,一起来探索吧

最近是不是都被华为mate60和苹果15刷屏了啊 &#xff0c;在我们的生活中&#xff0c;科技有着千变万化的面貌。它让我们的世界变得越来越小&#xff0c;让我们的生活越来越便捷。它使我们的梦想成为现实&#xff0c;使我们的思想得以落地。它打开了新的视野&#xff0c;为我们提…

java面向对象(八)

文章目录 一、abstract关键字的使用1.概念2. abstract修饰类:抽象类3.abstract修饰方法&#xff0c;抽象方法4.abstract使用上的注意点&#xff1a;5.抽象类的匿名子类 二、计算一段代码执行所花费的时间三、接口的使用1.接口的使用2.定义接口中的成员3.代码demo4.Java类可以实…

LabVIEW应用开发——前面板和程序框图

上篇我们讲述了LabVIEW的安装并且新建了一个VI程序成功运行&#xff0c;这篇我们详细了解界面上一些工具、属性和层次结构。 LabVIEW安装 我们双击打开上次创建的.vi文件。 这时候我们发现只有前面板&#xff0c;程序框图界面不见了&#xff0c;我们需要使用CtrlE或者在Windows…

点进来看看ChatBase替代品在提高工作效率方面有什么优势

ChatBase是帮助企业分析和改善其对话式 AI 体验的一个很好的定制聊天机器人平台。但它也有一些局限性&#xff0c;像其对对话分析的关注范围狭窄&#xff0c;而且还依赖手动标记和标记对话进行分析&#xff0c;可能会阻碍提高工作的效率。那有什么比较好的平台能够替代Chatbase…

解决 VMware Network Adapter VMnet1 IP 地址冲突导致无法打开路由器管理页面

问题表现 运行 ipconfig&#xff1a; 以太网适配器 以太网:连接特定的 DNS 后缀 . . . . . . . : lanIPv4 地址 . . . . . . . . . . . . : 192.168.1.226子网掩码 . . . . . . . . . . . . : 255.255.255.0默认网关. . . . . . . . . . . . . : 192.168.1.1以太网适配器 VM…

IM6ULL学习第18章Linux 系统对中断的处理

栈 什么是栈 栈是一段内存空间。ARM处理器程序的运行过程 ARM芯片属于精简指令集(RISC&#xff1a;Reduced Instruction Set Computing) 特点&#xff1a; 1、对内存只有读和写两种指令&#xff0c; 2、所有的数据运算都是在CPU内部完成的。举例实现aab; CPU 先在内存中读…