可以在这里找到关于3D API渲染管线的总体解释。这个教程指导您从零开始创建一个新的Shader
。而这个教程展示了如何使用自定义属性将数据传递给着色器。这个维基页面还解释了如何使用Material
Attributes
以及DefaultShader
支持哪些Attributes
。
在LibGDX中,Shader
和ShaderProgram
之间有所不同。 ShaderProgram
只是GPU实现(包括顶点和片段着色器程序),基本上只是编译后的GLSL文件。例如,您可以在ShaderProgram
上设置uniform并使用它来渲染网格。但是,ShaderProgram
本身并不“知道”它应该如何渲染模型。
Shader
接口旨在弥合ShaderProgram
和Renderable
(后者是模型的最小可渲染部分)之间的差距。因此,Shader
通常封装了一个ShaderProgram
,并确保设置正确的uniform等(请注意,严格来说,Shader
不必封装一个ShaderProgram
。例如,在移除GLES1支持之前,还有一个GLES1着色器,它管理固定的渲染管道而不是封装一个ShaderProgram
)。
BaseShader
类是一个abstract
帮助类,实现了Shader
接口,封装了一个ShaderProgram
并添加了一些帮助方法以轻松设置uniform。如果您扩展这个类,您可以很容易地register
和set
uniform,例如:
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);
}
}
这将设置名为"u_falloff"的uniform变量为指定值15f
(它将调用setUniformX)。如果ShaderProgram
(glsl文件)没有实现称为"u_falloff"的uniform变量,则简单地忽略该调用。您也可以使用以下代码进行检查:if (has(u_falloff)) { /* 计算falloff并设置它 */ }
。 BaseShader
还为每个uniform添加了一个Validator
和Setter
的可能性。
DefaultShader
扩展BaseShader
,并为大多数Material Attributes
添加了默认实现。如果您希望查看每个uniform变量的命名,请查看源代码。在实践中,如果你使用与DefaultShader相同的uniform变量命名,则可以仅指定glsl文件,让DefaultShader来设置uniform变量。当然,您可以扩展DefaultShader以添加其他uniform变量。
当您调用ModelBatch#render(...)
时,ModelBatch
会向ShaderProvider
查询要使用的Shader
。这是因为每种可能的顶点属性和材质属性都可能需要不同的Shader
。例如,如果您有两个ModelInstance
(或更准确地说是两个Renderable
),其中一个具有TextureAttribute.Diffuse
,而另一个没有纹理但具有ColorAttribute.Diffuse
。那么最常见的情况是,ShaderProvider需要创建两个不同的Shader
。注意它们可以是相同的类(例如DefaultShader),但底层的GLSL文件可能是不同的。
DefaultShader
使用预处理器宏(ubershader)来处理这个问题。根据顶点属性和材质属性,它将#define
多个标志,导致glsl程序专门为该组合的顶点和材质属性编译。如果您想了解如何完成此操作,请查看glsl文件。
因此,在实践中,您可能需要自己的ShaderProvider
和自己的Shader
(通过从头开始实现、扩展BaseShader
或扩展DefaultShader
)。您可以扩展DefaultShaderProvider
并在需要时回退到DefaultShader
,例如:
public class MyShaderProvider extends DefaultShaderProvider {
...
@Override
protected Shader createShader (final Renderable renderable) {
if (renderable.material.has(MyCustomAttribute.Type))
return new MyShader(renderable);
else
return super.createShader(renderable);
}
}
简而言之,如果您想使用自己的或修改后的ubershader,并使用与默认着色器相同的uniforms,那么只需提供glsl文件即可。如果您想使用相同的uniforms但添加一个或两个额外的uniforms,那么扩展DefaultShader可能很容易。否则(或者如果您正在学习着色器),我建议按照此教程从头开始创建着色器。
BaseShader
会为您绑定网格,包括顶点属性(例如a_tangent
),只需在渲染方法的末尾调用super.render(renderable);
即可。是的,请查看BaseShaderProvider
(https://github.com/libgdx/libgdx/blob/master/gdx/src/com/badlogic/gdx/graphics/g3d/utils/BaseShaderProvider.java),这是DefaultShaderProvider
扩展的内容。只有当它没有可重用的Shader
时,才会调用createShader
。compareTo
与此无关,仅用于对Renderable
进行排序(您可以安全地忽略它并返回0
)。 - XoppaTextureatrribute.diffuse
来设置我的纹理,并使用TextureAttribute.Normal
来设置其法线贴图。现在我感觉有点傻,因为找到所有这些东西有点困难。有太多的可能性了。再次感谢。+1并接受! - Robert PCustomShaderProvider
,我能够使用正确的Renderable
初始化CustomShader
。但由于某种原因,它只显示黑屏。ShaderProgram
本身是有效的,因为我首先使用默认的Shader
进行了测试。当我扩展BaseShader
时,是否有任何需要注意的事项?我复制了您的Shader
教程代码,并用BaseShader
的Setter
替换了program.setUniformX
。此外,我总是调用super.xxx()并让BaseShader
渲染物体,但是出现了问题... - Robert P