Модераторы: Rickert, Alexeis, BorisVorontsov
  

Поиск:

Ответ в темуСоздание новой темы Создание опроса
> OpenGL/Вычисление нормалей, Большие куски кода и рисунки (траффик) 
:(
    Опции темы
Succorso
Дата 5.8.2006, 22:12 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 9
Регистрация: 31.5.2006

Репутация: нет
Всего: нет



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

Код реализации данной задачи:
Код

// init == true : идёт инициализация
// init == false : инициализация уже была, и нормали не высчитываем
if(init)
{
    for(int j = 0; j < qualTr; j++)
    {
        u = detour[j * 3] - 1;        // первая вершина
        i = detour[j * 3 + 1] - 1;    // вторая вершина
        o = detour[j * 3 + 2] - 1;  // третья вершина

        // вычисление вектора перпендикулярного грани треугольника
        float r1[ 3 ], r2[ 3 ];    
        for (int k = 0; k < 3; k++)
        {
            r1[ k ] = locvec[i * 3 + k + 3] - locvec[u * 3 + k + 3];
            r2[ k ] = locvec[o * 3 + k + 3] - locvec[u * 3 + k + 3];
        }
        
        // векторное произведение 2-x векторов
        // x, y, z - координаты нормали
        x = r1[ 1 ] * r2[ 2 ] - r1[ 2 ] * r2[ 1 ];
        y = r1[ 2 ] * r2[ 0 ] - r1[ 0 ] * r2[ 2 ];
        z = r1[ 0 ] * r2[ 1 ] - r1[ 1 ] * r2[ 0 ];
        
        // нормализуем нормаль - т.е. приводим к единичному вектору 
        d = sqrt( x * x + y * y + z * z );
        if(d == 0)
            d = 1;                    
        x /= d;
        y /= d; 
        z /= d;

        // заносим вычисленные нормали в массив
        for(int k = 0; k < 3; k++)
            mechanism->setNormal(numpart, numgener, k, 0);

        mechanism->setNormal(numpart, numgener, u * 3 + 3, x);
        mechanism->setNormal(numpart, numgener, u * 3 + 1 + 3, y);
        mechanism->setNormal(numpart, numgener, u * 3 + 2 + 3, z);

        mechanism->setNormal(numpart, numgener, i * 3 + 3, x);
        mechanism->setNormal(numpart, numgener, i * 3 + 1 + 3, y);
        mechanism->setNormal(numpart, numgener, i * 3 + 2 + 3, z);

        mechanism->setNormal(numpart, numgener, o * 3 + 3, x);
        mechanism->setNormal(numpart, numgener, o * 3 + 1 + 3, y);
        mechanism->setNormal(numpart, numgener, o * 3 + 2 + 3, z);
    }
}
// отрисовываем модель
for(int j = 0; j < qualTr; j++)
{        
    u = detour[j * 3] - 1;
    i = detour[j * 3 + 1] - 1;
    o = detour[j * 3 + 2] - 1;

    glBegin( GL_TRIANGLES );
        // достаём нормаль для 1-ой вершины
        glNormal3f(locnorm[u * 3 + 3], locnorm[u * 3 + 3 + 1], locnorm[u * 3 + 3 + 2]);
        
        float v[ 3 ];
        for( int k = 0; k < 3; k++ )
            v[ k ] = locvec[u * 3 + k + 3];
        glVertex3fv( v );

        // достаём нормаль для 2-ой вершины
        glNormal3f(locnorm[i*3 +3], locnorm[i * 3 + 3 + 1], locnorm[i * 3 + 3 + 2]);
        for( int k = 0; k < 3; k++ )
            v[ k ] = locvec[i * 3 + k + 3];
        glVertex3fv( v );

        // достаём нормаль для 3-ей вершины
        glNormal3f(locnorm[o*3 +3], locnorm[o * 3 + 3 + 1], locnorm[o * 3 + 3 + 2]);
        for( int k = 0; k < 3; k++ )
            v[ k ] = locvec[o * 3 + k + 3];
        glVertex3fv( v );
    glEnd();
}

И полученное изображение получается изломанным:
user posted image
Теперь же если заставить программу во время каждой отрисовки модели вычислять нормаль (комментируем несколько строк) для треугольника, который мы рисуем в текущий момент, то получаем "по красивее" изображение (падение FPS в 15 раз, т.к. нормали вычисляются каждый раз).
Код:
Код

// init == true : идёт инициализация
// init == false : инициализация уже была, и нормали не высчитываем
//if(init)
//{
    for(int j = 0; j < qualTr; j++)
    {
        u = detour[j * 3] - 1;        // первая вершина
        i = detour[j * 3 + 1] - 1;    // вторая вершина
        o = detour[j * 3 + 2] - 1;  // третья вершина

        // вычисление вектора перпендикулярного грани треугольника
        float r1[ 3 ], r2[ 3 ];    
        for (int k = 0; k < 3; k++)
        {
            r1[ k ] = locvec[i * 3 + k + 3] - locvec[u * 3 + k + 3];
            r2[ k ] = locvec[o * 3 + k + 3] - locvec[u * 3 + k + 3];
        }
        
        // векторное произведение 2-x векторов
        // x, y, z - координаты нормали
        x = r1[ 1 ] * r2[ 2 ] - r1[ 2 ] * r2[ 1 ];
        y = r1[ 2 ] * r2[ 0 ] - r1[ 0 ] * r2[ 2 ];
        z = r1[ 0 ] * r2[ 1 ] - r1[ 1 ] * r2[ 0 ];
        
        // нормализуем нормаль - т.е. приводим к единичному вектору 
        d = sqrt( x * x + y * y + z * z );
        if(d == 0)
            d = 1;                    
        x /= d;
        y /= d; 
        z /= d;

        // заносим вычисленные нормали в массив
        for(int k = 0; k < 3; k++)
            mechanism->setNormal(numpart, numgener, k, 0);

        mechanism->setNormal(numpart, numgener, u * 3 + 3, x);
        mechanism->setNormal(numpart, numgener, u * 3 + 1 + 3, y);
        mechanism->setNormal(numpart, numgener, u * 3 + 2 + 3, z);

        mechanism->setNormal(numpart, numgener, i * 3 + 3, x);
        mechanism->setNormal(numpart, numgener, i * 3 + 1 + 3, y);
        mechanism->setNormal(numpart, numgener, i * 3 + 2 + 3, z);

        mechanism->setNormal(numpart, numgener, o * 3 + 3, x);
        mechanism->setNormal(numpart, numgener, o * 3 + 1 + 3, y);
        mechanism->setNormal(numpart, numgener, o * 3 + 2 + 3, z);
    //}
//}
// отрисовываем модель
//for(int j = 0; j < qualTr; j++)
//{        
    u = detour[j * 3] - 1;
    i = detour[j * 3 + 1] - 1;
    o = detour[j * 3 + 2] - 1;

    glBegin( GL_TRIANGLES );
        // достаём нормаль для 1-ой вершины
        glNormal3f(locnorm[u * 3 + 3], locnorm[u * 3 + 3 + 1], locnorm[u * 3 + 3 + 2]);
        
        float v[ 3 ];
        for( int k = 0; k < 3; k++ )
            v[ k ] = locvec[u * 3 + k + 3];
        glVertex3fv( v );

        // достаём нормаль для 2-ой вершины
        glNormal3f(locnorm[i*3 +3], locnorm[i * 3 + 3 + 1], locnorm[i * 3 + 3 + 2]);
        for( int k = 0; k < 3; k++ )
            v[ k ] = locvec[i * 3 + k + 3];
        glVertex3fv( v );

        // достаём нормаль для 3-ей вершины
        glNormal3f(locnorm[o*3 +3], locnorm[o * 3 + 3 + 1], locnorm[o * 3 + 3 + 2]);
        for( int k = 0; k < 3; k++ )
            v[ k ] = locvec[o * 3 + k + 3];
        glVertex3fv( v );
    glEnd();
}

Изображение теперь выглядит так:
user posted image

Теперь же решил дальше поэкспериментировать и заставить программу во время каждой отрисовки вычислить вначале все нормали для каждой вершины, а уже только потом отрисовать треугольники (падение FPS в 15 раз, т.к. нормали вычисляются каждый раз):
Код

// init == true : идёт инициализация
// init == false : инициализация уже была, и нормали не высчитываем
//if(init)
//{
    for(int j = 0; j < qualTr; j++)
    {
        u = detour[j * 3] - 1;        // первая вершина
        i = detour[j * 3 + 1] - 1;    // вторая вершина
        o = detour[j * 3 + 2] - 1;  // третья вершина

        // вычисление вектора перпендикулярного грани треугольника
        float r1[ 3 ], r2[ 3 ];    
        for (int k = 0; k < 3; k++)
        {
            r1[ k ] = locvec[i * 3 + k + 3] - locvec[u * 3 + k + 3];
            r2[ k ] = locvec[o * 3 + k + 3] - locvec[u * 3 + k + 3];
        }
        
        // векторное произведение 2-x векторов
        // x, y, z - координаты нормали
        x = r1[ 1 ] * r2[ 2 ] - r1[ 2 ] * r2[ 1 ];
        y = r1[ 2 ] * r2[ 0 ] - r1[ 0 ] * r2[ 2 ];
        z = r1[ 0 ] * r2[ 1 ] - r1[ 1 ] * r2[ 0 ];
        
        // нормализуем нормаль - т.е. приводим к единичному вектору 
        d = sqrt( x * x + y * y + z * z );
        if(d == 0)
            d = 1;                    
        x /= d;
        y /= d; 
        z /= d;

        // заносим вычисленные нормали в массив
        for(int k = 0; k < 3; k++)
            mechanism->setNormal(numpart, numgener, k, 0);

        mechanism->setNormal(numpart, numgener, u * 3 + 3, x);
        mechanism->setNormal(numpart, numgener, u * 3 + 1 + 3, y);
        mechanism->setNormal(numpart, numgener, u * 3 + 2 + 3, z);

        mechanism->setNormal(numpart, numgener, i * 3 + 3, x);
        mechanism->setNormal(numpart, numgener, i * 3 + 1 + 3, y);
        mechanism->setNormal(numpart, numgener, i * 3 + 2 + 3, z);

        mechanism->setNormal(numpart, numgener, o * 3 + 3, x);
        mechanism->setNormal(numpart, numgener, o * 3 + 1 + 3, y);
        mechanism->setNormal(numpart, numgener, o * 3 + 2 + 3, z);
    }
//}
// отрисовываем модель
for(int j = 0; j < qualTr; j++)
{        
    u = detour[j * 3] - 1;
    i = detour[j * 3 + 1] - 1;
    o = detour[j * 3 + 2] - 1;

    glBegin( GL_TRIANGLES );
        // достаём нормаль для 1-ой вершины
        glNormal3f(locnorm[u * 3 + 3], locnorm[u * 3 + 3 + 1], locnorm[u * 3 + 3 + 2]);
        
        float v[ 3 ];
        for( int k = 0; k < 3; k++ )
            v[ k ] = locvec[u * 3 + k + 3];
        glVertex3fv( v );

        // достаём нормаль для 2-ой вершины
        glNormal3f(locnorm[i*3 +3], locnorm[i * 3 + 3 + 1], locnorm[i * 3 + 3 + 2]);
        for( int k = 0; k < 3; k++ )
            v[ k ] = locvec[i * 3 + k + 3];
        glVertex3fv( v );

        // достаём нормаль для 3-ей вершины
        glNormal3f(locnorm[o*3 +3], locnorm[o * 3 + 3 + 1], locnorm[o * 3 + 3 + 2]);
        for( int k = 0; k < 3; k++ )
            v[ k ] = locvec[o * 3 + k + 3];
        glVertex3fv( v );
    glEnd();
}

И изображение как в первом варианте с "ломаным" светом.

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

Помогите кто уже сталкивался с вычислениями нормалей, м.б. уже были подобные трудности. Если нет, то прошу просто помочь разобраться, проект уже третий день стоит из-за этой проблемы.
PM MAIL WWW ICQ   Вверх
Succorso
Дата 6.8.2006, 13:15 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 9
Регистрация: 31.5.2006

Репутация: нет
Всего: нет



После обсуждения проблемы на gamedev (http://www.gamedev.ru/code/forum/?id=52427) стало ясно, что ошибка закралась в части хранения данных, а не в алгоритме вычисления нормалей. Топик можно закрывать.
PM MAIL WWW ICQ   Вверх
  
Ответ в темуСоздание новой темы Создание опроса
Вы можете найти полезным что...
Alexeis
Rickert
  • Английская документация по DirectX лежит где-то здесь.
  • Английская документация по OpenGL лежит где-то там.
  • Гейм-дев у нас обсуждают где-то тут

Ждём вас! С уважением, Alexeis, Rickert.

 
0 Пользователей читают эту тему (0 Гостей и 0 Скрытых Пользователей)
0 Пользователей:
« Предыдущая тема | C/C++: Мультимедия, OpenGL/DirectX | Следующая тема »


 




[ Время генерации скрипта: 0.0480 ]   [ Использовано запросов: 21 ]   [ GZIP включён ]


Реклама на сайте     Информационное спонсорство

 
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности     Powered by Invision Power Board(R) 1.3 © 2003  IPS, Inc.