【Godot】随风摆动、吹风 Shader

Godot 4.0 stable
改动自:https://godotshaders.com/shader/topdown-windy-plants/

随风摆动 shader

// reference: https://godotshaders.com/shader/topdown-windy-plants/
shader_type canvas_item;
render_mode blend_mix;


// 控制最大吹动的强度
uniform vec2 wind = vec2(0, 0);
// 控制被吹动到左右的比值
uniform float offset : hint_range(-1., 1., 0.01) = 0.;


void vertex() {
    VERTEX.y += 1. - UV.y + wind.y;
    VERTEX.x += wind.x * offset * ((1. - UV.y) / VERTEX.y);
}

使用 GDScript 脚本进行控制

先写个角度比值缓存脚本:

#============================================================
#    Angle Ratio Cache
#============================================================
# - author: zhangxuetu
# - datetime: 2023-04-13 12:36:52
# - version: 4.0
#============================================================

class_name AngleRatioCache

const MAX_VALUE = 360

var _angle_to_ratio : Array = []

func _init():
    const KEY = "AngleRatioCache_angle_to_ratio"
    if Engine.has_meta(KEY):
        _angle_to_ratio = Engine.get_meta(KEY)
    else:
        var value = PI / 30
        _angle_to_ratio.resize(MAX_VALUE)
        for i in MAX_VALUE:
            _angle_to_ratio[i] = sin(deg_to_rad(i))
        Engine.set_meta(KEY, _angle_to_ratio)


## 获取这个角度在 360 度内的比 [-1, 1)
func get_value(angle: float) -> float:
    return _angle_to_ratio[int(angle) % MAX_VALUE]

根据上面的类型进行角度偏移控制,每 0 到 360 度为一个左右周期

下面代码获取到有这个材质的对象,执行 execute 方法进行左右摇摆,我的是一个 Area2D 下的一个节点,进入这个区域后会进行左右摇摆

#============================================================
#    Sprouts
#============================================================
# - author: zhangxuetu
# - datetime: 2023-04-12 23:08:38
# - version: 4.0
#============================================================
extends Area2D


## 摇摆幅度。值越大,摇摆越剧烈
@export var amplitude : float = 5.0:
    set(v):
        amplitude = v
        if _mat == null: await ready
        _mat.set_shader_parameter("wind", Vector2(amplitude, 0))
## 摇摆持续时间
@export var duration : float = 2.0
## 摇摆次数。左右摇摆一个来回算一次
@export var range_count : float = 3.0


## 获取有这个 shader 的节点的材质属性
@onready var _mat : ShaderMaterial = get_child(0).material

var _ratio_cache := AngleRatioCache.new()
var _tween : Tween


##  执行方法
##[br]
##[br][code]left_or_right[/code]  初始摇摆方向。先向左还是向右摇摆
func execute(left_or_right: float = 0.0):
    # 摇摆幅度
    _mat.set_shader_parameter("wind", Vector2(amplitude, 0))

    #  默认先偏向左边,增加旋转 180 度旋转到右边
    var offset : float = 0.0
    if left_or_right:
        offset = 180.0 * left_or_right

    if is_instance_valid(_tween):
        _tween.stop()
    _tween = create_tween()

    # 摇摆最大值
    var max_v : float = 360.0 * range_count
    _tween.chain() \
        .tween_method(func(v: float):
            var ratio = v / max_v
            _mat.set_shader_parameter( "offset", _ratio_cache.get_value(v  + offset) * ratio )
            ,
        max_v, 0, duration)

发表评论