Godot屏幕抖动效果原理与实现

要用Godot实现屏幕/相机抖动效果,调查了网上的一些实现方案,效果都很不满意,于是自己实现了一个。

原理

从渲染过程看,实际发生抖动的是场景相机。
抖动过程对应物理学上的振动(物理量在某个定值附近反复变化),也称为震荡。
一个物体振动时,其振幅逐渐减小最后停止振动,这种振荡运动是阻尼的。
相机抖动符合阻尼振动的定义。

要实现抖动效果,理论上既可以是相机在平衡位置(设置坐标)附近的振动,也可以是相机朝向的方向角的振动。
从实现角度看,由于Godot的Camera类有h_offset和v_offset属性,用它们来实现是最方便的。

根据物理学中阻尼运动的动力学方程(振动方程),可以解得质点的运动方程:
阻尼振动的运动方程
另外,过阻尼振动和临界阻尼振动的情况我们不需要,不作讨论。
虽然运动方程是一维的,但是很容易扩展到多维。
只要多维的系统参数相同,符合物理规律,最终表现效果就会比较“真实”。
给定初始化条件(t=0, x=0)和(t=duration, x=0)可以进一步简化得到相机的运动方程,即相机坐标随时间变化的函数。

实现

在场景相机$Camera上添加GDScript脚本:

extends Cameraconst amp = 1.0
const cycle = 2
const duration = 0.3
const beta = 3 / duration
const omega = 2 * PI / duration * cyclevar a: Vector2func _ready():passfunc rnd_amp(amp_max: float):return rand_range(amp_max / 2, amp_max) * [1, -1][randi() % 2]func _on_vibra_finished():h_offset = 0v_offset = 0func damped_vibra(t: float):h_offset = a.x * exp(-beta * t) * sin(omega * t)v_offset = a.y * exp(-beta * t) * sin(omega * t)func _on_Main_sig_bad():a = Vector2(rnd_amp(amp), rnd_amp(amp))var tween = create_tween()tween.connect("finished", self, "_on_vibra_finished")tween.tween_method(self, "damped_vibra", 0.0, duration, duration)

说明

  • 将外部信号sig_bad连接到$Camera脚本中的方法_on_Main_sig_bad()
  • 方法_on_Main_sig_bad()初始化振动过程参数,并触发tween的补间(多次插值)过程
  • 系统会通过Tween机制每间隔一段时间触发函数damped_vibra(),函数采用阻尼振动的运动方程来更新相机参数h_offset和v_offset,实现抖动效果
  • 当补间结束时,finished信号触发函数_on_vibra_finished(),重置相机参数h_offset和v_offset

参考

知乎:阻尼运动、参变共振
百度百科:阻尼振动
【Godot】相机抖动
Godot Engine:屏幕振动效果的实现
Godot shader 实现抖动效果


本文来自互联网用户投稿,文章观点仅代表作者本人,不代表本站立场,不承担相关法律责任。如若转载,请注明出处。 如若内容造成侵权/违法违规/事实不符,请点击【内容举报】进行投诉反馈!

相关文章

立即
投稿

微信公众账号

微信扫一扫加关注

返回
顶部