高さまたは深度マップを読み取るためのサンプラー。
/// same data as HeightMap, but in a format that the pixel shader can read
/// the pixel shader dynamically generates the surface normals from this.
extern Texture2D HeightMap;
sampler2D HeightSampler = sampler_state
{
Texture=(HeightMap);
AddressU=CLAMP;
AddressV=CLAMP;
Filter=LINEAR;
};
私の入力マップは 512x512 の単一コンポーネント グレースケール テクスチャであることに注意してください。そこから法線を計算するのは非常に簡単です。
#define HALF2 ((float2)0.5)
#define GET_HEIGHT(heightSampler,texCoord) (tex2D(heightSampler,texCoord+HALF2))
///calculate a normal for the given location from the height map
/// basically, this calculates the X- and Z- surface derivatives and returns their
/// cross product. Note that this assumes the heightmap is a 512 pixel square for no particular
/// reason other than that my test map is 512x512.
float3 GetNormal(sampler2D heightSampler, float2 texCoord)
{
/// normalized size of one texel. this would be 1/1024.0 if using 1024x1024 bitmap.
float texelSize=1/512.0;
float n = GET_HEIGHT(heightSampler,texCoord+float2(0,-texelSize));
float s = GET_HEIGHT(heightSampler,texCoord+float2(0,texelSize));
float e = GET_HEIGHT(heightSampler,texCoord+float2(-texelSize,0));
float w = GET_HEIGHT(heightSampler,texCoord+float2(texelSize,0));
float3 ew = normalize(float3(2*texelSize,e-w,0));
float3 ns = normalize(float3(0,s-n,2*texelSize));
float3 result = cross(ew,ns);
return result;
}
そして、それを呼び出すピクセル シェーダー:
#define LIGHT_POSITION (float3(0,2,0))
float4 SolidPS(float3 worldPosition : NORMAL0, float2 texCoord : TEXCOORD0) : COLOR0
{
/// calculate a normal from the height map
float3 normal = GetNormal(HeightSampler,texCoord);
/// return it as a color. (Since the normal components can range from -1 to +1, this
/// will probably return a lot of "black" pixels if rendered as-is to screen.
return float3(normal,1);
}
LIGHT_POSITION
ホスト コードから入力することができます (そして、おそらく入力する必要があります) が、ここでは定数をだまして使用しました。
この方法では、法線ごとに 4 つのテクスチャ ルックアップが必要であることに注意してください。色を取得するために 1 回は数えません。それはあなたにとって問題ではないかもしれません(あなたが何をしているかによって異なります)。それがパフォーマンス ヒットになりすぎる場合は、テクスチャが変更されるたびにそれを呼び出し、ターゲットにレンダリングし、結果を法線マップとしてキャプチャすることができます。
別の方法として、高さマップでテクスチャリングされた画面に位置合わせされたクワッドをレンダー ターゲットに描画し、ddx
/ ddy
HLSL 組み込み関数を使用して、ソース テクスチャを再サンプリングすることなく法線を生成することができます。明らかに、パス前のステップでこれを行い、結果の法線マップを読み返し、それを後の段階への入力として使用します。
いずれにせよ、これは私にとって十分に速いことが証明されました。