Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > C/C++: Мультимедия, OpenGL/DirectX > Как вычислить нормаль к вертексу?


Автор: =Женек= 15.12.2020, 15:58
Друзья, есть вопрос. 

Есть библиотека 3d, простенькая. В ней есть функция - грузишь модель, представлющую собой массив, состоящий из вершин, индексов граней, нормалей и цвета, она эту модель отрисовывает.

Массив я создал - забил в него вертексы, назначил их граням, в режиме Wireframe рисует отлично. Хочу теперь запустить имеющуюся функцию отрисовки в режиме Flat и Gouraud.

Для этого в массив к каждому вертексу нужно добавить нормали. Именно к вертексу, а не к грани. ДЛя вычисления нормали к грани там есть своя функция, но для этого в нее нужно ввести нормали вертексов.

Код

    float32_t vertex_norm_a[3];
    float32_t vertex_norm_b[3];
    float32_t vertex_norm_c[3];
..............................
                vertex_norm_a[0] = dsp3dModel[2 + b * 6 + 3]; //   нормаль задается 3 числами
        vertex_norm_a[1] = dsp3dModel[2 + b * 6 + 4];//    заранее, при создании модели
        vertex_norm_a[2] = dsp3dModel[2 + b * 6 + 5];//    забитыми в массив


------------------------
// а потом вычисляется нормаль к грани
    dsp3D_calculateFaceNormal(vertex_norm_a, vertex_norm_b, vertex_norm_c, matrix_worldView, face_norm);




А как вычислить нормали к вертексам? 

Подвопрос: задает ли вершина нормаль? Или для ее расчета необходимы данные о всех трех ребрах, образующих грань?

P.S. Попытался в Blender создать куб, сохранить и посмотреть в сохраненный файл, но в него записались уже вычисленные нормали граней, а по вертексам данных нет.

[size="1"][color="grey"]Добавлено через 58 секунд[/color][/size]
Вот эта библиотека, если что   https://github.com/FabioRM/dsp3D/blob/master/src/dsp3D.c

Автор: Alexeis 15.12.2020, 16:09
=Женек=, в простейшем случае нормаль к вершине, это среднее арифметическое нормалей ко всем полигонам, которые содержат эту вершину. Такие нормали используют для сглаживания при расчете освещения. Но если нужно нарисовать резкую границу, то обычно вершину добавляют в 2 разных набора полигонов и соответственно в каждом из них она будет иметь свое значение нормали. Т.е. она дважды попадет в список вершин.

Автор: =Женек= 15.12.2020, 16:38
Цитата(Alexeis @  15.12.2020,  16:09 Найти цитируемый пост)
это среднее арифметическое нормалей ко всем полигонам, которые содержат эту вершину

А откуда ж я возьму нормаль к полигонам, если нормаль к вертексу мне как раз для того и нужна, чтобы эту нормаль к полигону расчитать?

Смотрите.
Есть функция dsp3D_renderFlat(float32_t * dsp3dModel)     -   вот тут https://github.com/FabioRM/dsp3D/blob/master/src/dsp3D.c

Она в процессе работы читает из dsp3dModel вертексы, индексы граней и нормали ВЕРТЕКСОВ. После чего на основании нормалей ВЕРТЕКСОВ рассчитывает нормали ГРАНЕЙ:

Код

dsp3D_calculateFaceNormal(vertex_norm_a, vertex_norm_b, vertex_norm_c, matrix_worldView, face_norm);


A массив vertex_norm_a она заполняет из dsp3dModel.

Вертексы в dsp3dModel я забил руками.
Грани из вертексов я тоже слепил руками.
Но этого хватает только для режима WireFrame. Для того чтобы идти дальше, мне необходимы нормали ВЕРТЕКСОВ.
Как их посчитать, если даны координаты вертексов (ну и архитектура граней тоже).

Автор: Alexeis 20.12.2020, 14:52
=Женек=, ну блин, нормаль к полигону это школьная программа. Векторное произведение 2х векторов дает вектор перпендикулярный плоскости этих 2х векторов. Берем любые 3 точки полигона, вычисляем вектора, вычитая из конца начало, перемножаем вектора, получаем вектор нормали, нормализуем его разделив координаты на длину вектора, которая вычисляется по теореме Пифагора.


Автор: =Женек= 27.12.2020, 13:33
Я может что-то не так делаю
Вот координаты 8 вершин куба и его нормали
Код

//         VERTEXES  
//   coords    normals
 1, 1, 1,     0, 0, 1, // 0        
 1, 1,-1,     0,-1, 0, // 1            
 1,-1, 1,    -1, 0,0, // 2   
 1,-1,-1,     0, 0,-1, // 3    
-1, 1, 1,     1, 0, 0, // 4 
-1, 1,-1,     0, 1, 0, // 5        
-1,-1, 1,     0, 0, 0, // 6            
-1,-1,-1,     0, 0, 0, // 7 


Черный экран.
Скажите, если нормаль неверна, то будет неправильное освещение? Или вообще не будет визуализации? Неужели я во всех 8 нормалях ошибся?

Автор: Alexeis 3.1.2021, 15:43
=Женек=, причин может быть много черноты. Лучше начать с рабочего примера, чтобы было с чем сравнить. 
Для куба я повторял вершины (вместо того чтобы задавать их индексами), потому как его грани перпендикулярны, вряд ли следует назначать одинаковые нормали для двух взаимно перпендикулярных граней. Т.е. получается что грани взаимно перпендикулярны, а освещаться должны одинаково. 

Автор: =Женек= 6.1.2021, 21:13
Код

Лучше начать с рабочего примера, чтобы было с чем сравнить. 


Нету его! И до автора библиотеки не достучаться


Автор: =Женек= 10.1.2021, 15:11
Вы были правы - причина черноты в другом.
Я поковырялся в коде и нашел вот что

Код

void dsp3D_drawPointDepthBuffer(int32_t x, int32_t y, float32_t z, color32_t color)
{
    if((x > -1) && (x < SCREEN_WIDTH) && (y > -1) && (y < SCREEN_HEIGHT))
    {
        int32_t index = (x + y * SCREEN_WIDTH) * 4;

        if(dsp3D_LL_readFromDepthBuffer(index) < z)  // вот тут засада - условие всегда выполняется и функция прерывается
            return;

        dsp3D_LL_writeToDepthBuffer(index, z);  //  а вот это 
        dsp3D_LL_drawPoint(x, y, color);//  и вот это не вызывается.
    }
}


Я в комментариях в коде написал что к чему.
Так вот, если я убираю эту проверку, то получаю вот такое видео  https://cloud.mail.ru/public/DGUX/TZoRw7stw 
Не обращайте внимание на тормоза, это поправимо.

Геометрия правильная, видно, что освещение не такое, и некоторые грани не освещены, потому что я нормали расставил наугад.
Но объясните мне, для чего нужна функция  dsp3D_LL_writeToDepthBuffer ?
Она пуста, потому что я должен сам туда ввести низкоуровневый код. К примеру функция dsp3D_LL_drawPoint тоже пуста, в нее я ввел свою функцию SetPixel(x,y,color)
А что нужно писать в dsp3D_LL_writeToDepthBuffer?



Автор: kurlyak 25.2.2021, 16:35
Если надо нормаль к вертексу могу дать псевдокод где три вершины треугольника v1, v2, v3.

Код

vector3 edge1,edge2,normal;

edge1 = v2 - v1;
edge2 = v3 - v1;

edge1 = Vec3Normalize(edge1);
edge2 = Vec3Normalize(edge2);

normal = Vec3Cross(edge1, edge2);

normal = Vec3Normalize(normal);


А потом как писалось в ответе усреднить три нормали.

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)