游戏开发Godot

Godot Shader笔记:你的第一个3D Shader 第一

2019-06-29  本文已影响0人  吃烧烤的老王

原文地址:Docs » Shading » Your first shader » Your first Spatial shader

和光交互

首先,将线框模式关闭。再次点击左上角的视窗选项,当前它应该显示透视(Perspective) ,然后选择显示法线(Display Normal)。

image

我们发现模型的颜色变得扁平了。这是因为模型上的光是扁平的(注原文:This is because the lighting on it is flat)。让我们来添加些光吧。

首先,我们在场景里添加一个全向光(OmniLight)。

image

你可以看到光对地形产生了影响,但是看起来很奇怪。问题在于,光依然是把这个地形当作一个平面来影响的。因为光着色器(light shader)依然是使用模型中的法线来计算光照。

法线存储在模型里,但是我们在shader中“改变”了模型的形状,所以原来的法线不再是正确的了。要修正这个问题,我们可以重新计算shader中的法线或者使用一个和我们的噪声相符的法线纹理。在Godot中,这两种方式实现其来都很简单。

你可以在顶点函数中手动计算新的法线,然后把它赋值给NORMAL,设置完NORMAL以后,Godot可以为我们处理所有复杂的光照计算。我们将在本教程的下个部分介绍这个方法。现在我们使用从一个纹理中读取法线的方法。

我们通过传入第2张噪声纹理的方式,再次依靠NoiseTexture`来计算法线。

uniform sampler2D normalmap;

再次使用OpenSimplexNoise生成一个NoiseTexture 设置给这个uniform变量。这一次勾选上As Normalmap选项。

image

因为这是一个法线图(Normalmap)而不是逐顶点法线(per-vertex normal),我们将在片元函数中指定它。我们将在本教程的下一部分对片元函数做更详细的介绍。

void fragment() {
}

如果我们有一些对应顶点的法线,我们应当设置NORMAL属性,而如果我们有一个由纹理生成的法线图,我们应当设置NORMALMAP属性。这样,Godot会自动将纹理包裹到模型上。

最后,为了确保我们从噪声纹理和法线图纹理的相同位置读取,我们将使用varying变量从顶点函数中传递VERTEX.xz到片元函数中。

在顶点函数的上面定义一个名为vertex_positionvec2 的变量。在顶点函数中将VERTEX.xz赋值给vertex_position

varying vec2 vertex_position;
​
void vertex() {
 ...
 vertex_position = VERTEX.xz / 2.0;
}

当法线就位以后,光线可以与模型的高度动态地作用了。

image

我们可以左右拖拽一下光源,光照会自动更新。

image

以下是本教程的全部代码。你可以看到,它并不是很长,因为Godot已经为你解决了绝大多数繁琐的工作。

shader_type spatial;
​
uniform float height_scale = 0.5;
uniform sampler2D noise;
uniform sampler2D normalmap;
​
varying vec2 vertex_position;
​
void vertex() {
 vertex_position = VERTEX.xz / 2.0;
 float height = texture(noise, vertex_position).x * height_scale;
}
​
void fragment() {
 NORMALMAP = texture(normalmap, vertex_position).xyz;
}

以上就是本部分的全部内容了。希望你已经理解了Godot中顶点着色器的基础知识。在本教程的下一个部分,我们将写一个片元函数来配合这个顶点函数,并且我们还会介绍一些高级技术,甚至可以把这个地形变成海洋中运动的波浪。

上一篇下一篇

猜你喜欢

热点阅读