本文介绍了Libgdx 如何在 3D 中使用着色器的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I reached a point in my wip game, where I want to make it more eye-appealing. Currently I add some Ambientlight and a Directionla-light to an Environment and render my scene with it. But now I want to add a custom Shader to it. So I have been looking for some tutorials and for some reason in almost every tutorial they have used another "version" of using Shader in their game:

  • ModelBatch 一个 StringFileHandle vertex/fragment-shader
  • 用顶点和片段Shader创建一个ShaderProgram.
  • 用这个顶点和片段Shader创建一个新的DefaultShader.
  • 创建一个类,它实现了Shader并使用这个ShaderClass.
  • Giving the ModelBatch a String or FileHandle vertex/fragment-shader
  • Creating a ShaderProgram with vertex and fragment Shader.
  • Creating a new DefaultShader with this vertex and fragment Shader.
  • Creating a class, which implements Shader and use this ShaderClass.

我认为还有更多的可能性,因为还有 ShaderProvider 和其他类.
由于所有这些可能性,我有点困惑.所以我正在寻找可以为我指明正确方向的人.
为了让您更轻松,我会告诉您我拥有什么以及我需要什么:
我有:

I think there are more possibilitis, because there is also ShaderProviderand other classes as well.
I am a bit confused cause of all this posibilities. so I am looking for someone who can point me in the right direction.
To make it easier for you i tell you what i have and what I need:
I have:

  1. 一个 ModelBatch 应该绘制所有内容.
  2. 一个 Array 实例,我想对其应用 Shader.
  3. 一个 Texture 和它的 NormalMap,都存储为 Textures.
  4. 我的光的位置方向颜色,以Vector3给出,并给出它的强度作为 float.
  5. 环境光的颜色及其强度,以Vector3float表示.
  6. 作为 Vector3 给出的光衰减".
  1. A ModelBatch which should draw everything.
  2. An Array<ModelInstance> instances, to which i wanna apply the Shader.
  3. A Texture and its NormalMap, both stored as Textures.
  4. The position, the direction and the color of my light, given as Vector3 and its strength given as float.
  5. The color of the ambient light and its strength, given as Vector3 and float.
  6. The light "Falloff" given as Vector3.

我需要:

  1. Texture和它的Normal Map绑定到Shader.
  2. Shader 提供光的位置、方向、颜色和强度.
  3. Shader 提供环境光颜色和强度.
  4. Falloff 向量提供给 Shader.
  5. Array 中的所有实例"使用这个 Shader,它们都是用我的 ModelBatch 绘制的.
  1. To bind the Texture and its Normal Map to the Shader.
  2. Give the light pos, direction, color and strength to the Shader.
  3. Give the ambientlight color and strength to the Shader.
  4. Give the Falloff Vector to the Shader.
  5. Use this Shader for all "instances" in the Array, which are all drawn with my ModelBatch.

我希望能够做的另一件事是,为不同的模型使用不同的Texture.我的所有 ModleInstance 都带有纹理 Material.我有所有那些不同的 Texture 的法线贴图.现在我希望能够将正确的 TextureNormal Map 绑定到 Shader,具体取决于 TextureModelinstanceMaterial中.

Another thing I would like to be able to do is, using different Textures for different models.I have all my ModleInstances with a textured Material. And I have the normal map for all those different Textures. Now i want to be able to bind the right Texture and Normal Map to the Shader, depending on the Texture in the Material of the Modelinstance.

一个更高级"的东西,如果可能的话,我想在我的游戏中为不同的 ModelTypes 使用不同的 Shaders(Stonewall 使用一个 Shader 没有Specularity"和Reflection",而 Metalwalls 使用 Specularity 例如).

A more "advanced" thing, I would like to if it is possible, is using different Shaders for different ModelTypes in my game (Stonewall uses a Shader without "Specularity" and "Reflection", while Metalwalls use Specularity for example).

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

What would be the best way to do this things in Libgdx?How can i bind the different variables i have? (With ShaderProgram i can use setUniformi for example).

非常感谢.如果您需要更多信息或难以理解,请告诉我,我会尽力提出更好的问题.

Thanks a lot. If you need more information or if it is hard to understand let me know and i will try to create a better question.

我认为最好的方法是创建一个新的 Shader 类,它实现了 Shader.但我想听听有关设计、性能和可能的限制的所有其他可能性及其优缺点.

I think the best way in my case creating a new Shader class, which implements Shader. But i would like to hear about all the other possibilities, their pros and their cons, regarding design, performance and possible restrictions.

推荐答案

3d api 渲染管道的整体解释可以在 这里.本教程将指导您从头开始创建一个新的Shader.而本教程展示了如何使用自定义属性将数据传递给着色器.这个wiki页面还解释了如何使用Material Attributes 以及 DefaultShader 支持哪些 Attributes.

An overall explanation of rendering pipeline of the 3d api can be found here. This tutorial guides you in creating a new Shader from scratch. And this tutorial show how to use custom attributes to pass data to the shader. This wiki page also explains how to use Material Attributes and which Attributes the DefaultShader supports.

在 LibGDX 中,ShaderShaderProgram 是有区别的.一个 ShaderProgram 只是 GPU 实现(顶点和片段着色器程序),这基本上只是编译后的 GLSL 文件.例如,您可以在 ShaderProgram 上设置统一并使用它来渲染网格.但是 ShaderProgram 本身并不知道"它应该如何渲染模型.

In LibGDX there's a difference between a Shader and ShaderProgram. A ShaderProgram is only the GPU implementation (both the vertex and fragment shader program), which is basically only the compiled GLSL files. You can, for example, set uniforms on ShaderProgram and use it to render a mesh. But the ShaderProgram itself does not "know" how it should render a model.

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

The Shader interface is intended to bridge the gap between the ShaderProgram and the Renderable (the latter being the smallest renderable part of a model). Thus a Shader most commonly encapsulates a ShaderProgram and makes sure it sets the correct uniforms etc. (Note that strictly speaking a Shader doesn't have to encapsulate a ShaderProgram. E.g. before GLES1 support was removed, there also was a GLES1 shader which managed the fixed rendering pipe instead of encapsulating a ShaderProgram)

BaseShader 类是一个 abstracthelper类实现了Shader接口,封装了一个ShaderProgram,并添加了一些helper方法,方便设置uniform.如果你扩展这个类,你可以很容易地registerset统一,例如像这样:

The BaseShader class is an abstract helper class which implements the Shader interface, encapsulated a ShaderProgram and adds some helper methods to easily set uniforms. If you extend this class, you can easily register and set uniform, e.g. like this:

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"的统一设置为指定的值 15f(它将调用 setUniformX).如果 ShaderProgram(glsl 文件)没有实现名为u_falloff"的统一,它将简单地忽略调用.您还可以使用以下方法进行检查:if (has(u_falloff)) {/* 计算衰减并设置它 */}.BaseShader 还增加了为每个统一使用 ValidatorSetter 的可能性.

This will set the unifom called "u_falloff" to the specified value 15f (it will call setUniformX). If the ShaderProgram (glsl files) don't implement an uniform called "u_falloff", it will simply ignore the call. You could also check this using: if (has(u_falloff)) { /* calculate falloff and set it */ }. The BaseShader also adds the possibility to use a Validator and Setter for each uniform.

DefaultShader 扩展了 BaseShader 并为大部分 Material Attributes 添加了默认实现.查看源代码 如果你想看到每个制服的命名.实际上,如果您使用与 DefaultShader 相同的统一命名,则可以只指定 glsl 文件并让 DefaultShader 负责设置统一.当然,可以扩展 DefaultShader 以添加额外的uniform.

The DefaultShader extends the BaseShader and adds a default implementation for most of the Material Attributes. Have a look at the source if you want to see the naming of each uniform. In practice, if you use the same uniform naming as the DefaultShader does, it is possible to only specify the glsl files and let the DefaultShader take care of setting the uniforms. Of course it is possible to extend the DefaultShader to add additional uniforms.

当您调用 ModelBatch#render(...) 时,ModelBatch 将查询 ShaderProvider 以获得 Shader使用.这是因为顶点属性和材质属性的每种可能组合都可能需要不同的 Shader.例如,如果您有两个 ModelInstance(或更准确地说是两个 Renderable),一个带有 TextureAttribute.Diffuse,另一个没有纹理但是使用 ColorAttribute.Diffuse.然后最常见的是,ShaderProvider 需要创建两个不同的 Shader.请注意,它们可以属于同一类(例如 DefaultShader),但底层 GLSL 文件可能不同.

When you call ModelBatch#render(...), the ModelBatch will query the ShaderProvider for a Shader to use. This is because every possible combination of vertex attributes and material attributes might require a different Shader. For example if you have two ModelInstances (or to be more precise two Renderables), one with a TextureAttribute.Diffuse and one without texture but with a ColorAttribute.Diffuse. Then most commonly, the ShaderProvider needs to create two different Shaders. Note that they can be of the same class (e.g. DefaultShader), but that the underlying GLSL files might be different.

DefaultShader 使用预处理器宏(一个 ubershader)来处理这个问题.根据顶点属性和材质属性,它会#define多个标志,导致专门为顶点和材质属性的组合编译glsl程序.看看 glsl 文件,如果你想看看这是怎么做的.

The DefaultShader takes care of this using preprocessor macros (an ubershader). Depending on the vertex attributes and material attributes, it will #define multiple flags, causing the glsl program to be compiled specifically for that combination of vertex and material attributes. Have a look at the glsl files if you want to see how this is done.

因此,在实践中,您可能需要自己的 ShaderProvider 和自己的 Shader(通过从头开始实现,扩展 BaseShader 或扩展 DefaultShader).您可以为此扩展 DefaultShaderProvider 并在需要时回退到 DefaultShader,例如:

So, in practice you will likely need you own ShaderProvider and your own Shader (either by implementing it from scratch, extending BaseShader or extending DefaultShader). You can extends DefaultShaderProvider for this and fall back to the DefaultShader if needed, e.g.:

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 可能很容易.否则(或者如果您正在学习着色器)我建议从头开始创建着色器,如 此教程.

tl;dr If you want to use your own or a modified version of the ubershader, using the same uniforms as the default shader does, then simply provide the glsl files. If you want to use the same uniforms but add an additional uniform or two, then it might be easy to extend DefaultShader. Otherwise (or if you're learning shaders) I would advise to create the shader from scratch as described in This tutorial.

这篇关于Libgdx 如何在 3D 中使用着色器的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

08-21 09:18