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)