新規記事の投稿を行うことで、非表示にすることが可能です。
2018年08月10日
《その434》シェーダ(点光源の場合)(1)
シェーダ(点光源の場合)(1)
点光源とは、発光部の大きさが点とみなせるほど小さく、かつ被照射面との距離が比較的近い 光源のことです。今回のプログラムでは、光源を実際に点として考えます。
(a) 点光源からの光は、光源から離れるにつれて広い面積に拡散するので、明るさは減少します。
(b) ある面に光が当たるとき、光が面に垂直に当たるときが最も明るく、斜めに当たる場合は明るさが減少します。
(a)の効果は、光源と面との距離を用いることで、比較的 簡単に処理することができます。
(b)の効果は、光の向きと面の法線の向きを考えることで、処理することができます。
今回は、(b) の効果のみを扱います。
(a) の効果については、次回に見てみます。
今回も、これまでと同じ立方体を使います。
あらためて、立方体の各頂点の座標を確認しておきます。原点が立方体の中心になっています。
次に、いくつかの出力結果を示しておきます。
点光源の座標が (0.0, 0.8, 0.0) のときの様子です(真上からの照射です)。
光が当たらない面は真っ黒になっています。
点光源の座標が (0.0, 1.5, 2.0) のときの様子です(手前やや上からの照射です)。
点光源の座標が (0.0, 0.0, 1.0) のときの様子です(正面からの照射です)。
点光源の座標が (0.6, 0.7, 0.7) のときの様子です(手前右上からの照射です)。
以下は、SampleVertexShader.hlsl のコードです。
// ジオメトリを作成するために 3つの基本的な列優先のマトリックスを保存する定数バッファ
cbuffer ModelViewProjectionConstantBuffer : register(b0)
{
matrix model;
matrix view;
matrix projection;
};
// 頂点シェーダへの入力として使用する頂点ごとのデータ
struct VertexShaderInput
{
float3 pos : POSITION;
float3 nrm : NORMAL;
};
// ピクセルシェーダを通じて渡されるピクセルごとのデータ
struct PixelShaderInput
{
float4 pos : SV_POSITION; // レンダリングパイプラインで加工済みの点座標
float3 pos_ : POSITION; // 未処理のままの点座標
float3 nrm : NORMAL;
};
// GPU で頂点処理を行うための簡単なシェーダ
PixelShaderInput main(VertexShaderInput input)
{
PixelShaderInput output;
float4 pos_ = float4(input.pos, 1.0f);
pos_ = mul(pos_, model);
output.pos_ = pos_.xyz;
float4 pos = float4(input.pos, 1.0f);
pos = mul(pos, model);
pos = mul(pos, view);
pos = mul(pos, projection);
output.pos = pos;
float4 nrm = float4(normalize(input.nrm), 0.0f);
nrm = mul(nrm, model);
output.nrm = normalize(nrm.xyz);
return output;
}
以下は、SamplePixelShader.hlsl のコードです。
// ピクセルシェーダを通じて渡されるピクセルごとのデータ
struct PixelShaderInput
{
float4 pos : SV_POSITION;
float3 pos_ : POSITION;
float3 nrm : NORMAL;
};
// (補間済み)色データのパススルー関数
float4 main(PixelShaderInput input) : SV_TARGET
{
// light処理をしたピクセルの色成分を返します。
float3 light = float3(0.6, 0.7, 0.7); // 点光源の位置
float3 lightDirection = input.pos_ - light; // 光の方向ベクトル
float len = length(lightDirection); // 光の方向ベクトルを正規化(大きさを 1 にします)
// 正規化した法線ベクトル と 正規化した光の方向ベクトル のなす角から、その点の明るさの程度(0 〜 1)を算出。
float lightMagnitude = saturate(dot(input.nrm, -normalize(lightDirection)));
return float4(0,1,0,0) * lightMagnitude; // 緑色(R,G,B が 0,1,0)に明るさの程度を乗じます。
}