キャラクターの真下にShaderを使って丸い影を描く(投影丸影)
🎯 この影の作り方のイメージ
プレイヤーの下に「黒い丸いライト」を当てて、地面をちょっとだけ暗く見せるという工夫です。
ライトなので、授業でやった点光源がわかっていれば全く同じように実装できます。
しかも、現在のシェーダーにコンスタントバッファと、影付け部分を足すだけでできます。
こんな感じの影です👇
👦 ← プレイヤー(ジャンプ中でもOK)
↓
黒い光を下に照らす
↓
 ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄
● ← 黒い影(地面に丸く表示される)
 ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄🧠 なぜこんな影を作るの?
本物の影は、光を遮ってリアルタイムに計算するので**とても重たい(処理が大変)**です。
でも、このやり方は:
項目 | 内容 |
|---|---|
🎮 ゲーム性能 | とても軽い!(超高速) |
🧠 理解しやすさ | 仕組みが簡単! |
📦 実装方法 | ライトと同じように扱える |
✅ どうやって作るの?
① まず、プレイヤーの位置(XZ)をHLSLに送る
casterPos.xzという変数で、影の中心の位置を指定します。- これはプレイヤーの真下の位置(XZ座標)です。
cbuffer ShadowParam : register(b2)
{
float4 casterPos; // プレイヤーのXZ位置(影の中心)
float4 shadowParams; // x:半径, y:ぼかし, z:濃さ, w:高さ
}② ピクセルシェーダーで、今の描画場所とプレイヤーの距離を調べる
float2 d = inData.wpos.xz - casterPos.xz;
float distSq = dot(d, d); // 二乗距離(速い)これで「このピクセルが影の中心からどれくらい離れてるか」が分かります。
③ 半径の中にあるなら、少し黒くする
float radius = shadowParams.x;
float softness = shadowParams.y;
float alphaScale = shadowParams.z;
float intensity = saturate((radius * radius - distSq) * softness);
float shadowAlpha = intensity * alphaScale;名前 | 意味 |
|---|---|
| 影の半径(大きさ) |
| 境界のぼやけ具合 |
| 影の濃さ |
④ 影の濃さを、黒で合成!
result.rgb = lerp(result.rgb, float3(0, 0, 0), shadowAlpha);これで、shadowAlpha の強さだけ黒くなります。
⑤ 高さに応じて調整する(ジャンプ中も自然に)
float heightRatio = saturate(shadowParams.w * 0.3f);
float dynamicRadius = lerp(radius, radius * 1.8f, heightRatio);
float dynamicAlphaScale = lerp(alphaScale, alphaScale * 0.3f, heightRatio);高さが低いとき(地面) | 小さくて濃い影 |
|---|---|
高さが高いとき(ジャンプ中) | 大きくて薄い影 |
📝 最後にまとめると
項目 | 内容 |
|---|---|
💡 本質 | 黒いスポットライトの逆(黒く照らす) |
🎮 パフォーマンス | 超軽い。リアル影の100倍速いことも |
🧠 理解度 | 円の距離と濃さを調べて、ちょっと黒くするだけ |
📏 調整可能 | 半径、ぼかし、濃さ、高さに応じて調整できる |
📌 図解(かんたんに)
👦
↑ プレイヤー
| 高さ(距離)
↓
┌──────────────────┐
│ ●●●●●●●●●●● │ ← 黒い影(中心からだんだん薄く)
└──────────────────┘コンスタントバッファへの毎フレームのプレイヤーの位置とパラメタの渡し方
💡 1. プレイヤーの位置と影の設定を準備
float4 casterPos = { playerX, playerY, playerZ, 1.0f };
float4 shadowParams = { radius, softness, alphaScale, height };casterPos→ 影を作りたいプレイヤーの位置(XZだけ使う)shadowParams→ 影の大きさ・ぼかし具合・濃さ・高さ
🔧 2. それを GPU 用のバッファに入れて…
device->CreateBuffer(...); // ID3D11Buffer* cbShadow
context->UpdateSubresource(cbShadow, ...);🚀 3. ピクセルシェーダーのスロットb2に渡す
context->PSSetConstantBuffers(2, 1, &cbShadow);🎨 4. HLSL の cbuffer ShadowParam : register(b2) に届く
これで casterPos と shadowParams がシェーダーの中で使えるようになります!