39 WebGL着色器和着色器程序对象:initShader()函数的作用
2017-06-12 11:20
232 查看
这一节,我们研究一下以前一直使用的辅助函数initShader()。
之前教程当中故意把这个函数中留到最后讲解,是为了确保学习initShaders()函数中的复杂细节时,对WebGL已经有了比较深入的了解。掌握这一部分内容不是必须的,直接使用initShaders()函数也能够编写出相当不错的WebGL程序。
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中,一个程序对象必须包含一个顶点着色器和一个片元着色器。
创建着色器对象(gl.createShader())
所有的着色器对象都必须通过调用gl.createShader()来创建
gl.createShader()函数根据传入的参数创建一个顶点着色器或者片元着色器。如果不需要这个着色器,可以使用gl.deleteShader()函数来删除着色器。
注意,如果着色器对象还在使用(也就是说已经使用gl.attachShader()函数使之附加在了程序对象上),那么gl.deleteShader()并不会立刻删除着色器,二十要等到程序对象不再使用该着色器后,才将其删除。
指定着色器对象的代码(gl.shaderSource())
通过gl.shaderSource()函数向着色器指定GLSL ES源代码。
编译着色器(gl.compileShader())
向着色器对象传入源代码之后,还需要对其进行编译才能够使用。GLSL ES语言和JavaScript不同而更接近C或C++,在使用之前需要编译成二进制的可执行格式,WebGL系统真正使用的是这种可执行格式。使用gl.compileShader()函数进行编译。注意,如果你通过调用gl.shaderSource(),用新的代码替换掉了着色器中旧的代码,WebGL系统中的用旧的代码编译出的可执行部分不会被自动替换,你需要手动地重新进行编译。
当调用gl.compileShader()函数时,如果着色器源代码中存在错误,那么就会出现编译错误。可以调用gl.getShaderParameter()函数来检查着色器的状态。
调用gl.getShaderParameter()并将参数pname指定为gl.COMPILE_STATUS,就可以检查着色器编译是否成功。
如果编译失败,gl.getShaderParameter()会返回false,WebGL系统会把编译错误的具体内容写入着色器的信息日志(information log),我们可以通过gl.getShaderInfoLog()来获取。
虽然日志信息的具体格式依赖于浏览器对WebGL的实现,但大多数WebGL系统给出的错误信息都会包含代码出错行的行号。比如,如果你视图编译如下这样的一个着色器:
创建程序对象(gl.createProgram())
程序对象包含了顶点着色器和片元着色器,可以调用gl.createProgram()来创建程序对象。事实上,之前使用程序对象,gl.getAttribLocation()和gl.getUniformLocation()函数的第一个函数,就是这个程序对象。
可以使用gl.deleteProgram()函数来删除程序对象。
一旦程序对象被创建之后,需要向程序附上两个着色器。
为程序对象分配着色器对象(gl.attachShader())
WebGL系统要运行起来,必须要有两个着色器:一个顶点着色器和一个片元着色器。可以使用gl.attachShader()函数为程序对象分配这两个着色器。
.
着色器在附给程序对象前,并不一定要为其制定代码或进行编译(也就是说,把空的着色器附给程序对象也是可以的)。类似的,可以使用gl.detachShader()函数来解除分配给程序对象的着色器。
连接程序对象(gl.linkProgram())
在为程序对象分配了两个着色器对象后,还需要将顶点着色器和片元着色器连接起来。使用gl.linkProgram()函数来进行这一步操作。
程序对象进行着色器连接操作,目的是保证:
(1)顶点着色器和片元着色器的varying变量同名同类型,且一一对应
(2)顶点着色器对每个varying变量赋了值
(3)顶点着色器和片元着色器中的同名uniform变量也是同类型的(无需一一对应,即某些uniform变量可以出现在一个着色器中而不出现在另一个中)
(4)着色器中的attribute变量、uniform变量和varying变量的个数没有超过着色器的上线,等等。
在着色器连接之后,应当检查是否连接成功。通过调用gl.getProgramPara-meters()函数来实现。(程序对象即使连接成功了,也有可能运行失败,比如没有为取样器分配纹理单元。这写错误是在运行阶段而不是连接阶段产生的。在运行阶段进行错误检查的性能开销很大,所以通常只在调试程序时这样做。)
如果程序已经成功连接,我们就得到了一个二进制的可执行模块供WebGL系统使用。如果连接失败了,也可以通过调用gl.getProgramInfoLog()从信息日志中获取连接出错信息。
告知WebGL系统所使用的程序对象(gl.useProgram())
最后,通过调用gl.useProgramUI告知WebGL系统绘制时使用哪个程序对象。
这个函数的存在使得WebGL具有了一个强大的特性,那就是在绘制前准备多个程序对象,然后在绘制的时候根据需要切换对象。
之前教程当中故意把这个函数中留到最后讲解,是为了确保学习initShaders()函数中的复杂细节时,对WebGL已经有了比较深入的了解。掌握这一部分内容不是必须的,直接使用initShaders()函数也能够编写出相当不错的WebGL程序。
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中,一个程序对象必须包含一个顶点着色器和一个片元着色器。
创建着色器对象(gl.createShader())
所有的着色器对象都必须通过调用gl.createShader()来创建
gl.createShader()函数根据传入的参数创建一个顶点着色器或者片元着色器。如果不需要这个着色器,可以使用gl.deleteShader()函数来删除着色器。
注意,如果着色器对象还在使用(也就是说已经使用gl.attachShader()函数使之附加在了程序对象上),那么gl.deleteShader()并不会立刻删除着色器,二十要等到程序对象不再使用该着色器后,才将其删除。
指定着色器对象的代码(gl.shaderSource())
通过gl.shaderSource()函数向着色器指定GLSL ES源代码。
编译着色器(gl.compileShader())
向着色器对象传入源代码之后,还需要对其进行编译才能够使用。GLSL ES语言和JavaScript不同而更接近C或C++,在使用之前需要编译成二进制的可执行格式,WebGL系统真正使用的是这种可执行格式。使用gl.compileShader()函数进行编译。注意,如果你通过调用gl.shaderSource(),用新的代码替换掉了着色器中旧的代码,WebGL系统中的用旧的代码编译出的可执行部分不会被自动替换,你需要手动地重新进行编译。
当调用gl.compileShader()函数时,如果着色器源代码中存在错误,那么就会出现编译错误。可以调用gl.getShaderParameter()函数来检查着色器的状态。
调用gl.getShaderParameter()并将参数pname指定为gl.COMPILE_STATUS,就可以检查着色器编译是否成功。
如果编译失败,gl.getShaderParameter()会返回false,WebGL系统会把编译错误的具体内容写入着色器的信息日志(information log),我们可以通过gl.getShaderInfoLog()来获取。
虽然日志信息的具体格式依赖于浏览器对WebGL的实现,但大多数WebGL系统给出的错误信息都会包含代码出错行的行号。比如,如果你视图编译如下这样的一个着色器:
//片元着色器 var FSHADER_SOURCE = "" + "varying vec4 v_Color;\n" + "void main(){" + " gl.FragColor = v_Color;\n" + "}\n";代码的第二行出错了,在控制台显示的错误信息是:
创建程序对象(gl.createProgram())
程序对象包含了顶点着色器和片元着色器,可以调用gl.createProgram()来创建程序对象。事实上,之前使用程序对象,gl.getAttribLocation()和gl.getUniformLocation()函数的第一个函数,就是这个程序对象。
可以使用gl.deleteProgram()函数来删除程序对象。
一旦程序对象被创建之后,需要向程序附上两个着色器。
为程序对象分配着色器对象(gl.attachShader())
WebGL系统要运行起来,必须要有两个着色器:一个顶点着色器和一个片元着色器。可以使用gl.attachShader()函数为程序对象分配这两个着色器。
.
着色器在附给程序对象前,并不一定要为其制定代码或进行编译(也就是说,把空的着色器附给程序对象也是可以的)。类似的,可以使用gl.detachShader()函数来解除分配给程序对象的着色器。
连接程序对象(gl.linkProgram())
在为程序对象分配了两个着色器对象后,还需要将顶点着色器和片元着色器连接起来。使用gl.linkProgram()函数来进行这一步操作。
程序对象进行着色器连接操作,目的是保证:
(1)顶点着色器和片元着色器的varying变量同名同类型,且一一对应
(2)顶点着色器对每个varying变量赋了值
(3)顶点着色器和片元着色器中的同名uniform变量也是同类型的(无需一一对应,即某些uniform变量可以出现在一个着色器中而不出现在另一个中)
(4)着色器中的attribute变量、uniform变量和varying变量的个数没有超过着色器的上线,等等。
在着色器连接之后,应当检查是否连接成功。通过调用gl.getProgramPara-meters()函数来实现。(程序对象即使连接成功了,也有可能运行失败,比如没有为取样器分配纹理单元。这写错误是在运行阶段而不是连接阶段产生的。在运行阶段进行错误检查的性能开销很大,所以通常只在调试程序时这样做。)
如果程序已经成功连接,我们就得到了一个二进制的可执行模块供WebGL系统使用。如果连接失败了,也可以通过调用gl.getProgramInfoLog()从信息日志中获取连接出错信息。
告知WebGL系统所使用的程序对象(gl.useProgram())
最后,通过调用gl.useProgramUI告知WebGL系统绘制时使用哪个程序对象。
这个函数的存在使得WebGL具有了一个强大的特性,那就是在绘制前准备多个程序对象,然后在绘制的时候根据需要切换对象。
相关文章推荐
- 40 WebGL着色器和着色器程序对象:initShader()函数的内部流程
- 一个关于“OLE DB 提供程序 'sqloledb' 指出该对象中没有任何列”错误的解决方法
- symbian 程序的cpp文件的第一个函数老显示没有定义 undefined identifier 'CZFirstTest_Login_Form'
- JavaScript实现对象克隆函数clone( )的程序及分析
- 1.<%@Page%>中的Codebehind、AutoEventWireup、Inherits有何作用?
- <%@Page%>中的Codebehind、AutoEventWireup、Inherits有何作用?
- algo1-4.cpp 说明exit()函数作用的程序
- 【ThinkingInC++】22、函数必须用它特有的方式去改变外部的string对象
- 参数和函数对象转化调用道指令程序
- 未能处理对象 'select * from teacher.dbf'。OLE DB 提供程序 'microsoft.JET.OLEDB.4.0' 指出该对象中没有任何列。
- 说明exit()函数作用的程序
- what's in string? c语言string类函数实现汇总 都是学习使用指针的好例子啊(算是读书摘抄和笔记吧)
- ecshop中define('IN_ECS', true)的作用
- System.Globalization.CultureInfo.InvariantCulture在Silverlight程序中的作用
- 如何解决 X-code5.0中的iOS7.0SDK运行程序时,出现的以下问题:“Could not find a storyboard named 'Main' in bundle NSBundle”
- vs 程序运行时跳出 An unhandled exception of type 'System.Runtime.InteropServices.SEHException' occurred in 。。 错误
- 请问,在下面这个函数中m_pMainWnd = &dlg;的作用是什么?为什么我把这句话注释起来之后程序依然是正确的啊?
- ecshop中define('IN_ECS', true)的作用
- 编写一个程序,定义一个职工类,输入3个职工的编号、姓名、工资和年龄, 类中的成员函数实现输入、输出,在主函数中定义对象,并计算输出3个职工的平均工资。
- 说明exit()函数作用的程序