単純な残像効果ですが
昔から好きで多用しています。
要するに
前のフレームのカメラ行列をシェーダに渡しているのですが、今回はGodotでの実装例を紹介します。
まずはGDScriptで
前回のカメラ座標を格納しておきます。この処理は最後に実行するようにします。
self._prev_camera_transform = main_camera.get_camera_transform()
前のフレームで格納しておいたこの transform を Vector4 の配列に格納します。
func _process(delta:float) -> void:
var prev_matrix:Array = [ Vector4(1, 0, 0, 0), Vector4(0, 1, 0, 0), Vector4(0, 0, 1, 0), Vector4(0, 0, 0, 1), ]
var camera_transform_inverse := self._prev_camera_transform.inverse()
var rot = camera_transform_inverse.basis
var origin = camera_transform_inverse.origin;
prev_matrix[0] = Vector4(rot.x.x, rot.x.y, rot.x.z, 0.0)
prev_matrix[1] = Vector4(rot.y.x, rot.y.y, rot.y.z, 0.0)
prev_matrix[2] = Vector4(rot.z.x, rot.z.y, rot.z.z, 0.0)
prev_matrix[3] = Vector4(origin.x, origin.y, origin.z, 1.0)
_material.set_shader_parameter("prev_matrix", prev_matrix)
次にシェーダ
shader_type spatial;
render_mode cull_disabled, blend_add, depth_draw_never, unshaded, specular_disabled, shadows_disabled, ambient_light_disabled, skip_vertex_transform;
uniform vec4 prev_matrix[4];
void vertex()
{
mat4 prev_view;
prev_view[0] = prev_matrix[0];
prev_view[1] = prev_matrix[1];
prev_view[2] = prev_matrix[2];
prev_view[3] = prev_matrix[3];
float elapsed_time = COLOR.a;
float velocity = 8.0;
vec4 p = MODEL_MATRIX * vec4(VERTEX + NORMAL*elapsed_time*velocity, 1);
VERTEX = VERTEX_ID%2 != 0 ? (VIEW_MATRIX * p).xyz : (prev_view * p).xyz;
COLOR.a = VERTEX_ID%2 != 0 ? 1.0 : 0.0;
}
void fragment()
{
ALBEDO = COLOR.rgb;
ALPHA = COLOR.a;
}
VERTEX =
の行で、VERTEX_ID がどちらかで通常の行列か、ひとつ前の行列かを切り替えます。 mesh topology を line に設定したモデルを渡しているので、扱う頂点は2つだけなので。
そんな小ネタでした
Advent Calendar がちょっと「弾幕薄いぞ」のように見えたので、援護射撃をば。