Показаны сообщения с ярлыком calculation. Показать все сообщения
Показаны сообщения с ярлыком calculation. Показать все сообщения

воскресенье, 21 июня 2009 г.

UV координаты вершины принадлежащей треугольнику

При сложном разбиении mesh’а (дополнительная генерация геометрии), треугольники дробятся таким образом, что текстурные координаты новых вершин бывает не так просто вычислить. Потому, что новая вершина может по разным причинам быть различно удаленной от вершин треугольника. Вспомнил, что как то приводил свой вывод расчета в форуме xnadev.ru, но как понадобилось самому, долго искал, где именно.

Делаю для себя заначку, чтоб добру не пропадать:



using System;
using Microsoft.Xna.Framework;

namespace Test
{
public class TestMath2
{
public TestMath2()
{
// вершины треугольника
Vector3 A = new Vector3(1f, -1f, 0f);
Vector3 B = new Vector3(3f, -4f, 0f);
Vector3 C = new Vector3(5f, -1f, 0f);
// текстурные координаты вершин
Vector2 tA = new Vector2(1f, 1f);
Vector2 tB = new Vector2(3f, 4f);
Vector2 tC = new Vector2(5f, 1f);
// точка в плоскости треугольника ограниченная его гранями
Vector3 D = new Vector3(3f, -2f, 0f);
// B
// .
// / \
// / \
// / \
// / .D \
// / \
// .-----------.
// A C
// расчет
Vector2 tD = CalculationDuvFromABC( A, tA,
B, tB,
C, tC,
D);
}
///
/// Нахождение текстурных координат точки D
///
/// Позиция точки A
/// Текстурные координаты точки A
/// Позиция точки B
/// Текстурные координаты точки B
/// Позиция точки C
/// Текстурные координаты точки C
/// Позиция точки D
/// Текстурные координаты точки D
private Vector2 CalculationDuvFromABC( Vector3 A, Vector2 tA,
Vector3 B, Vector2 tB,
Vector3 C, Vector2 tC,
Vector3 D)
{
Vector3 E = PointOfLinesCrossing(A, B, C, D);
float kAEC = (E - A).Length() / (C - A).Length();
Vector2 tE = tA + (tC - tA) * kAEC;
float kBDE = (D - B).Length() / (E - B).Length();
return (Vector2)(tB + (tE - tB) * kBDE);
}
///
/// Нахождение позиции точки пересечения двух прямых,
/// проходящих через точки AC и BD
///
/// Позиция точки A
/// Позиция точки B
/// Позиция точки C
/// Позиция точки D
/// Позиция точки E, полученной пересечением двух прямых AC и BD
private Vector3 PointOfLinesCrossing(Vector3 A, Vector3 B, Vector3 C, Vector3 D)
{
Vector3 vecAC = C - A;
Vector3 vecBD = D - B;
float Tac = Math.Abs( Matrix2x2Determinant( vecBD.X, A.X - B.X,
vecBD.Y, A.Y - B.Y)
/
Matrix2x2Determinant( vecBD.X, vecAC.X,
vecBD.Y, vecAC.Y));
return Vector3.Add(A, Vector3.Multiply(vecAC, Tac));
}
///
/// Определитель матрицы 2х2
///
/// a00
/// a01
/// a10
/// a11
/// Определитель
private float Matrix2x2Determinant( float a00, float a01,
float a10, float a11)
{
return (float)(a00 * a11 - a10 * a01);
}
}
}

пятница, 19 июня 2009 г.

Calculation deep normal map

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

Вот еще один, более сложный пример расчета.

Что тут добавлено:
I. При расчете переворачивается ось Y, для приведения соответствующего tangent space к нормальному виду.
Это связанно с тем, что в мировой системе координат ось Y смотрит в верх, а в текстуре в низ.
II. Сглаживание normal map
III. Масштабирование для получения более глубокого эффекта.

(код примера)
///
/// Расчет normal map к текстуре
///

/// Текстура для расчета (цветная, черно-белая - по барабану)
/// Во сколько целых раз нужно уменьшить (2^n)
/// Рассчитанная normal map текстура
private Texture2D GenNormalMamp(Texture2D inTex, int K)
{
int inX = inTex.Width;
int inY = inTex.Height;
int outX = inTex.Width / K;
int outY = inTex.Height / K;
float z = 1;
int l = inX * inY;
Texture2D outTex = new Texture2D(graphics.GraphicsDevice, outX, outY);
Color[] inColor = new Color[l];
Color[] outColor = new Color[l / (K * K)];
float[,] heightMap = new float[outX, outY];
Vector3[,] normalMap = new Vector3[outX, outY];
inTex.GetData(inColor);
// height map
for (int iy = 0; iy < outY; iy++)
{
for (int ix = 0; ix < outX; ix++)
{
Vector3 v3 = inColor[iy * inX * K + ix * K].ToVector3();
heightMap[ix, iy] = (v3.X + v3.Y + v3.Z) / 3;
}
}
// normal map
float[] delHeight = new float[8];
Vector3[] v38 = new Vector3[8];
Vector3 vAddPack = new Vector3(0.5f, 0.5f, 0.5f);
Vector3 vScale = new Vector3(2f, 2f, 1f);
for (int iy = 0; iy < outY; iy++)
{
for (int ix = 0; ix < outX; ix++)
{
if (iy == 0 || iy == outY - 1 || ix == 0 || ix == outX - 1)
{
normalMap[ix, iy] = Vector3.Backward;
continue;
}
delHeight[0] = heightMap[ix, iy] - heightMap[ix - 1, iy - 1];
delHeight[1] = heightMap[ix, iy] - heightMap[ix, iy - 1];
delHeight[2] = heightMap[ix, iy] - heightMap[ix + 1, iy - 1];
delHeight[3] = heightMap[ix, iy] - heightMap[ix - 1, iy];
delHeight[4] = heightMap[ix, iy] - heightMap[ix + 1, iy];
delHeight[5] = heightMap[ix, iy] - heightMap[ix - 1, iy + 1];
delHeight[6] = heightMap[ix, iy] - heightMap[ix, iy + 1];
delHeight[7] = heightMap[ix, iy] - heightMap[ix + 1, iy + 1];
v38[0] = new Vector3(-delHeight[0], delHeight[0], z - delHeight[0]);
v38[1] = new Vector3(0f, delHeight[1], z - delHeight[1]);
v38[2] = new Vector3(delHeight[2], delHeight[2], z - delHeight[2]);
v38[3] = new Vector3(-delHeight[3], 0f, z - delHeight[3]);
v38[4] = new Vector3(delHeight[4], 0f, z - delHeight[4]);
v38[5] = new Vector3(-delHeight[5], -delHeight[5], z - delHeight[5]);
v38[6] = new Vector3(0f, -delHeight[6], z - delHeight[6]);
v38[7] = new Vector3(delHeight[7], -delHeight[7], z - delHeight[7]);
normalMap[ix, iy] = Vector3.Zero;
for (int ii = 0; ii < 8; ii++) normalMap[ix, iy] += v38[ii] * vScale;
normalMap[ix, iy].Normalize();
}
}
// smooth
Vector3[] s = new Vector3[8];
int pas = 4;
for (int iS = 0; iS < pas; iS++)
{
for (int iy = 1; iy < outY - 2; iy++)
{
for (int ix = 1; ix < outY - 2; ix++)
{
if (normalMap[ix, iy] == Vector3.Backward) continue;
s[0] = normalMap[ix - 1, iy - 1];
s[1] = normalMap[ix, iy];
s[2] = normalMap[ix + 1, iy - 1];
s[3] = normalMap[ix - 1, iy];
s[4] = normalMap[ix + 1, iy];
s[5] = normalMap[ix - 1, iy + 1];
s[6] = normalMap[ix, iy + 1];
s[7] = normalMap[ix + 1, iy + 1];
normalMap[ix, iy] = Vector3.Zero;
for (int ii = 0; ii < s.Length; ii++)
normalMap[ix, iy] += s[ii];
normalMap[ix, iy].Normalize();
}
}
}
// color
int i = 0;
for (int iy = 0; iy < outY; iy++)
{
for (int ix = 0; ix < outX; ix++)
{
normalMap[ix, iy] *= new Vector3(16f, 16f, 1f);
normalMap[ix, iy].Normalize();
outColor[i] = new Color(new Color(normalMap[ix, iy] * 0.5f + vAddPack), heightMap[ix, iy]);
i++;
}
}
// texture
outTex.SetData(outColor);
outTex.Save(@"normalMap.tga", ImageFileFormat.Tga);
return outTex;
}

картинка normal map

результат Bump mapping'а

понедельник, 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.