понедельник, 15 июня 2009 г.

Calculation normal map for “Bump mapping” & “Parallax Mapping”

Расчет normal map для“Bump mapping” и “Parallax Mapping”

Было время, когда разбирался с реализацией Bump и Parallax Mapping.
В статьях которые я находил, помнится очень раздражали высказывания типа:
"... Для расчета карт нормалей существуют специальные программы. На сайте nVidia для разработчиков есть плагин к PhotoShop'у. Все они действуют по одному и тому же принципу. В них задается карта высот, которая представляет собой черно-белое изображение, на котором более светлые пятна соответствует более высоким местам ..."(из оригинала).
Это не хорошо и не плохо. Просто нужна была конкретика.

Что нам может дать собственный расчет? Он избавит нас от необходимости включения в проект предварительно рассчитанных normal map текстур. И тем самым сократить размер дистрибутива. Так же во время расчета, проигравшись с коэффициентами, можно добиться различных результатов.

Потому, дабы сэкономить Вам время, привожу свой пример для XNA GS.

  private Texture2D GenNormalMamp(Texture2D inTex)
  {
  int x = inTex.Width;
  int y = inTex.Height;
  int l = x * y;
  Texture2D outTex = new Texture2D(graphics.GraphicsDevice, x, y);
  Color[] color = new Color[l];
  float[] height = new float[l];
  inTex.GetData(color);
  for (int i = 0; i < l; i++)
  {
  Vector3 v3 = color[i].ToVector3();
  height[i] = (v3.X + v3.Y + v3.Z) / 3;
  }
  float[] delHeight = new float[8];
  Vector3[] v38 = new Vector3[8];
  for (int iy = 0; iy < y; iy++)
  {
  for (int ix = 0; ix < x; ix++)
  {
  if (iy == 0 || iy == y - 1 || ix == 0 || ix == x - 1)
  {
  color[iy * x + ix] = new Color(0.5f, 0.5f, 1f, 1f);
  continue;
  }
  delHeight[0] = height[iy * x + ix] - height[(iy - 1) * x + ix - 1];
  delHeight[1] = height[iy * x + ix] - height[(iy - 1) * x + ix ];
  delHeight[2] = height[iy * x + ix] - height[(iy - 1) * x + ix + 1];
  delHeight[3] = height[iy * x + ix] - height[iy * x + ix - 1];
  delHeight[4] = height[iy * x + ix] - height[iy * x + ix + 1];
  delHeight[5] = height[iy * x + ix] - height[(iy + 1) * x + ix - 1];
  delHeight[6] = height[iy * x + ix] - height[(iy + 1) * x + ix ];
  delHeight[7] = height[iy * x + ix] - height[(iy + 1) * x + ix + 1];
  v38[0] = new Vector3(-delHeight[0], -delHeight[0], 1f);
  v38[1] = new Vector3(0f, -delHeight[1], 1f);
  v38[2] = new Vector3(delHeight[2], -delHeight[2], 1f);
  v38[3] = new Vector3(-delHeight[3], 0f, 1f);
  v38[4] = new Vector3(delHeight[4], 0f, 1f);
  v38[5] = new Vector3(-delHeight[5], delHeight[5], 1f);
  v38[6] = new Vector3(0f, delHeight[6], 1f);
  v38[7] = new Vector3(delHeight[7], delHeight[7], 1f);
  Vector3 vS = new Vector3();
  for (int s = 0; s < 8; s++) vS += v38[s];
  Vector3 v = vS;
  v.X = v.X * 0.5f + 0.5f;
  v.Y = v.Y * 0.5f + 0.5f;
  color[iy * x + ix] = new Color(v);
  }
  }
  outTex.SetData(color);
  return outTex;
  }


Берем стандартную текстуру из приложения к Microsoft DirectX SDK:


И получаем:

Если не поленюсь, чуть позже, приведу примеры реализации “Bump mapping” & “Parallax Mapping” в XNA.


8 комментариев:

  1. Спасибо за статейку, буду ждать продолжения о поводу “Bump mapping” & “Parallax Mapping” в XNA :)

    ОтветитьУдалить
  2. спасибо за отзыв!

    есть вариант более глубокого результата со сглаживанием и (в отличие от этого примера) для нормально ориентированного tangent space

    выкладывать? :)

    ОтветитьУдалить
  3. Выкладывать :)
    А есть пример как можно преобразовать карту высот в карту нормалей в ContentProcessor'е? или другого примера работы с текстурами на этапе компиляции?

    ОтветитьУдалить
  4. на выходных постараюсь написать про глубокий normal map (сглаженный, c alpha каналом) и Bump mapping (пример готов, описание нет).

    с ContentProcessor'ом еще не разбирался.
    не горит пока.

    ОтветитьУдалить
  5. Написал на основе данной статьи расширенный текстурный процессор. Выложить на xnadev.ru?

    ОтветитьУдалить
  6. супер. только данный расчет поправить нужно.
    для корректного расчета tangent space

    ОтветитьУдалить
  7. для простоты примера я не инвертировал ось Y.
    т.к. в текстуре эта ось смотрит в низ, а в мировой системе координат в верх, tangent space получается извращенный, нужно переводить.
    ща закину пост с более сложным расчетом.

    ОтветитьУдалить