Пробоотборник для чтения карты высоты или глубины.
/// 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 поиска текстур на нормальный, не считая одного, чтобы получить цвет. Возможно, это не проблема для вас (в зависимости от того, что вы делаете). Если это слишком сильно влияет на производительность, вы можете просто называть его всякий раз, когда текстура изменяется, отображает цель и фиксирует результат как обычную карту.
Альтернативой может быть нарисовать квадрат с выравниванием по экрану с текстурой высот до цели рендеринга и использовать свойства HLSL ddx
/ddy
для генерации нормалей без необходимости повторной выборки исходной текстуры. Очевидно, что вы сделаете это на этапе предварительного прохода, прочитайте полученную нормальную карту назад, а затем используйте ее как вход для своих последующих этапов.
В любом случае, это оказалось достаточно быстрым для меня.
Я не уверен, если это возможно. На самом деле вы хотите создать 3D-модель (нормальную карту) 2D-текстуры. – Ondra