Нормаль из координат треугольника Объяснения и Реализующая Функция
Решил сделать карту высот, Все просто и понятно, одна картинка чёрно-белая формирует рельеф, вторая цветная формирует цвет.
Но вот вечная проблема нормалей, помню несколько лет для моделей искал тему, нашёл кусок кода вставил, заработало но верно ли и каким образом до конца не был уверен. Для карты высот такой же вопрос, возможно так тоже можно было бы решить, но немного хочу разобраться и получить 100 процентной рабочий способ. Не привязывая к конкретно моей программе хочу получить общее понятное и кратное объяснения без заумных математических фраз, как почитать нормали по трем координатам, не забываем правило построения точек по часовой стрелке, это соблюдено. Дополнительно хотелось бы в ответе получить функцию в которой на входе ми отправляем три точки, а на выходе получаем нормаль.
Заранее спасибо, очень поможете. C++.
Уточнение: нормаль по сути общая для всех трех точек, так как центр нормали всегда в центре координат 0,0,0, а точки находиться в одной плоскости. Точки задаться трема координатами x,y,z
Для тех кто просто посмотреть, нормали нужны для расчета освещения.
Нормаль выглядит как на картинке, но у меня для каждого треугольника (или для каждой точки) своя нормаль.
//===================================== После комментариев KoVadim и Stranger in the Q Вот что получилось, присутствует некий кубизм хотя у каждой верни с одинаковыми координатами только одна нормаль, но думаю разберусь. Блгодарен
К сожалению вопрос не решён, нормали совершенно не корректно рассчитаны. Что странно, на плоскости вроде все ок, но не на холмах. Там просто в бок.
Не уверен что поможет но вот код
namespace USMod
{
class HeighMap
{
public:
//Моделька
MeshCreater Mesh;
//Модель линий для нормалей
MeshCreater NormalMesh;
//только при загрузке
glm::vec3 Scalse;
glm::vec3 Translate;
//Массив с точками итд
MeshCreater::VertexOne **masiv;
//Ширина глубина
float height, width;
HeighMap()
{
height = 0;
width = 0;
}
MeshCreater::v3 glmToV3(glm::vec3 v)
{
MeshCreater::v3 a;
a.x = v.x;
a.y = v.y;
a.z = v.z;
return a;
}
MeshCreater::v2 glmToV2(glm::vec2 v)
{
MeshCreater::v2 a;
a.x = v.x;
a.y = v.y;
return a;
}
//Загрузить картинку
bool Load(std::string url,ShaderL &sh,glm::vec3 scale = glm::vec3(1,0.57,1))
{
Scalse = scale;
//Файл с высотой
FIBITMAP *dib1 = FreeIMloadImage(url.c_str());
if (!dib1)
{
return false; //ошибка
}
Mesh.SH = sh;
NormalMesh.SH = sh;
//темп
int x, y;
//Удалить массив если бил MeshCreater::VertexOne **masiv;
for (int i = 0; i < width; i++)
delete []masiv[i];
delete []masiv;
//Для загрузки текстур
RGBQUAD rgbquad;
FREE_IMAGE_TYPE type;
BITMAPINFOHEADER *header;
type = FreeImage_GetImageType(dib1);
height = FreeImage_GetHeight(dib1);
width = FreeImage_GetWidth(dib1);
//Инит массив MeshCreater::VertexOne **masiv;
masiv = new MeshCreater::VertexOne*[width];
for (int i = 0; i < width; i++)
masiv[i] = new MeshCreater::VertexOne[height];
//С картинки в масив
header = FreeImage_GetInfoHeader(dib1);
int scanLineWidh = ((3 * (int)width) % 4 == 0) ? 3 * (int)width : ((3 * (int)width) / 4) * 4 + 4;
unsigned char * texels = (GLubyte*)calloc(height*scanLineWidh, sizeof(GLubyte));
for (x = 0; x < width; x++)
for (y = 0; y < height; y++)
{
FreeImage_GetPixelColor(dib1, x, y, &rgbquad);
masiv[x][y].v.y = ((GLubyte*)&rgbquad)[1];
}
free(texels);
FreeImage_Unload(dib1);
//=====================================
//Сместить в центр сцены
Translate.x = -width / 2;
Translate.z = -height / 2;
//Заполнить вершины текстур координаты и нормали
for (x = 0; x < width - 1; x++)
for (y = 0; y < height - 1; y++)
{
glm::vec3 a, b, c, d;//Точки
a = glm::vec3(x, masiv[x][y].v.y, y);
b = glm::vec3(x + 1, masiv[x + 1][y + 1].v.y, y + 1);
c = glm::vec3(x + 1, masiv[x + 1][y].v.y, y);
d = glm::vec3(x, masiv[x][y + 1].v.y, y + 1);
//Применить трансформации
a = a * scale + Translate;
b = b * scale + Translate;
c = c * scale + Translate;
d = d * scale + Translate;
glm::vec2 atx, btx, ctx, dtx;//Текстур корденаты
atx = glm::vec2((float)x / (float)width, (float)y / (float)-height);
btx = glm::vec2(((float)x + 1.0f) / (float)width, (((float)y + 1.0f) / (float)-height));
ctx = glm::vec2(((float)x + 1.0f) / (float)width, (float)y / (float)-height);
dtx = glm::vec2(((float)x) / (float)width, ((float)y + 1.0f) / (float)-height);
//a
masiv[x][y].v = glmToV3(a);
masiv[x][y].t = glmToV2(atx);
{
glm::vec3 s = glm::normalize(glm::cross(c-a, c-b));
masiv[x][y].n = glmToV3(s);
}
//b *scale + Translate
masiv[x+1][y+1].v = glmToV3(b);
masiv[x+1][y+1].t = glmToV2(btx);
masiv[x+1][y+1].n = masiv[x][y].n;
//c
masiv[x + 1][y].v = glmToV3(c);
masiv[x + 1][y].t = glmToV2(ctx);
masiv[x + 1][y].n = masiv[x][y].n;
//d
masiv[x][y + 1].v = glmToV3(d);
masiv[x][y + 1].t = glmToV2(dtx);
{
glm::vec3 s = glm::normalize(glm::cross(a - b, a - b));
masiv[x][y+1].n = glmToV3(s);
}
} //Массив заполнен
NormalMesh.begin();
//Обнулить меш
Mesh.begin();
for (x = 0; x < width - 1; x++)
for (y = 0; y < height - 1; y++)
{
//c
Mesh.Nomal3f(masiv[x + 1][y].n);
Mesh.TextCord2f(masiv[x + 1][y].t);
Mesh.Vertex3f(masiv[x + 1][y].v);
//b
Mesh.Nomal3f(masiv[x + 1][y + 1].n);
Mesh.TextCord2f(masiv[x + 1][y + 1].t);
Mesh.Vertex3f(masiv[x + 1][y + 1].v);
//a
Mesh.Nomal3f(masiv[x][y].n);
Mesh.TextCord2f(masiv[x][y].t);
Mesh.Vertex3f(masiv[x][y].v);
NormalMesh.Vertex3f(masiv[x][y].v);
glm::vec3 p2;
p2.x = masiv[x][y].v.x+ masiv[x][y].n.x;
p2.y = masiv[x][y].v.y+ masiv[x][y].n.y;
p2.z = masiv[x][y].v.z+ masiv[x][y].n.z;
NormalMesh.Vertex3f(p2);
//a
Mesh.Nomal3f(masiv[x][y].n);
Mesh.TextCord2f(masiv[x][y].t);
Mesh.Vertex3f(masiv[x][y].v);
//b
Mesh.Nomal3f(masiv[x + 1][y + 1].n);
Mesh.TextCord2f(masiv[x + 1][y + 1].t);
Mesh.Vertex3f(masiv[x + 1][y + 1].v);
//d
Mesh.Nomal3f(masiv[x][y + 1].n);
Mesh.TextCord2f(masiv[x][y + 1].t);
Mesh.Vertex3f(masiv[x][y + 1].v);
}
Mesh.end(); //Компилировать графику
NormalMesh.end();
}
void Draw()
{
Mesh.draw();
NormalMesh.draw(GL_LINES);
}
};
}
Отмечу что источники света вроде работают, но расчет скорее всего работает от позиции точки, а я то думал что за глюки со светом, направление не работает из за некорректных нормалей.
Проверил методику расчета и она верна, значит я где то намудрил, буду разбираться. Проверил на едином треугольнике с постоянно подвижными точками. Все ок.

glm::vec3 A, B, C;
glm::vec3 NormalA;
//Анимировать точки
A = glm::vec3(-5, sin(glfwGetTime())*3, 5);
B = glm::vec3(-5, sin(glfwGetTime()/2)*3, -5);
C = glm::vec3(5, cos(glfwGetTime())*3,5);
NormalA = glm::normalize(glm::cross(C - A, B - A));
TesterNormal.begin();
Tester.begin();
Tester.Nomal3f(NormalA);
Tester.TextCord2f(0,1); Tester.Vertex3f(A);
Tester.TextCord2f(0, 0); Tester.Vertex3f(B);
Tester.TextCord2f(1, 1); Tester.Vertex3f(C);
TesterNormal.Vertex3f(A);
TesterNormal.Vertex3f(A + NormalA);
Tester.end();
TesterNormal.end();
Tester.draw();
TesterNormal.draw(GL_LINES);
В любом случаи расчет нормали normalize(cross(a-b,a-c)) рабочий, Буду копаться в своем коде.





