问题描述
我在我的 wip 游戏中达到了一个点,我想让它更吸引眼球.目前我添加了一些 Ambientlight
和一个 Directionla-light
到 Environment
并用它渲染我的场景.但现在我想给它添加一个自定义的 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
一个String
或FileHandle
vertex/fragment
-shader - 用顶点和片段
Shader
创建一个ShaderProgram
. - 用这个顶点和片段
Shader
创建一个新的DefaultShader
. - 创建一个类,它实现了
Shader
并使用这个ShaderClass
.
- Giving the
ModelBatch
aString
orFileHandle
vertex/fragment
-shader - Creating a
ShaderProgram
with vertex and fragmentShader
. - Creating a new
DefaultShader
with this vertex and fragmentShader
. - Creating a class, which implements
Shader
and use thisShaderClass
.
我认为还有更多的可能性,因为还有 ShaderProvider
和其他类.
由于所有这些可能性,我有点困惑.所以我正在寻找可以为我指明正确方向的人.
为了让您更轻松,我会告诉您我拥有什么以及我需要什么:
我有:
I think there are more possibilitis, because there is also ShaderProvider
and 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:
- 一个
ModelBatch
应该绘制所有内容. - 一个
Array
实例,我想对其应用Shader
. - 一个
Texture
和它的NormalMap
,都存储为Texture
s. - 我的光的
位置
、方向
和颜色
,以Vector3
给出,并给出它的强度作为float
. - 环境光的
颜色
及其强度,以Vector3
和float
表示. - 作为
Vector3
给出的光衰减".
- A
ModelBatch
which should draw everything. - An
Array<ModelInstance>
instances, to which i wanna apply theShader
. - A
Texture
and itsNormalMap
, both stored asTexture
s. - The
position
, thedirection
and thecolor
of my light, given asVector3
and its strength given asfloat
. - The
color
of the ambient light and its strength, given asVector3
andfloat
. - The light "Falloff" given as
Vector3
.
我需要:
- 将
Texture
和它的Normal Map
绑定到Shader
. - 为
Shader
提供光的位置、方向、颜色和强度. - 为
Shader
提供环境光颜色和强度. - 将
Falloff
向量提供给Shader
. - 对
Array
中的所有实例"使用这个Shader
,它们都是用我的ModelBatch
绘制的.
- To bind the
Texture
and itsNormal Map
to theShader
. - Give the light pos, direction, color and strength to the
Shader
. - Give the ambientlight color and strength to the
Shader
. - Give the
Falloff
Vector to theShader
. - Use this
Shader
for all "instances" in theArray
, which are all drawn with myModelBatch
.
我希望能够做的另一件事是,为不同的模型使用不同的Texture
.我的所有 ModleInstance
都带有纹理 Material
.我有所有那些不同的 Texture
的法线贴图.现在我希望能够将正确的 Texture
和 Normal Map
绑定到 Shader
,具体取决于 Texture
在Modelinstance
的Material
中.
Another thing I would like to be able to do is, using different Texture
s for different models.I have all my ModleInstance
s with a textured Material
. And I have the normal map for all those different Texture
s. 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
使用不同的 Shader
s(Stonewall 使用一个 Shader
没有Specularity"和Reflection",而 Metalwalls 使用 Specularity
例如).
A more "advanced" thing, I would like to if it is possible, is using different Shader
s 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 中,Shader
和 ShaderProgram
是有区别的.一个 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
接口旨在弥合 ShaderProgram
和 Renderable
(后者是模型中最小的可渲染部分)之间的差距).因此,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
类是一个 abstract
helper类实现了Shader
接口,封装了一个ShaderProgram
,并添加了一些helper方法,方便设置uniform.如果你扩展这个类,你可以很容易地register
和set
统一,例如像这样:
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
还增加了为每个统一使用 Validator
和 Setter
的可能性.
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 ModelInstance
s (or to be more precise two Renderable
s), one with a TextureAttribute.Diffuse
and one without texture but with a ColorAttribute.Diffuse
. Then most commonly, the ShaderProvider needs to create two different Shader
s. 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 中使用着色器的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!