我在我的wip游戏中达到了一个点,我想让它更吸引眼球。目前,我向Ambientlight
添加了一些Directionla-light
和Environment
,并使用它渲染我的场景。但现在我想为它添加一个自定义Shader
。所以我一直在寻找一些教程,并且出于某种原因,在几乎每个教程中他们都使用了另一个"版本"在他们的游戏中使用Shader
:
ModelBatch
一个String
或FileHandle
vertex/fragment
- 着色器ShaderProgram
创建Shader
。DefaultShader
创建新的Shader
。Shader
并使用此ShaderClass
。我认为还有更多的可能性,因为还有ShaderProvider
和其他课程
所有这些可能性让我有点困惑。所以我正在寻找能指出正确方向的人
为了方便你,我告诉你我拥有什么和我需要什么:
我有:
ModelBatch
。Array<ModelInstance>
个实例,我想应用Shader
。Texture
及其NormalMap
,均存储为Texture
。position
,direction
和color
,Vector3
,强度为float
。color
及其强度,以Vector3
和float
给出。Vector3
为准。我需要:
Texture
及其Normal Map
绑定到Shader
。Shader
。Shader
。Falloff
向量提供给Shader
。Shader
用于所有&#34;实例&#34;在Array
中,这些都是使用我的ModelBatch
。我希望能够做的另一件事是,对不同的模型使用不同的Texture
。
我的所有ModleInstance
都带有纹理Material
。我有所有不同Texture
s的法线贴图。现在我希望能够将Texture
和Normal Map
绑定到Shader
,具体取决于Texture
Material
中的Modelinstance
}。
更多&#34;高级&#34;事情,我想如果有可能的话,在我的游戏中使用不同的Shader
用于不同的ModelTypes
(Stonewall使用Shader
而没有&#34; Specularity&#34;和& #34;反思&#34;,而Metalwalls例如使用Specularity
。
在Libgdx中做这件事最好的方法是什么?
我如何绑定我拥有的不同变量? (使用ShaderProgram我可以使用setUniformi
)。
非常感谢。如果您需要更多信息或者难以理解,请告诉我,我会尝试创建一个更好的问题。
编辑:我认为在我的情况下创建新Shader
类的最佳方法是实现Shader
。但我想了解所有其他可能性,它们的优点和缺点,包括设计,性能和可能的限制。
答案 0 :(得分:14)
可以找到渲染3d api管道的整体说明here。 This tutorial指导您从头开始创建新的Shader
。 this tutorial显示了如何使用自定义属性将数据传递到着色器。 This wiki page还解释了如何使用Material
Attributes
以及Attributes
支持的DefaultShader
。
在LibGDX中,Shader
和ShaderProgram
之间存在差异。 ShaderProgram
只是GPU实现(顶点和片段着色器程序),它基本上只是已编译的GLSL文件。例如,您可以在ShaderProgram
上设置制服并使用它来渲染网格。但是ShaderProgram
本身并不知道&#34;如何渲染模型。
Shader
接口旨在弥合ShaderProgram
和Renderable
之间的差距(后者是模型中最小的可渲染部分)。因此,Shader
最常封装ShaderProgram
,并确保设置正确的制服等。(请注意,严格来说Shader
不必封装ShaderProgram
例如,在删除GLES1支持之前,还有一个GLES1着色器管理固定渲染管道而不是封装ShaderProgram
)
BaseShader
类是一个abstract
辅助类,它实现了Shader
接口,封装了ShaderProgram
并添加了一些辅助方法来轻松设置制服。如果您扩展此课程,则可以轻松register
和set
统一,例如像这样:
public class MyShader extends BaseShader {
public final int u_falloff = register("u_falloff");
...
@Override
public void render (final Renderable renderable) {
set(u_falloff, 15f);
...
super.render(renderable);
}
}
这将设置称为&#34; u_falloff&#34;到指定值15f
(它将调用setUniformX)。如果ShaderProgram
(glsl文件)没有实现名为&#34; u_falloff&#34;的统一,则它将忽略该调用。您也可以使用if (has(u_falloff)) { /* calculate falloff and set it */ }
进行检查。 BaseShader
还增加了为每件制服使用Validator
和Setter
的可能性。
DefaultShader
扩展了BaseShader
,并为大多数Material
Attributes
添加了默认实施。如果您想查看每件制服的命名,请查看at the source。实际上,如果使用与DefaultShader相同的统一命名,则可以仅指定glsl文件,并让DefaultShader负责设置制服。当然可以扩展DefaultShader以添加额外的制服。
当您致电ModelBatch#render(...)
时,ModelBatch
会向ShaderProvider
查询要使用的Shader
。这是因为顶点属性和材质属性的每种可能组合可能需要不同的Shader
。例如,如果您有两个ModelInstance
s(或更精确的两个Renderable
s),一个TextureAttribute.Diffuse
,一个没有纹理,但ColorAttribute.Diffuse
。最常见的是,ShaderProvider需要创建两个不同的Shader
。请注意,它们可以是同一个类(例如DefaultShader),但底层GLSL文件可能不同。
DefaultShader
使用预处理器宏(ubershader)来处理这个问题。根据顶点属性和材质属性,它将#define
多个标志,导致glsl程序专门针对顶点和材质属性的组合进行编译。如果您想了解如何完成此操作,请查看the glsl files。
因此,在实践中,您可能需要拥有ShaderProvider
和您自己的Shader
(通过从头开始实施,扩展BaseShader
或扩展DefaultShader
)。您可以为此扩展DefaultShaderProvider
,如果需要,可以回退到DefaultShader
,例如:
public class MyShaderProvider extends DefaultShaderProvider {
... // implement constructor
@Override
protected Shader createShader (final Renderable renderable) {
if (renderable.material.has(MyCustomAttribute.Type))
return new MyShader(renderable);
else
return super.createShader(renderable);
}
}
tl; dr如果您想使用自己的或者修改过的ubershader版本,使用与默认着色器相同的制服,那么只需提供glsl文件即可。如果你想使用相同的制服但是增加一两件制服,那么扩展DefaultShader可能很容易。否则(或者如果您正在学习着色器)我建议按照This tutorial中的描述从头开始创建着色器。