GLSL-使用Subroutines选择着色器功能
2012-09-01 19:36
225 查看
http://blog.csdn.net/xiajun07061225/article/details/7664336
在GLSL中,subroutine是这样一种机制:它根据某个变量的值把一个函数调用和一个函数定义集合中的某一个函数定义绑定起来。在很多方面它和C语言中的函数指针类似。一个全局变量充当指针,用来调用函数。可以在OpenGL中设置这个变量的值,这样可以把它和多个函数定义中的一个绑定起来。subroutine中的函数定义不一定要同名,但是必须要有同等数量和相同类型的参数以及相同的返回类型
Subroutines提供了在运行时刻不用切换着色器或者是重新编译或者是使用if判断就能选择不同实现功能的方法。例如,一个着色器里面可以实现多种算法用来在场景中渲染不同的对象。当渲染场景的时候,我们可以通过改变subroutines的全局变量的值来选择合适的渲染算法而不是去通过切换着色器或者是使用条件判断来实现。
注意:由于性能在着色器中越来越重要,所以避免条件判断或着色器切换是很有必要的。有了subroutines,我们就能够在不增加计算负载的情况下实现条件判断和着色器切换的功能。
下面用一个例子来进行说明。在这个例子中,采用subroutine渲染了两次茶壶。分别采用不同的光照模型。第一次用ADS(ambient,diffuse,specular)模型进行渲染,第二次只用diffuse模型渲染。一个subroutine全局变量用来选择渲染算法。下面两幅图可以看出效果的对比。
左边是ADS模型渲染效果,右边是diffuse模型渲染效果。
下面介绍使用subroutines的步骤。
我们在vertex shader中进行subroutines的定义。
(1)首先是定义subroutine类型:
subroutine vec3 shadeModelType( vec4 position, vec3 normal);
上面的代码定义了一个新的subroutine类型,其名字是shadeModelType。其语意和函数原型很类似。它定义了一个名字,一个参数列表和返回类型,参数名不是必须的。
(2)紧接着我们定义一个上述类型的uniform变量shadeModel:
subroutine uniform shadeModelType shadeModel;
这个变量充当了函数指针的作用,它在OpenGL应用程序中将会被赋值为两个可能的函数之一。
(3)定义两个函数,作为subroutine的一部分。
它们都有一个前缀是:
subroutine( shadeModelType )
其意味着函数和subroutine类型匹配。我们使用这个前缀定义了两个函数:
[cpp]
view plaincopyprint?
subroutine( shadeModelType )
vec3 phongModel( vec4 position, vec3 norm )
{
vec3 s = normalize(vec3(Light.Position - position));
vec3 v = normalize(-position.xyz);
vec3 r = reflect( -s, norm );
vec3 ambient = Light.La * Material.Ka;
float sDotN = max( dot(s,norm), 0.0 );
vec3 diffuse = Light.Ld * Material.Kd * sDotN;
vec3 spec = vec3(0.0);
if( sDotN > 0.0 )
spec = Light.Ls * Material.Ks *
pow( max( dot(r,v), 0.0 ), Material.Shininess );
return ambient + diffuse + spec;
}
subroutine( shadeModelType )
vec3 diffuseOnly( vec4 position, vec3 norm )
{
vec3 s = normalize( vec3(Light.Position - position) );
return
Light.Ld * Material.Kd * max( dot(s, norm), 0.0 );
}
在vertex shader的main函数中,我们使用subroutine的uniform变量shadeModel来调用定义的两个函数。
LightIntensity = shadeModel( eyePosition, eyeNorm );
这样,根据uniform变量shadeModel的值,这个调用会被绑定到上述我们定义的两个函数之一。
(5)给subroutine uniform变量赋值。
分两步进行。
1、使用glGetSubroutineIndex函数查询每个subroutine函数的索引。
[cpp]
view plaincopyprint?
GLuint adsIndex = glGetSubroutineIndex( programHandle,
GL_VERTEX_SHADER,
"phongModel" );
GLuint diffuseIndex = glGetSubroutineIndex(programHandle,
GL_VERTEX_SHADER,
"diffuseOnly");
2、为了选择合适的subroutine函数,我们需要给subroutine uniform变量shadeModel赋值。采用如下函数调用实现:
glUniformSubroutinesuiv( GL_VERTEX_SHADER, 1, &adsIndex);
这个函数可以一次设置多个uniform变量值。第一个参数指定着色阶段。第二个是要设定的uniform变量的数量。这里只需要设置一个uniform变量的值。
如果要设置多个,那么第三个参数应该是个数组,通常数组中的第i个元素赋值给subroutine uniform变量中索引为i的那个。
这里只需要设置一个值,我们设置的是索引为0 的那么subroutine uniform变量。
注意:OpenGL中,uniform 变量的索引默认就是从0开始的。如果有多个变量需要设置,可以用 glGetSubroutineUniformLocation()查询。
接下来进行渲染就可以得出相应的效果了。
要进行另外一种效果的渲染只需调用下面函数:
glUniformSubroutinesuiv( GL_VERTEX_SHADER, 1, &diffuseIndex);
再进来渲染过程即可。
在GLSL中,subroutine是这样一种机制:它根据某个变量的值把一个函数调用和一个函数定义集合中的某一个函数定义绑定起来。在很多方面它和C语言中的函数指针类似。一个全局变量充当指针,用来调用函数。可以在OpenGL中设置这个变量的值,这样可以把它和多个函数定义中的一个绑定起来。subroutine中的函数定义不一定要同名,但是必须要有同等数量和相同类型的参数以及相同的返回类型
Subroutines提供了在运行时刻不用切换着色器或者是重新编译或者是使用if判断就能选择不同实现功能的方法。例如,一个着色器里面可以实现多种算法用来在场景中渲染不同的对象。当渲染场景的时候,我们可以通过改变subroutines的全局变量的值来选择合适的渲染算法而不是去通过切换着色器或者是使用条件判断来实现。
注意:由于性能在着色器中越来越重要,所以避免条件判断或着色器切换是很有必要的。有了subroutines,我们就能够在不增加计算负载的情况下实现条件判断和着色器切换的功能。
下面用一个例子来进行说明。在这个例子中,采用subroutine渲染了两次茶壶。分别采用不同的光照模型。第一次用ADS(ambient,diffuse,specular)模型进行渲染,第二次只用diffuse模型渲染。一个subroutine全局变量用来选择渲染算法。下面两幅图可以看出效果的对比。
左边是ADS模型渲染效果,右边是diffuse模型渲染效果。
下面介绍使用subroutines的步骤。
我们在vertex shader中进行subroutines的定义。
(1)首先是定义subroutine类型:
subroutine vec3 shadeModelType( vec4 position, vec3 normal);
上面的代码定义了一个新的subroutine类型,其名字是shadeModelType。其语意和函数原型很类似。它定义了一个名字,一个参数列表和返回类型,参数名不是必须的。
(2)紧接着我们定义一个上述类型的uniform变量shadeModel:
subroutine uniform shadeModelType shadeModel;
这个变量充当了函数指针的作用,它在OpenGL应用程序中将会被赋值为两个可能的函数之一。
(3)定义两个函数,作为subroutine的一部分。
它们都有一个前缀是:
subroutine( shadeModelType )
其意味着函数和subroutine类型匹配。我们使用这个前缀定义了两个函数:
[cpp]
view plaincopyprint?
subroutine( shadeModelType )
vec3 phongModel( vec4 position, vec3 norm )
{
vec3 s = normalize(vec3(Light.Position - position));
vec3 v = normalize(-position.xyz);
vec3 r = reflect( -s, norm );
vec3 ambient = Light.La * Material.Ka;
float sDotN = max( dot(s,norm), 0.0 );
vec3 diffuse = Light.Ld * Material.Kd * sDotN;
vec3 spec = vec3(0.0);
if( sDotN > 0.0 )
spec = Light.Ls * Material.Ks *
pow( max( dot(r,v), 0.0 ), Material.Shininess );
return ambient + diffuse + spec;
}
subroutine( shadeModelType )
vec3 diffuseOnly( vec4 position, vec3 norm )
{
vec3 s = normalize( vec3(Light.Position - position) );
return
Light.Ld * Material.Kd * max( dot(s, norm), 0.0 );
}
subroutine( shadeModelType ) vec3 phongModel( vec4 position, vec3 norm ) { vec3 s = normalize(vec3(Light.Position - position)); vec3 v = normalize(-position.xyz); vec3 r = reflect( -s, norm ); vec3 ambient = Light.La * Material.Ka; float sDotN = max( dot(s,norm), 0.0 ); vec3 diffuse = Light.Ld * Material.Kd * sDotN; vec3 spec = vec3(0.0); if( sDotN > 0.0 ) spec = Light.Ls * Material.Ks * pow( max( dot(r,v), 0.0 ), Material.Shininess ); return ambient + diffuse + spec; } subroutine( shadeModelType ) vec3 diffuseOnly( vec4 position, vec3 norm ) { vec3 s = normalize( vec3(Light.Position - position) ); return Light.Ld * Material.Kd * max( dot(s, norm), 0.0 ); }(4)函数调用
在vertex shader的main函数中,我们使用subroutine的uniform变量shadeModel来调用定义的两个函数。
LightIntensity = shadeModel( eyePosition, eyeNorm );
这样,根据uniform变量shadeModel的值,这个调用会被绑定到上述我们定义的两个函数之一。
(5)给subroutine uniform变量赋值。
分两步进行。
1、使用glGetSubroutineIndex函数查询每个subroutine函数的索引。
[cpp]
view plaincopyprint?
GLuint adsIndex = glGetSubroutineIndex( programHandle,
GL_VERTEX_SHADER,
"phongModel" );
GLuint diffuseIndex = glGetSubroutineIndex(programHandle,
GL_VERTEX_SHADER,
"diffuseOnly");
GLuint adsIndex = glGetSubroutineIndex( programHandle, GL_VERTEX_SHADER, "phongModel" ); GLuint diffuseIndex = glGetSubroutineIndex(programHandle, GL_VERTEX_SHADER, "diffuseOnly");第一个参数是程序的句柄。第二个是着色器。第三个是subroutine的名字。查询到的索引存储在两个GLuint型的值中。
2、为了选择合适的subroutine函数,我们需要给subroutine uniform变量shadeModel赋值。采用如下函数调用实现:
glUniformSubroutinesuiv( GL_VERTEX_SHADER, 1, &adsIndex);
这个函数可以一次设置多个uniform变量值。第一个参数指定着色阶段。第二个是要设定的uniform变量的数量。这里只需要设置一个uniform变量的值。
如果要设置多个,那么第三个参数应该是个数组,通常数组中的第i个元素赋值给subroutine uniform变量中索引为i的那个。
这里只需要设置一个值,我们设置的是索引为0 的那么subroutine uniform变量。
注意:OpenGL中,uniform 变量的索引默认就是从0开始的。如果有多个变量需要设置,可以用 glGetSubroutineUniformLocation()查询。
接下来进行渲染就可以得出相应的效果了。
要进行另外一种效果的渲染只需调用下面函数:
glUniformSubroutinesuiv( GL_VERTEX_SHADER, 1, &diffuseIndex);
再进来渲染过程即可。
相关文章推荐
- 【OpenGL4.0】GLSL-使用Subroutines选择着色器功能
- drupal7级联选择和自动填充功能的使用
- 使用百度地图SDK开发选择地址功能遇到的问题总结
- Angalarjs之上拉菜单(ActionSheet)实现使用拍照和选择图库的方式上传头像功能
- 右键菜单的“打开方式―选择程序”功能不能使用
- 有效的使用和设计COM智能指针——条款3:按照功能和实现原理选择合适的智能指针
- 在DevExpress程序中使用GridView直接录入数据的时候,增加列表选择的功能
- 如果选择使用SharePoint server 2016 你必须知道----这些功能已经被删除。
- 微信小程序使用picker实现时间和日期选择框功能【附源码下载】
- wheel自定义控件,实现城市三级联动,时间选择的功能简单使用
- 安卓设置默认应用功能失效,设置后仍然总是反复提示选择默认使用的应用
- asp.net下使用jQuery.AutoComplete完成仿淘宝商品搜索自动完成功能(改进了键盘上下选择体验)
- 微信小程序使用checkbox显示多项选择框功能【附源码下载】
- UICollectionView使用storyBoard完成设置自动布局,并附带简单选择功能
- 使用shell提供的命令行编辑功能, 选择set -o vi 还是 set -o emacs !
- 在DevExpress程序中使用GridView直接录入数据的时候,增加列表选择的功能
- linux下使用hiredis异步API实现sub/pub消息订阅和发布的功能 标签: hiredishiredis异步APIhiredis事件处理redis消息订阅发布redis c接口 2016-
- 【OpenGL4.0】GLSL-使用Uniform Block实现着色器的数据共享
- Android:使用百度地图SDK定位当前具体位置(类似QQ发表说说的选择地点功能)
- wheel自定义控件,实现城市三级联动,时间选择的功能简单使用