Skip to main content

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

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

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

こんな感じの影です👇

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

🧠 なぜこんな影を作るの?

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

でも、このやり方は:

項目

内容

🎮 ゲーム性能

とても軽い!(超高速)

🧠 理解しやすさ

仕組みが簡単!

📦 実装方法

ライトと同じように扱える


✅ どうやって作るの?

丸影(Blob Shadow)導入フロー


1. 🎯 目的整理

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

2. 📦 定数バッファの設計(CBShadow)

struct CBShadow {
    XMFLOAT4 casterPos;     // プレイヤーのXZ座標(Yは使わない:お空の方向を表すから)
    XMFLOAT4 shadowParams;  // (softness, alphaScale, unused, playerHeightY)
};
  • .wに高さを埋めることで1スロットで完結
  • b2スロットなど空いてる定数バッファにバインド

3. 🧠 HLSL シェーダー統合 (3Dの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);

4. 🧩 C++側:描画前にプレイヤーの情報を渡す

Stage::Draw や Stage::Update にて:

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);
  • playerHeightY = playerPos.y - Stage::GetTerrainHeight(playerPos.x, playerPos.z)
  • プレイヤーの高さを計算して .w に渡すのがポイント

5. 🛠 描画順序

  1. 通常の地面 + モデル描画(Model::Draw()
  2. その後 Stage.hlsl のピクセルシェーダー内で影を合成(クワッド描画不要)

6. 🧪 確認と調整

テスト項目

備考

影が正しい位置に出るか

XZが正しく渡っているか

高さでサイズ変化するか

.w

の補間式が効いているか

透明度が変化しているか

alpha

の計算式の係数調整

カメラを回しても違和感ないか

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


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

要素

内容

CBShadow

プレイヤー位置・高さ・影パラメータの格納

UpdateShadowCB()

定数バッファ更新(プレイヤー→影情報)

Stage.hlsl

丸影の合成コード(ピクセルシェーダー内)

GetTerrainHeight(x, z)

高さ推定関数(Stageが提供)