【Godot】2D画像をもとに擬似的な影を実装する方法

# 概要
この記事では、2D画像をもとに擬似的な影を実装する方法について紹介します。
![shot.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/43772/cfde5ce3-8a5d-a7ab-ccac-d40a62d98948.gif)

# 影の実装
## 画像の登録
今回の素材は「立ち絵素材 わたおきば」様よりお借りしています。

* [立ち絵素材 わたおきば](https://wataokiba.net)

背景が明るいほうがわかりやすいので、`ColorRect` を背面に配置して明るい灰色にします。
![Godot_Engine_-_Test2DShadow____.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/43772/fc06c033-827b-7e66-286a-671c8f648835.png)
登録した画像は `Chara` にノード名を変更しておきます。
![Godot_Engine_-_Test2DShadow____.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/43772/a873736e-8f03-8c23-81b5-a60f658fc94c.png)

## 影用のSpriteの作成
影用のSpriteとして、`Chara` を複製し、名前を `Shadow` にリネームします。
![Godot_Engine_-_Test2DShadow____.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/43772/0175c229-def9-066b-632b-309c727bc260.png)
図ではわかりやすいように位置をずらしていますが、`Shadow`ノード の `Transform > Position` は 0 (初期値) にしておきます。
![Godot_Engine_-_Test2DShadow____.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/43772/aa9367e0-ef67-c394-464c-f0192dd90598.png)

そして、`Chara`ノードを選択して、インスペクタから `Z Index > Z Index` を 「1」にしておきます。
![Godot_Engine_-_Test2DShadow____.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/43772/b98f8c23-8ca2-3ab4-800a-9f1e240b69d4.png)
これはキャラクターを影よりも前面に表示したいためとなります。
さらに `Shadow` ノードを選択して、インスペクタから `Z Index > Z Index` を 「-1」にしておきます。
![Godot_Engine_-_Test2DShadow____.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/43772/f8f18fd9-361c-e94b-3ec4-17b496da7264.png)

少しややこしいですが、Z Indexの並びは以下のようになります。

```
Mainシーン
 +-- ColorRect (0) => 一番奥
 +-- Chara (1) => 一番手前
      +-- Shadow (1-1=0) => 真ん中
```

## シェーダーの追加
`Shadow`ノードを選択した状態で、`CanvasItem > Material > Material > [空]` をクリックして「新規 Shader Material」を追加します。
![Godot_Engine_-_Test2DShadow____.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/43772/b96f7d4f-845b-c455-b511-aa5581891df0.png)

作成されたMaterialをクリックして、`Shader > [空]` をクリックし、「新規 Shader」を選びます。
![Godot_Engine_-_Test2DShadow____.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/43772/66575ed4-40ca-743e-68c7-45f62e7a108f.png)

するとシェーダーエディタが表示されるので以下のコードを記述します。

```glsl
shader_type canvas_item;

uniform float shearAngleX = -45.0;
uniform float sunAngle = 45.0;

//const float SHEAR_ORIGIN_Y = 1.0; // 左上が原点
const float SHEAR_ORIGIN_Y = 0.5; // 中心が原点

// 頂点シェーダー
void vertex()
{
	vec2 v = VERTEX;

	float originOffsetY = SHEAR_ORIGIN_Y / TEXTURE_PIXEL_SIZE.y;
	v.y -= originOffsetY; // 原点をずらす
	// 影の傾きを計算
	v.y *= cos(radians(shearAngleX)) / tan(radians(sunAngle));
	v.x += tan(radians(shearAngleX))  * v.y;
	
	v.y += originOffsetY; // 原点をもとに戻す

	VERTEX = v;
}

// フラグメントシェーダー
void fragment()
{
	// 薄い黒色にする
	vec4 color = texture(TEXTURE, UV);
	color.rgb = vec3(0, 0, 0);
	color.a *= 0.5;
	COLOR = color;
}
```

シェーダーコードを記述すると、以下のように影が描画されます。
![Godot_Engine_-_Test2DShadow_-_Main_tscn.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/43772/4d165305-cb61-fe17-293f-7a256e015b35.png)

## スクリプトの追加
`Shadow`ノードにスクリプトをアタッチして以下のように記述します。

```gd:Shadow.gd
tool
extends Sprite

export(float, -90, 90) var shear_angle_x = -45 
export(float, 45, 90) var sun_angle = 45

func _process(delta: float) -> void:
	material.set_shader_param("shearAngleX", shear_angle_x)
	material.set_shader_param("sunAngle", sun_angle)
```

tool宣言をしているので、シーンをいったん保存して開き直します。

するとエディタから影の調整ができるようになります。
![shot.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/43772/cfde5ce3-8a5d-a7ab-ccac-d40a62d98948.gif)

# 参考

* [Does anyone know how to make this shadow effect in 2D? - reddit](https://www.reddit.com/r/godot/comments/lm40o0/does_anyone_know_how_to_make_this_shadow_effect/)