sim*_*eon 10 opengl glsl wrapper ios
更新:因为我马上就需要一些东西,所以我创建了一个简单的着色器包装器来完成我需要的东西.你可以在这里找到它:GitHub上的ShaderManager.请注意,它是为Objective-C/iOS设计的,因此对每个人都没有用.如果您对设计改进有任何建议,请告诉我们!
原始问题:
我是新手使用GLSL着色器.我对GLSL语言和OpenGL界面非常熟悉,但是我在设计一个简单的API时遇到了麻烦,通过它可以使用着色器.
用于与着色器交互的OpenGL C接口似乎很麻烦.我似乎无法在网上找到任何涵盖这类内容的API设计的教程.
我的问题是:任何人都有一个好的,简单的API设计或模式来包装OpenGL着色器程序API吗?
采用以下简单示例.假设我有一个顶点着色器,它只是模拟固定功能,还有两个片段着色器 - 一个用于绘制平滑矩形,另一个用于绘制平滑圆.我有以下文件:
Shader.vsh : Simple vertex shader, with the following inputs/outputs:
-- Uniforms: mat4 Model, mat4 View, mat4 Projection
-- Attributes: vec4 Vertex, vec2 TexCoord, vec4 Color
-- Varying: vec4 vColor, vec2 vTexCoord
Square.fsh : Fragment shader for drawing squares based on tex coord / color
Circle.fsh : Fragment shader for drawing circles based on tex coord / color
Run Code Online (Sandbox Code Playgroud)
现在使用这些的标准方法是什么?我是否将上述着色器链接到两个OpenGL着色器程序中?那是:
Shader.vsh + Square.fsh = SquareProgram
Shader.vsh + Circle.fsh = CircleProgram
Run Code Online (Sandbox Code Playgroud)
或者我是否创建一个大程序,其中片段着色器检查一些条件统一变量并调出着色器函数以生成其结果.例如:
Shader.vsh + Square.fsh + Circle.fsh + Main.fsh = ShaderProgram
//Main.fsh here would simply check whether to call out to square or circle
Run Code Online (Sandbox Code Playgroud)
有两个单独的程序,我可能需要打电话
glUseProgram(CircleProgram); or glUseProgram(SquareProgram);
Run Code Online (Sandbox Code Playgroud)
在我想要绘制的每种元素之前.然后我需要在使用它之前设置每个程序的制服(模型/视图/投影)和属性.这看起来很笨重.
使用单个ShaderProgram选项,我仍然需要在片段着色器中设置某种布尔开关(圆形或方形),在绘制每个像素之前将对其进行检查.这似乎也很复杂.
作为旁注,我是否允许将两个片段着色器(每个具有main()函数)链接到一个着色器程序中?OpenGL如何知道要调用哪一个?
电话:
glUniform*
glVertexAttribPointer
Run Code Online (Sandbox Code Playgroud)
用于在当前程序上设置制服和属性指针位置.
不同的类和结构可能需要从代码中的不同位置访问和设置当前着色器上的变量(或更改当前着色器).我想不出一个很好的方法来将着色器代码与想要使用它的代码分离开来.
也就是说,我想要绘制的每个形状都需要设置顶点和纹理坐标属性 - 需要处理由OpenGL生成的那些属性.
相机需要在顶点着色器中将其投影矩阵设置为均匀,而管理模型矩阵堆栈的类需要在顶点着色器中设置自己的均匀.
通过绘制场景来中途改变着色器将意味着所有这些类将需要再次设置其制服和属性.
大多数人如何设计这个?
通过句柄或名称访问的着色器的全局字典,其参数包含getter和setter?
具有着色器对象的OO设计,每个对象都有参数?
我看了下面的包装器:
Jon的Teapot:GLSL着色器管理器 - 它在C++类中包装着色器.它似乎只是一个在C API上强制执行OO原则的包装器,导致C++ API大致相同.
我正在进行任何简化Shader程序使用的设计,并不关心使用的特定范例(OO,程序等)
我认为这是标签与iOS,所以如果你偏爱的Objective-C,我会采取在杰夫·拉马什的GLProgram包装类,其中他介绍了一个很好看这里,有可用的源位置.我在自己的应用程序中使用它来简化一些着色器程序设置,并使代码更清洁.
例如,您可以使用如下代码设置着色器及其属性和制服:
sphereDepthProgram = [[GLProgram alloc] initWithVertexShaderFilename:@"SphereDepth" fragmentShaderFilename:@"SphereDepth"];
[sphereDepthProgram addAttribute:@"position"];
[sphereDepthProgram addAttribute:@"inputImpostorSpaceCoordinate"];
if (![sphereDepthProgram link])
{
NSLog(@"Depth shader link failed");
NSString *progLog = [sphereDepthProgram programLog];
NSLog(@"Program Log: %@", progLog);
NSString *fragLog = [sphereDepthProgram fragmentShaderLog];
NSLog(@"Frag Log: %@", fragLog);
NSString *vertLog = [sphereDepthProgram vertexShaderLog];
NSLog(@"Vert Log: %@", vertLog);
[sphereDepthProgram release];
sphereDepthProgram = nil;
}
sphereDepthPositionAttribute = [sphereDepthProgram attributeIndex:@"position"];
sphereDepthImpostorSpaceAttribute = [sphereDepthProgram attributeIndex:@"inputImpostorSpaceCoordinate"];
sphereDepthModelViewMatrix = [sphereDepthProgram uniformIndex:@"modelViewProjMatrix"];
sphereDepthRadius = [sphereDepthProgram uniformIndex:@"sphereRadius"];
Run Code Online (Sandbox Code Playgroud)
当您需要使用着色器程序时,您可以执行以下操作:
[sphereDepthProgram use];
Run Code Online (Sandbox Code Playgroud)
这并没有解决上面提到的分支与单个着色器的问题,但Jeff的实现确实提供了一些OpenGL ES样板着色器设置代码的很好的封装.
基本链接:
这里没有标准的方法.至少有两种一般方法:
单片 - 一个着色器覆盖许多情况,使用统一的布尔开关.这些分支不会损害性能,因为条件结果对于任何片段组都是恒定的(实际上,对于所有片段).
多目标程序合成 - 主着色器声明一组入口点(如'get_diffuse','get_specular'等),这些入口点在附加的单独着色器对象中实现.这意味着每个对象都有单独的着色器,但任何类型的缓存都有帮助.
设置变量:制服
我将描述我开发的方法.
每个着色器程序都有一个统一字典列表.它用于在程序(重新)链接时填充统一源列表.程序激活后,它会通过统一列表,从其来源获取值并将它们上传到GL.在结果中,数据不直接与用户着色器程序相关联,并且管理它的任何内容都不关心使用它的程序.
例如,这些词典中的一个可以是核心词典,包含模型,视图变换,相机投影以及其他可能的其他词典.
设置变量:属性
首先,着色器程序是一个属性使用者,因此必须从网格(或任何其他数据存储)中提取这些属性,并以它需要的方式将它们上传到GL.它还应确保提供的属性类型与请求的类型匹配.
当使用单片着色器方法时,如果禁用的分支方式需要未提供的顶点属性,则可能存在令人不快的情况.我建议使用另一个属性的数据来提供缺失的数据,因为在这种情况下我们不关心实际值.
PS您可以在此处找到这些想法的实际实现:http://code.google.com/p/kri/
| 归档时间: |
|
| 查看次数: |
6823 次 |
| 最近记录: |