Godot 游戏引擎学习 第九课

Godot 游戏引擎学习 第九课

December 27, 2020

再次学习 Shader

这里先吐槽一句,以前玩全没接触过,在没有概念的情况下看待未知的事物的感觉真不好。跟着 UP 主把代码写出来效果实现后却对这些参数函数的意义完全不懂。

所以我索性上 Godot 的官方文档里重新认真大概了解一下 Shader 是什么东西,以下写的东西都是在 Godot 里的情况

着色器是在图形处理器上运行的独特程序。它们用于指定如何获取网格数据 (顶点位置、颜色、法线等等) 然后把它们绘制到屏幕上。着色器并不像普通程序那样处理信息,因为它们经过了优化,可以在图形处理器上运行。其结果是,着色器在运行后不会保留数据;它们把最后一种颜色输出到屏幕上,然后继续。因此,无法访问着色器上次运行时的颜色输出。

首先是 Shader 的类型,一个 shader 着色器开头必须定义它的类型,官方给了三种,分别是:

  1. Spatial:用于 3d 渲染
  2. canvas_item:用于 2D 渲染
  3. particles:用于粒子系统

定义完 Shader 类型后要写一个主入口函数,也分为三种

  1. vertex ():运行在所有网格的定点上,并设置他们的位置及部分其他每个顶点的变量。
  2. fragment ():官方没说,应该是为每个像素运行的。
  3. light ():为每个像素和美术光照。

吐槽一下,Godot 的官方文档翻译好烂啊....,哎,不过有总比没有好,毕竟都是网友翻译的。(这里不是否定大家的工作,相反还要感谢。)

这样就大概完成函数主体了,接下来我们就可以在主题中对像素进行操作了。

我目前理解的一些东西就是。

  1. 可以通过 vec4 变量来储存图片的 rpga 通道,当然也有三位变量储存 rgb 颜色值。
  2. 可以通过 texture 函数获取外部贴图
  3. UV 代表一个像素再网格中的坐标,最小是 0,最大是 1,分为 r,x,g,y,这里 r 和 g 我不知道是什么意思,但是 x 应该是水平坐标,y 为垂直坐标。
  4. COLOR 代表当前像素的原本颜色,你可以给与一个 vec4 变量来改变颜色。

目前的理解大概就是这样,当然只是最基础的部分。Shader 肯定没这么简单,但是我现在也不需要了解的非常深刻,但是要有一些基础原理的理解有利于以后的学习。

Godot 里利用 shader 完成花里胡哨转场

首先为 Globals 的 ColorRect 添加一个 ShaderMaterial,并添加如下代码如下:

shader_type canvas_item; 

// 定义默认值
// 渐变边界
uniform float cutoff: hint_range(0.0, 1.0) = 0.5;
// 模糊级别
uniform float feather:hint_range(0.0, 1.0) = 0.1;
// 2D纹理
uniform sampler2D mask;

// 片段函数,可以对图片中的每个像素进行操作
void fragment()
{
	// 顶一个思维变量,代表像素的四个通道的颜色,分别是Red Green Blue Alpha
	vec4 col = vec4(0.0, 0.0, 0.0, 1.0);
	// 读取外部纹理
	vec4 v = texture(mask, UV);
	
//	//如果uv的横向还没到我们的效果区域则全部设置为透明
//	if(UV.x < cutoff - feather){
//		col.a = 0.0
//	//如果横向坐标到达效果区的最右边
//	}else if(UV.x < cutoff){
//		// 则讲透明度设置成边界减羽化值
//		col.a = (UV.x - (cutoff - feather))
//	}
	
	// 这个函数不太懂,看了下官方手册是一个插值函数,原理是一个名为:埃尔米特插值法(Hermite interpolation)的东西,我完全看不懂。
	// up的解释是如果最后一个参数小于第一个参数则返回0,大于第二个参数则返回1,介于第一个参数和第二个参数之间的话返回一个过渡值
	// 第三个为啥用纹理像素中的r通道,我自己测试了一下,其他通道也是可以,我觉得只是为了界定像素在哪个位置而已。
	col.a = smoothstep(cutoff - feather, cutoff, v.g * (1.0 -feather));
	
	// 应用颜色
	COLOR = col;
}

然后修改 fadein 动画,动态改变代码中设置的 cutofffeather 值。

效果如下:

第九课_shader_tranistion

怪物进入镜头视野后才会行动

另外这里处理了一个问题,就是原先怪物的逻辑是一加载到场景中就会开始执行设置好的动作,在 Godot 里这个功能甚至不用写代码...。这里我们给 Enemy 加了一个 VisibilityEnabler2D 节点,文档对这个节点的解释为:Enables certain nodes only when approximately visible.,作用就是怪物进入镜头视野后才会开始执行预先设定的指令,且不会影响其加载。

image-20201227143553379

改变关卡

到最后一集了,UP 这一集基本上就是利用之前所学重新搭建了场景,增加了一个改变关卡的功能。

image-20201227142857988

因为 Godot 的特性,所以这里我们搭建新关卡的时候很简单,只需要把我们之前创建好的怪物,道具什么的实例化到新场景,摆到想要摆放的位置即可,搭建这个新场景前后不过五分钟把...,面向对象万岁。

做了一个 Exit 场景,并连接_on_Exit_body_entered 信号,这里指定类型用了和 hint_range 一样的写法,指定类型为 File,并且指定了可选择的后缀 (想起了以前 C# 的文件组件。),这样我们就能在编辑器里设置下一个场景的路径,并调用我们写好的 Globals.go_to_world(path) 函数跳转场景

# Exit.gd
extends Area2D

# 外部参数,指定使用文件系统,并设定可选区的文件类型
export(String, FILE, "*.tscn") var path

func _on_Exit_body_entered(_player):
    # 调用转场函数,传入设置好的场景路径
    Globals.go_to_world(path)
# ...
    
    
# Globals.gd
# ...
func go_to_world(path):
    # 死亡的时候让动画倒叙播放
    animation_player.play_backwards("fadein")
    # 等待动画播放完毕
    yield(animation_player, "animation_finished")
    # 跳转场景
    get_tree().change_scene(path)
    # 动画正序播放
    animation_player.play("fadein")
# ...

效果如下

好了,UP 主上传的视频已经全部看完了,准备开始自己设计一些关卡,并制作机关功能。

第九课_sence_change

加入评论