IT博客汇
  • 首页
  • 精华
  • 技术
  • 设计
  • 资讯
  • 扯淡
  • 权利声明
  • 登录 注册

    Godot游戏引擎学习 第九课

    1900发表于 2020-12-27 14:44:42
    love 0

    再次学习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动画,动态改变代码中设置的cutoff和feather值。

    效果如下:

    第九课_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



沪ICP备19023445号-2号
友情链接