DxDev.narod.ru

Bump mapping

Bump mapping это наложение рельефа(неровностей) на участок поверхности. Для этого используется две текстуры одна для участка поверхности назовём её базовой, а другая для карты нормалей имитирующие неровности. Нормали учитывая угол освещения создают иллюзию неровной поверхности. Поэтому базовая текстура должна быть сопоставлена, с картой нормалей.

=

*

TextureBump

TextureBase

NormalMap

Если поворачивать полигон, то его собственные нормали будут также изменять направление, а значит источник должен это учесть. Ведь повернув полигон мы не поворачиваем вектор источника, соответственно у нас есть проблема. Решить её можно с помощью матрицы tangent – spase(TBN) которая трансформит источник относительно полигона. TBN представляет собой базис взаимно перпендикулярных векторов отдельно взятого полигона. Этот базис вычисляется один раз до вывода.

Для каждой поверхности мы имеем два базиса: texture space содержащий текстурные координаты и object space хранящий координаты полигона, источника освещения. Чтобы источник правильно светил на повёрнутый полигон его нужно преобразовать из object space в texture space.

Пусть object space использует базис [(1,0,0), (0,1,0), (0,0,1)], а texture space - [T, B, N] где N = [T x B]. Нам остаётся вычислить Т и В.

Пусть V4 некая точка лежащая внутрях полигона, С4 соответствующая ей текстурная координата. Разложим вектор (С4 – С1) по компонентам Т и В:

Т = (С4 – С1)T
В = (С4 – С1)B

Как я понял текстурные координаты участка (V4 - V1) есть сумма компонентов Т и В:

V4 - V1 = (C4 - C1)T * T + (C4 - C1)B * B

Следовательно для двух сторон поверхности получаем систему уравнений с двумя неизвестными Т и В:

V2 - V1 = (C2 - C1)T * T + (C2 - C1)B * B
V3 - V1 = (C3 - C1)T * T + (C3 - C1)B * B

Запишем её в матричном виде



где

t1 = (C2 - C1)T, t2 = (C3 - C1)T
b1 = (C2 - C1)B, b2 = (C3 - C1)B
v1 = V2 - V1, v2 = V3 - V1

Чтобы в матричном уравнении [B] = [A] [X] найти [X], понадобится обратная матрица [A] -1 для умножения на обе части уравнения.

[A] -1 [B] = [A] [A] -1 [X]
т.к. [A] [A] -1 есть единичная матрица, зн
[A] -1 [B] = [X]

если [A] = тогда [A] -1 = определитель матрицы равен det(A) = t1 * b1 - t2 * b1.



Очевидно det(A) не должен быть равен 0. Т.о. ну и как было ранее сказано N = [T x B]

А для вычисления вектора освещения нужно TBN умножить на world space


struct VS_IN
{
  float4 position : POSITION;
  float2 texcoord : TEXCOORD0;

  // Заранее вычисленный tangent space
  float3 T        : TANGENT;
  float3 B        : BINORMAL;
  float3 N        : NORMAL;  //  N = [T x B]
};

struct VS_OUT
{
  float4 position : POSITION;
  float2 texcoord : TEXCOORD0;
  float4 light    : TEXCOORD1;  // освещение учитанное tangent space - ом
};

float4x4 WorldViewProj;
float4x4 WorldView;
float4   vLight;// освещение в object space

VS_OUT main_vs_hlsl( VS_IN IN)
{
  VS_OUT OUT;

  OUT.position = mul( IN.position, WorldViewProj );

  OUT.texcoord = IN.texcoord;

  float3x3 TBN;

  // tangent space распологаем в мировом пространстве
  TBN[0] = mul(IN.T, WorldView  );
  TBN[1] = mul(IN.B, WorldView );
  TBN[2] = mul( IN.N, WorldView );
  // А light в пространстве tangent space 
  float3 light = mul(TBN, vLight.xyz);
  OUT.light = float4(light, 1.0);

  return OUT;
}

теперь мы имеем корректный источник и его можно смело сопоставлять с картой нормалей.

sampler TextureBase;
sampler NormalMap;

float4 main_ps_hlsl( VS_OUT IN ) : COLOR
{
  float4 ColorOut;

  float4 ColorBase = tex2D( TextureBase, IN.texcoord );
  float4 ColorNormal = 2 * (tex2D(NormalMap, IN.texcoord.xy) - 0.5);

  //convert from [-1;1] to [0;1]
  float4 light = 0.5 * IN.light + 0.5;

  float NormalDotLight = dot(ColorNormal.xyz, light.xyz);

  ColorOut = ColorBase * NormalDotLight;

  return ColorOut;

}

Источники:
http://www.gamedev.net/columns/hardcore/cgbumpmapping/GameDev_net -- Cg Bumpmapping.htm
http://www.blacksmith-studios.dk/projects/downloads/tangent_matrix_derivation.php
HLSL Specular Bump Mapping на gamedev.ru
Просто Bump Mapping на gamedev.ru

Hosted by uCoz