質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.50%
HLSL

HLSLは、米マイクロソフト社によって開発された Direct3D APIで使われるプロプライエタリなシェーディング言語です。

DirectX

DirectX(ダイレクトエックス)は、 マイクロソフトが開発したゲーム・マルチメディア処理用のAPIの集合です。

Q&A

解決済

1回答

1933閲覧

HLSL ポイントライトの実装

Hoxon

総合スコア13

HLSL

HLSLは、米マイクロソフト社によって開発された Direct3D APIで使われるプロプライエタリなシェーディング言語です。

DirectX

DirectX(ダイレクトエックス)は、 マイクロソフトが開発したゲーム・マルチメディア処理用のAPIの集合です。

0グッド

0クリップ

投稿2017/09/21 04:44

編集2017/09/23 13:53

現在DirectX9でシェーダーの勉強をしております。
シェーダ内でポイントライトを実装してみたのですが、実装結果がちょっとおかしいことになってます。
ライトの位置は床より下
床より下にライトがあるのですが、なぜか天井だけが暗くなってません。
ネットで検索して、逆2乗の法則(光の強さ=1.0/ライトと頂点の距離^2)というのを見つけて一度導入したのですが、余計に変なことになりました(画像イメージとは無関係)
直す方法ご存知の方、ぜひともご教授お願いします。

↓ピクセルシェーダ内の処理 リクエストあれば追記いたします。

HLSL

1 2 //------------------------------------------------ 3 //拡散色 4 //------------------------------------------------ 5 float3 PointDir = normalize(In.wPos - LightPos); // per pixel diffuse lighting //ライトとの距離 6 float PointLPow = dot(-PointDir, w_normal); // 光の強さ -1~1 7 PointLPow = saturate(PointLPow); // 0~1内に収める このLPowが、このピクセルに当たる光の強さになる 0だと0% 1だと100% 8//逆2乗-------------------------------------------------------- 9float Test =(1.0f/(PointDir*PointDir)); 10 11 12 float4 pointCol = PointLPow*Test; //光のつよさ*減衰 13 pointCol.a = 1; //アルファは1固定 14//-------------------------------------------------------------- 15 16 // 環境光ぶんライト色を加算する 17 pointCol += LightAmbient; 18 19 20 //------------------------------------------------ 21 // 反射色 22 //------------------------------------------------ 23 float3 vCam = normalize( CamPos - In.wPos // 目(カメラ)への方向 24 25 //point 26 float3 pvRef = PointDir + 2.0f * dot(w_normal, -PointDir) * w_normal; 27 float pspePow = pow(max(0, dot(vCam, pvRef)), MateSpePower); 28 float4 plightSpe = LightSpecular * pspePow; 29 30 // 最終的な色を算出。 31 float4 PointCol = pointCol * modelCol; // 最終的な拡散(Diffuse)色を求める。 32 float4 PspeCol = plightSpe * MateSpecular; // 最終的な反射(Specular)色を求める。 33 34 //ピクセルシェーダ出力用変数 35 PS_OUT Out; 36 37 Out.Color = PointCol + PspeCol ; // 拡散色 + 反射色 38 39 return Out;

追記
Bongoさん、ご質問ありがとうございます。 確かに影の処理も入っていないのですが、現在天井はライトがどれだけ離れても明るくなっているのです。 ポイントライトなのでライトを下に離していけばだんだんと暗くなっていくはずなのですが・・・

追記2
逆2乗を導入した結果
↓ライトが床より下イメージ説明
↓ライトが床より少し上
イメージ説明
遠くなるほど光が増している?

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

Bongo

2017/09/21 22:20

床の下に光源があるということは、天井の面は光源の方を向いているということですよね?でしたら、天井が明るく照らされて見えるのはもっともらしい結果のように思いますが、質問者さんが意図する結果はどのようなものでしょうか?もし、「天井(あるいは床の上に小さく立っている人形の下面)が、床によって光源から遮られているのに明るく見えるのはおかしい」ということでしたら、これは物体(床)の落とす影をどうやって表現するかという問題になりそうです。
Hoxon

2017/09/22 01:56 編集

ご質問ありがとうございます。 追記いたしました
guest

回答1

0

ベストアンサー

なるほど、そういうことでしたら、描画しようとしているピクセルとライトの距離に基づいて明るさを減衰させればいいはずです(現状では両者の距離が計算に組み込まれておらず、減衰していない状態になるでしょう)。

物理的にはご質問者さんの挙げられた逆2乗の法則を用いるのが妥当かと思いますが、今回のような単純化した照明方式で逆2乗減衰させると、ライトに近い物体(床の上の人形など)が明るくなりすぎたり、遠い物体(天井など)が暗くなりすぎたりしたのではないでしょうか?
今回のケースでは、物理的な正しさにはあまりこだわらず、もっと減衰の仕方を緩やかにするといいかと思います。
例えば減衰とスポットライト係数 (Direct3D 9)では

Atten = 1/( att0i + att1i * d + att2i * d2)

といった感じで減衰率の分母が二次の多項式になっており、定数項(att0i)、1次の項(att1i)、2次の項(att2i)の係数を調整することで減衰のカーブを急にしたりなだらかにしたりできるようにしているようです。
この方式での実装例としては~プログラミング~ DirectX 11で点光源ライティングなどはご参考になりますでしょうか?

私の思うところですと、厳密な逆2乗の法則に基づく減衰は、最近のゲームのような写実的なライティング手法で真価を発揮するような気がします。基礎からはじめる物理ベースレンダリング - Qiitaの記事などでリアルな絵作りの技法が紹介されていました。魅力的ですが、なかなかややこしいですね。

[追記]

ご提示いただいたfloat Test =(1.0f/(PointDir*PointDir));ですと、「PointDir(ライトから見たピクセルの方向)のx、y、zをそれぞれ2乗」→「x、y、zをそれぞれ逆数にする」→「xだけをTestに格納」という結果になってしまうはずです。
この場合、ライトから見たピクセルの方向のx成分の絶対値が小さいほどTestの値は大きくなるので、ご提示の画像のような奇妙な結果になったのかと思います。「ライトが床より少し上」の画像の床部分にこの効果が顕著に見られ、床中心に対して前後方向が最も明るく、左右方向が最も暗くなっています。

シェーダーコードの先頭部分を下記のようにしてみましたがどうでしょうか?

//------------------------------------------------ //拡散色 //------------------------------------------------ float3 PointDir = In.wPos - LightPos; // ライトを原点としたピクセルの相対位置...後で正規化して「ライトから見たピクセルの方向」にする float PointDist = length(PointDir); // PointDirの長さ→ライトとピクセルの距離 PointDir /= PointDist; // 相対位置を距離で割る→これでPointDirがnormalize(In.wPos - LightPos)と同等になる float PointLPow = dot(-PointDir, w_normal); // 光の強さ -1~1...この行は変更なし PointLPow = saturate(PointLPow); // 0~1内に収める このLPowが、このピクセルに当たる光の強さになる 0だと0% 1だと100%...この行も変更なし //逆2乗-------------------------------------------------------- float Test =(1.0f/(PointDist*PointDist)); // PointDirの代わりにPointDistの逆二乗を求める

投稿2017/09/22 11:30

編集2017/09/23 21:29
Bongo

総合スコア10807

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

Hoxon

2017/09/23 11:17

うーん・・・どうにもうまくいきません。 というのも、まず極端な逆2乗減衰のほうを試したのですが、遠い物体が暗くなりすぎたりするのではなく、逆にものすごく強く光っています。 おそらく遠くなるほど光が強くなっているのでしょうが…
Bongo

2017/09/23 11:49

おお...予想外の不具合ですね... さすがにこれは計算式に何かおかしいところがあるんじゃないでしょうか。逆2乗減衰版のコードも見てみたいですが、いかがでしょうか?
Hoxon

2017/09/23 13:55

ほんと予想外で驚いてます・・・ 本文中のコードを逆2乗追加版に編集しておきました。
Hoxon

2017/09/24 06:00

素晴らしいです!納得いく結果になりました! 長らくお付き合いいただきありがとうございました
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.50%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問