我最近在学习并实现自己的libgdx着色器技术。目前,我使用自定义的着色器提供者,根据对象的userdata值,在几个着色器之间进行选择。
public class MyShaderProvider extends DefaultShaderProvider {
public final DefaultShader.Config config;
final static String logstag = "ME.MyShaderProvider";
//known shaders
static public enum shadertypes {
prettynoise,
invert,
standardlibgdx,
noise,
distancefield,
conceptbeam
}
public MyShaderProvider (final DefaultShader.Config config) {
this.config = (config == null) ? new DefaultShader.Config() : config;
}
public MyShaderProvider (final String vertexShader, final String fragmentShader) {
this(new DefaultShader.Config(vertexShader, fragmentShader));
}
public MyShaderProvider (final FileHandle vertexShader, final FileHandle fragmentShader) {
this(vertexShader.readString(), fragmentShader.readString());
}
public MyShaderProvider () {
this(null);
}
public void testListShader(Renderable instance){
for (Shader shader : shaders) {
Gdx.app.log(logstag, "shader="+shader.getClass().getName());
Gdx.app.log(logstag, "can render="+shader.canRender(instance));
}
}
@Override
protected Shader createShader (final Renderable renderable) {
//pick shader based on renderables userdata?
shadertypes shaderenum = (shadertypes) renderable.userData;
if (shaderenum==null){
return super.createShader(renderable);
}
Gdx.app.log(logstag, "shaderenum="+shaderenum.toString());
switch (shaderenum) {
case prettynoise:
{
return new PrettyNoiseShader();
}
case invert:
{
String vert = Gdx.files.internal("shaders/invert.vertex.glsl").readString();
String frag = Gdx.files.internal("shaders/invert.fragment.glsl").readString();
return new DefaultShader(renderable, new DefaultShader.Config(vert, frag));
}
case noise:
{
return new NoiseShader();
}
case conceptbeam:
{
Gdx.app.log(logstag, "creating concept gun beam ");
return new ConceptBeamShader();
}
case distancefield:
{
return new DistanceFieldShader();
}
default:
return super.createShader(renderable);
}
//return new DefaultShader(renderable, new DefaultShader.Config());
}
}
这似乎有效。
我有一个应用了噪声着色器的物体,动画效果良好。我有一个应用了反转纹理着色器的物体,同样看起来很好。
我有一堆其他物体使用默认的着色器进行渲染。 看起来我设置的提供者可以正确地根据userData呈现不同着色器的不同物体。
然而,最近我发现我创建的一个新对象,使用新的着色器类型(ConceptBeamShader),只能使用默认着色器进行渲染。
该对象的用户数据与其他对象相同;
newlazer.userData = MyShaderProvider.shadertypes.conceptbeam;
然而,在整个过程中,conceptbeamshader并没有被创建或使用。
事实上,createShader()似乎根本没有运行它...这意味着shaders数组中的现有着色器已经足够好了。
使用上面的testListShader()函数,我看到“DefaultShader”在“shader”列表中,可以渲染任何东西,因此它永远不会创建我想让该对象使用的新着色器 :-/
我认为其他着色器之前只是因为那些对象在DefaultShader添加到内部着色器列表之前就被创建了。
当然,一旦使用了DefaultShader,它就会存储在该提供程序列表中,并且将“吞噬”任何其他着色器。MyShaderProvider类中的getShader函数如下:
public Shader getShader (Renderable renderable) {
Shader suggestedShader = renderable.shader;
if (suggestedShader != null && suggestedShader.canRender(renderable)) return suggestedShader;
for (Shader shader : shaders) {
if (shader.canRender(renderable)) return shader;
}
final Shader shader = createShader(renderable);
shader.init();
shaders.add(shader);
return shader;
}
正如您所看到的,着色器会循环运行,并使用第一个返回“canRender”为true的着色器。那么...嗯...您应该如何说“使用此着色器渲染此ModelInstance”?我在网上阅读的所有教程似乎都没有涵盖这个问题 - 实际上,官方网站上的教程似乎建议我正在做的事情,因此显然有些东西我没弄清楚。谢谢。编辑被要求实例化的位置。不确定这有多大帮助,但是在此处;
public static MyShaderProvider myshaderprovider = new MyShaderProvider();
然后它会在游戏设置中被分配给模型批处理。
modelBatch = new ModelBatch(myshaderprovider);
如上所述,我的其他着色器可以工作并显示在我分配匹配的用户数据的对象上,因此我有99.9%的把握提供程序正在被调用,并且至少在某些情况下为正确的对象选择了正确的着色器。 我的猜测是,当“DefaultShader”添加到内部着色器列表时就会出现问题。