Libgdx如何在3D中使用着色器

时间:2014-03-21 08:11:25

标签: opengl 3d libgdx shader

我在我的wip游戏中达到了一个点,我想让它更吸引眼球。目前,我向Ambientlight添加了一些Directionla-lightEnvironment,并使用它渲染我的场景。但现在我想为它添加一个自定义Shader。所以我一直在寻找一些教程,并且出于某种原因,在几乎每个教程中他们都使用了另一个"版本"在他们的游戏中使用Shader

  • ModelBatch一个StringFileHandle vertex/fragment - 着色器
  • 使用顶点和片段ShaderProgram创建Shader
  • 使用此顶点和片段DefaultShader创建新的Shader
  • 创建一个实现Shader并使用此ShaderClass
  • 的类

我认为还有更多的可能性,因为还有ShaderProvider和其他课程 所有这些可能性让我有点困惑。所以我正在寻找能指出正确方向的人 为了方便你,我告诉你我拥有什么和我需要什么:
我有:

  1. 应该绘制所有内容的ModelBatch
  2. Array<ModelInstance>个实例,我想应用Shader
  3. Texture及其NormalMap,均存储为Texture
  4. 我的灯光的positiondirectioncolorVector3,强度为float
  5. 环境光的color及其强度,以Vector3float给出。
  6. 光&#34;衰减&#34;以Vector3为准。
  7. 我需要:

    1. Texture及其Normal Map绑定到Shader
    2. 将光线的位置,方向,颜色和强度赋予Shader
    3. 将环境光的颜色和强度赋予Shader
    4. Falloff向量提供给Shader
    5. 将此Shader用于所有&#34;实例&#34;在Array中,这些都是使用我的ModelBatch
    6. 绘制的

      我希望能够做的另一件事是,对不同的模型使用不同的Texture。 我的所有ModleInstance都带有纹理Material。我有所有不同Texture s的法线贴图。现在我希望能够将TextureNormal Map绑定到Shader,具体取决于Texture Material中的Modelinstance }。

      更多&#34;高级&#34;事情,我想如果有可能的话,在我的游戏中使用不同的Shader用于不同的ModelTypes(Stonewall使用Shader而没有&#34; Specularity&#34;和& #34;反思&#34;,而Metalwalls例如使用Specularity

      在Libgdx中做这件事最好的方法是什么? 我如何绑定我拥有的不同变量? (使用ShaderProgram我可以使用setUniformi)。

      非常感谢。如果您需要更多信息或者难以理解,请告诉我,我会尝试创建一个更好的问题。

      编辑:我认为在我的情况下创建新Shader类的最佳方法是实现Shader。但我想了解所有其他可能性,它们的优点和缺点,包括设计,性能和可能的限制。

1 个答案:

答案 0 :(得分:14)

可以找到渲染3d api管道的整体说明hereThis tutorial指导您从头开始创建新的Shaderthis tutorial显示了如何使用自定义属性将数据传递到着色器。 This wiki page还解释了如何使用Material Attributes以及Attributes支持的DefaultShader

在LibGDX中,ShaderShaderProgram之间存在差异。 ShaderProgram只是GPU实现(顶点和片段着色器程序),它基本上只是已编译的GLSL文件。例如,您可以在ShaderProgram上设置制服并使用它来渲染网格。但是ShaderProgram本身并不知道&#34;如何渲染模型。

Shader接口旨在弥合ShaderProgramRenderable之间的差距(后者是模型中最小的可渲染部分)。因此,Shader最常封装ShaderProgram,并确保设置正确的制服等。(请注意,严格来说Shader不必封装ShaderProgram例如,在删除GLES1支持之前,还有一个GLES1着色器管理固定渲染管道而不是封装ShaderProgram

BaseShader类是一个abstract辅助类,它实现了Shader接口,封装了ShaderProgram并添加了一些辅助方法来轻松设置制服。如果您扩展此课程,则可以轻松registerset统一,例如像这样:

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还增加了为每件制服使用ValidatorSetter的可能性。

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中的描述从头开始创建着色器。