# キャラクターの真下にShaderを使って丸い影を描く（投影丸影）

## 🎯 この影の作り方のイメージ

> プレイヤーの下に「黒い丸いライト」を当てて、地面を****ちょっとだけ暗く見せる****という工夫です。  
> ライトなので、授業でやった点光源がわかっていれば全く同じように実装できます。  
> しかも、現在のシェーダーにコンスタントバッファと、影付け部分を足すだけでできます。

こんな感じの影です👇

```
👦 ← プレイヤー（ジャンプ中でもOK）
   ↓
黒い光を下に照らす
   ↓
￣￣￣￣￣￣￣￣￣￣￣￣
　 ● ← 黒い影（地面に丸く表示される）
￣￣￣￣￣￣￣￣￣￣￣￣
```

---

## 🧠 なぜこんな影を作るの？

本物の影は、光を遮ってリアルタイムに計算するので\*\*とても重たい（処理が大変）\*\*です。

でも、このやり方は：

<table id="bkmrk-%E9%A0%85%E7%9B%AE%E5%86%85%E5%AE%B9%F0%9F%8E%AE-%E3%82%B2%E3%83%BC%E3%83%A0%E6%80%A7%E8%83%BD%E3%81%A8%E3%81%A6%E3%82%82%E8%BB%BD%E3%81%84%EF%BC%81%EF%BC%88%E8%B6%85%E9%AB%98"><colgroup><col></col><col></col></colgroup><tbody><tr><th>項目

</th><th>内容

</th></tr><tr><td>🎮 ゲーム性能

</td><td>とても軽い！（超高速）

</td></tr><tr><td>🧠 理解しやすさ

</td><td>仕組みが簡単！

</td></tr><tr><td>📦 実装方法

</td><td>ライトと同じように扱える

</td></tr></tbody></table>

---

## ✅ どうやって作るの？

# 丸影（Blob Shadow）導入フロー

---

## <span style="white-space: pre-wrap;">1. 🎯 </span>****目的整理****

- 丸影を「地面に貼り付けるような」影として合成する
- 地面用の描画パスに統合せず、「影合成処理」は別パスとして独立させたい
- プレイヤーの現在位置（XZ）と高さを使って「影の位置・サイズ・濃さ」を計算

---

## <span style="white-space: pre-wrap;">2. 📦 </span>****定数バッファの設計（CBShadow）****

```cpp
struct CBShadow {
    XMFLOAT4 casterPos;     // プレイヤーのXZ座標（Yは使わない：お空の方向を表すから）
    XMFLOAT4 shadowParams;  // (softness, alphaScale, unused, playerHeightY)
};
```

- `<span class="editor-theme-code">.w</span>`に高さを埋めることで1スロットで完結
- `<span class="editor-theme-code">b2</span>`スロットなど空いてる定数バッファにバインド

---

## <span style="white-space: pre-wrap;">3. 🧠 </span>****HLSL シェーダー統合 (3Dのhlslの後ろに追加するなど？)****

### ⚙ 丸影のアルファ合成ロジックをピクセルシェーダー末尾に追加

```hlsl
float2 casterXZ = casterPos.xz;
float2 pixelXZ = inData.wpos.xz;

float2 diff = pixelXZ - casterXZ;
float distSq = dot(diff, diff);

float softness = shadowParams.x;
float alphaScale = shadowParams.y;
float heightY = shadowParams.w;

float heightRatio = saturate(heightY / 2.0f); // 最大ジャンプ2.0f想定
float radius = lerp(0.4f, 1.0f, heightRatio);
float alpha  = lerp(0.6f, 0.1f, heightRatio);

float shadowAlpha = saturate((radius * radius - distSq) * softness) * alpha;

// 丸影を黒で合成（必要に応じて色も乗せられる）
float4 shadowColor = float4(0, 0, 0, shadowAlpha);
return lerp(resultColor, shadowColor, shadowAlpha);
```

---

## <span style="white-space: pre-wrap;">4. 🧩 </span>****C++側：描画前にプレイヤーの情報を渡す****

### Stage::Draw や Stage::Update にて：

```cpp
CBShadow shadowCB;
shadowCB.casterPos = XMFLOAT4(playerPos.x, 0.0f, playerPos.z, 1.0f);
shadowCB.shadowParams = XMFLOAT4(softness, alphaScale, 0.0f, playerHeightY);

// 書き込み → バッファ更新
context->UpdateSubresource(pCBShadow, 0, nullptr, &shadowCB, 0, 0);
context->PSSetConstantBuffers(2, 1, &pCBShadow);
```

- `<span class="editor-theme-code">playerHeightY = playerPos.y - Stage::GetTerrainHeight(playerPos.x, playerPos.z)</span>`
- <span style="white-space: pre-wrap;">プレイヤーの高さを計算して </span>`<span class="editor-theme-code">.w</span>`<span style="white-space: pre-wrap;"> に渡すのがポイント</span>

---

## <span style="white-space: pre-wrap;">5. 🛠 </span>****描画順序****

1. 通常の地面 + モデル描画（`<span class="editor-theme-code">Model::Draw()</span>`）
2. <span style="white-space: pre-wrap;">その後 </span>`<span class="editor-theme-code">Stage.hlsl</span>`<span style="white-space: pre-wrap;"> のピクセルシェーダー内で影を合成（クワッド描画不要）</span>

---

## <span style="white-space: pre-wrap;">6. 🧪 </span>****確認と調整****

<table id="bkmrk-%E3%83%86%E3%82%B9%E3%83%88%E9%A0%85%E7%9B%AE%E5%82%99%E8%80%83%E5%BD%B1%E3%81%8C%E6%AD%A3%E3%81%97%E3%81%84%E4%BD%8D%E7%BD%AE%E3%81%AB%E5%87%BA%E3%82%8B%E3%81%8Bxz"><colgroup><col></col><col></col></colgroup><tbody><tr><th>テスト項目

</th><th>備考

</th></tr><tr><td>影が正しい位置に出るか

</td><td>XZが正しく渡っているか

</td></tr><tr><td>高さでサイズ変化するか

</td><td>`<span class="editor-theme-code">.w</span>`

の補間式が効いているか

</td></tr><tr><td>透明度が変化しているか

</td><td>`<span class="editor-theme-code">alpha</span>`

の計算式の係数調整

</td></tr><tr><td>カメラを回しても違和感ないか

</td><td>視差が出ないか、影が地面に貼りついて見えるか

</td></tr></tbody></table>

---

## ✅ 最終的な関数と構造の一覧

<table id="bkmrk-%E8%A6%81%E7%B4%A0%E5%86%85%E5%AE%B9%E8%BF%BD%E5%8A%A0%E3%81%99%E3%81%B9%E3%81%8D%E5%A0%B4%E6%89%80-%2F-%E3%82%AF%E3%83%A9%E3%82%B9cbs"><colgroup><col></col><col></col><col></col></colgroup><tbody><tr><th>要素

</th><th>内容

</th><th>追加すべき場所 / クラス

</th></tr><tr><td>`<span class="editor-theme-code">CBShadow</span>`

</td><td>丸影用の定数バッファ構造体

</td><td>`<span class="editor-theme-code">Engine/ShaderStruct.h</span>`

<span style="white-space: pre-wrap;"> など定数バッファ定義系ヘッダ</span>

</td></tr><tr><td>`<span class="editor-theme-code">UpdateShadowCB()</span>`

</td><td><span style="white-space: pre-wrap;">プレイヤー情報から </span>

`<span class="editor-theme-code">CBShadow</span>`

<span style="white-space: pre-wrap;"> を更新・送信する関数</span>

</td><td>`<span class="editor-theme-code">Stage</span>`

<span style="white-space: pre-wrap;"> クラス、または </span>

`<span class="editor-theme-code">ShadowManager</span>`

<span style="white-space: pre-wrap;"> を作ってもOK</span>

</td></tr><tr><td>`<span class="editor-theme-code">Stage.hlsl</span>`

</td><td>丸影の合成コードを含む HLSL

</td><td>`<span class="editor-theme-code">Assets/Shader/Stage.hlsl</span>`

（または新規に丸影対応シェーダ）

</td></tr><tr><td>`<span class="editor-theme-code">GetTerrainHeight(x, z)</span>`

</td><td>指定座標の地面高さを返す

</td><td>`<span class="editor-theme-code">Stage</span>`

<span style="white-space: pre-wrap;"> クラスに追加（地形データを持っているなら）</span>

</td></tr></tbody></table>

---

# ✅ より具体的に解説

### <span style="white-space: pre-wrap;">📦 1. </span>`<span class="editor-theme-code">CBShadow</span>`

```cpp
// ShaderStruct.h または ShadowStruct.h など
struct CBShadow {
    DirectX::XMFLOAT4 casterPos;     // プレイヤーのXZ座標
    DirectX::XMFLOAT4 shadowParams;  // (softness, alphaScale, -, playerHeightY)
};
```

- <span style="white-space: pre-wrap;">すでに </span>`<span class="editor-theme-code">CBGlobal</span>`<span style="white-space: pre-wrap;"> や </span>`<span class="editor-theme-code">CBLight</span>`<span style="white-space: pre-wrap;"> がある場所に追加すると整理しやすい</span>

---

### <span style="white-space: pre-wrap;">🔁 2. </span>`<span class="editor-theme-code">UpdateShadowCB()</span>`<span style="white-space: pre-wrap;"> のような関数</span>

****追加先:****<span style="white-space: pre-wrap;"> </span>`<span class="editor-theme-code">Stage.cpp</span>`<span style="white-space: pre-wrap;"> 内のメンバ関数 or </span>`<span class="editor-theme-code">ShadowManager</span>`<span style="white-space: pre-wrap;"> クラスとして独立化もOK</span>

```cpp
void Stage::UpdateShadowCB(const Player& player)
{
    CBShadow cb;
    auto pos = player.GetTransform().position_;
    float terrainY = GetTerrainHeight(pos.x, pos.z);

    cb.casterPos = XMFLOAT4(pos.x, 0.0f, pos.z, 1.0f);
    cb.shadowParams = XMFLOAT4(softness, alphaScale, 0.0f, pos.y - terrainY);

    D3D11_MAPPED_SUBRESOURCE mapped;
    context->Map(pCBShadow_, 0, D3D11_MAP_WRITE_DISCARD, 0, &mapped);
    memcpy(mapped.pData, &cb, sizeof(cb));
    context->Unmap(pCBShadow_, 0);

    context->PSSetConstantBuffers(2, 1, &pCBShadow_);
}
```

---

### <span style="white-space: pre-wrap;">🎨 3. </span>`<span class="editor-theme-code">Stage.hlsl</span>`<span style="white-space: pre-wrap;"> 内のピクセルシェーダー後半に合成コード</span>

****追加先:****<span style="white-space: pre-wrap;"> </span>`<span class="editor-theme-code">Assets/Shader/Stage.hlsl</span>`

```hlsl
cbuffer ShadowParam : register(b2)
{
    float4 casterPos;
    float4 shadowParams; // (softness, alphaScale, -, playerHeightY)
}

...

// ピクセルシェーダー末尾
float2 delta = inData.wpos.xz - casterPos.xz;
float distSq = dot(delta, delta);

float softness = shadowParams.x;
float alphaScale = shadowParams.y;
float playerHeightY = shadowParams.w;
float heightRatio = saturate(playerHeightY / 2.0f);
float radius = lerp(0.4f, 1.0f, heightRatio);
float alpha  = lerp(0.6f, 0.1f, heightRatio);

float shadowAlpha = saturate((radius * radius - distSq) * softness) * alpha;
float4 shadowColor = float4(0, 0, 0, shadowAlpha);

return lerp(resultColor, shadowColor, shadowAlpha);
```

---

### <span style="white-space: pre-wrap;">🧭 4. </span>`<span class="editor-theme-code">Stage::GetTerrainHeight(x, z)</span>`<span style="white-space: pre-wrap;"> 関数</span>

****追加先:****<span style="white-space: pre-wrap;"> </span>`<span class="editor-theme-code">Stage.h</span>`<span style="white-space: pre-wrap;"> / </span>`<span class="editor-theme-code">Stage.cpp</span>`

```cpp
float Stage::GetTerrainHeight(float x, float z) const
{
    // 例えば地形がグリッドなら、高さマップや地面モデルから高さを補間して返す
    return heightMap.SampleAt(x, z);
}
```

---

# 🧩 補足：必要な DirectX11 の初期化項目

<table id="bkmrk-%E5%90%8D%E5%89%8D%E6%A6%82%E8%A6%81id3d11buffer%2A-pc"><colgroup><col></col><col></col></colgroup><tbody><tr><th>名前

</th><th>概要

</th></tr><tr><td>`<span class="editor-theme-code">ID3D11Buffer* pCBShadow_</span>`

</td><td>丸影用定数バッファ

</td></tr><tr><td>`<span class="editor-theme-code">CreateBuffer()</span>`

<span style="white-space: pre-wrap;"> で生成</span>

</td><td><span style="white-space: pre-wrap;">初期化時に </span>

`<span class="editor-theme-code">sizeof(CBShadow)</span>`

<span style="white-space: pre-wrap;"> を渡す</span>

</td></tr></tbody></table>