Загрузка файла OBJ, как использовать нормали (#вершины ‹ #нормали)

У меня есть файл obj, и я успешно загрузил объект в opengl без использования заданных нормалей.
Вот как это выглядит:
дерево без нормалей
Формат файла:

v x y z
vn x y z
f x//x' y//y' z//z'

Функция отображения сетки такова:

glBegin(GL_TRIANGLES);
for all faces
{
    glVertex3f(.., .., ..);
    glVertex3f(.., .., ..);
    glVertex3f(.., .., ..);
}
glEnd();

И вот результат:
введите здесь описание изображения

Я читал, что объект может выглядеть плоским из-за вектора нормалей по умолчанию, который OpenGL использует для уравнений освещения.
Это можно решить с помощью нормалей. Даны нормали 780 и вершины 155.

Я пытался использовать glNorm перед каждым вызовом glVertex3f, но объект выглядит совершенно странно (линии и т. д.).

Что я должен делать?

EDIT #1: Вот как я прочитал файл:

void loader(class mesh &tree)
{
int vx1, vx2, vx3, vn1, vn2, vn3;
ifstream file;
string line;
point vec, norm;
face tempface;

file.open("tree.obj"); 
if (file.is_open() == true)
{
    while(getline(file, line) )
    {
        if (line.substr(0,2) == "") continue;
        else if (line.substr(0, 2) == "v ")
        {
            istringstream numbers(line.substr(2));
            numbers >> vec.x >> vec.y >> vec.z;
            tree.vectors.push_back(vec);
        }
        else if (line.substr(0,2) == "vn")
        {
            istringstream numbers(line.substr(2));
            numbers >> norm.x >> norm.y >> norm.z;
            tree.normals.push_back(norm);
        }
        else if (line.substr(0,2) == "f ")
        {
            face f;
            line = line.substr(2,line.length());
            for (string::iterator it = line.begin(); it != line.end(); ++it)
            {
                if (*it == '/')
                {
                    //erase both of the "//"
                    line.erase(it);
                    line.erase(it);
                    //add a space between the numbers
                    line.insert(it, ' ');
                }
            }
            istringstream inp(line);
            inp >> f.vert_indices[0] >> f.norm_indices[0] >> f.vert_indices[1] >> f.norm_indices[1] >> f.vert_indices[2] >> f.norm_indices[2];
            tree.faces.push_back(f);
        }
        else 
            continue;
    }
    file.close();
}
}

И вот как я это показываю:

    void mesh::displayMesh()
{
    glPushMatrix();
    glBegin(GL_TRIANGLES);
    for(vector<face>::const_iterator it = faces.begin();
        it != faces.end(); ++it)
    {
        //glVertex3f(normals[it->norm_indices[0] -1 ].x, normals[it->norm_indices[0] -1 ].y, normals[it->norm_indices[0] -1 ].z);
        glVertex3f(vectors[it->vert_indices[0] -1 ].x, vectors[it->vert_indices[0] -1 ].y, vectors[it->vert_indices[0] -1 ].z);
        //glVertex3f(normals[it->norm_indices[1] -1 ].x, normals[it->norm_indices[1] -1 ].y, normals[it->norm_indices[1] -1 ].z);
        glVertex3f(vectors[it->vert_indices[1] -1 ].x, vectors[it->vert_indices[1] -1 ].y, vectors[it->vert_indices[1] -1 ].z);
        //glVertex3f(normals[it->norm_indices[2] -1 ].x, normals[it->norm_indices[2] -1 ].y, normals[it->norm_indices[2] -1 ].z);
        glVertex3f(vectors[it->vert_indices[2] -1 ].x, vectors[it->vert_indices[2] -1 ].y, vectors[it->vert_indices[2] -1 ].z);
    }
    glEnd();
    glPopMatrix();
}

Функция displayMesh вызывается в функции Render OpenGL, а функция загрузчика вызывается в функции Setup OpenGL, а объект дерева сетки является глобальной переменной.

РЕДАКТИРОВАТЬ №2: Вот как выглядит дерево с нормалями:
дерево с нормалями  Также это код функции настройки OpenGL.


person Chris    schedule 01.02.2013    source источник
comment
Если вы открываете свой OBJ с помощью Blender (или другого 3D-редактора/просмотрщика), он отображается правильно?   -  person Vinícius Gobbo A. de Oliveira    schedule 01.02.2013
comment
Добавление только вызовов glNormal3f перед вашими функциями glVertex3f не даст эффекта, если вы не включите освещение OpenGL glEnable(GL_LIGHTING) и хотя бы один источник света, например, glEnable(GL_LIGHT0). Освещение будет рассчитано со всеми настройками освещения по умолчанию для материалов, светлых цветов и т. д.   -  person radical7    schedule 01.02.2013
comment
@ ViníciusGobboA.deOliveira: Да, я открыл его в Blender, и он выглядит намного лучше, чем когда я загружал его с помощью opengl.   -  person Chris    schedule 01.02.2013
comment
@radical7: Кроме того, я включил освещение в своем коде glEnable(GL_LIGHTING); glEnable(GL_LIGHT0);, и все равно ничего. Я обновил вопрос и добавил две картинки.   -  person Chris    schedule 01.02.2013
comment
Мне кажется, что вы неправильно читаете некоторые вершины. Вы уверены, что каждая строка в файле имеет формат, который вы читаете? Что нет ничего необычного ни в одной из строк в файле obj?   -  person jcoder    schedule 01.02.2013
comment
Да, это не должно быть неправильно. Дано для загрузки по заданию. И поскольку первая картинка в порядке (в смысле формы), почему я должен неправильно читать вершины?   -  person Chris    schedule 01.02.2013
comment
Не могли бы вы предоставить код? Как заявил J99, с загрузкой/чтением происходит что-то подозрительное. Либо вы правильно загружаете вершины, но неправильно их отображаете (доступ к памяти), либо загружаете их неправильно и отображаете правильно (с точки зрения доступа к памяти). Вы можете попробовать использовать glNormalPointer и glVertexPointer (если это еще не сделано) и посмотреть, изменит ли это что-нибудь.   -  person Juicef    schedule 01.02.2013
comment
@Juicef: я добавил код загрузчика и функцию отображения. Если вам нужна дополнительная информация, скажите мне. Я не знаком с этими функциями, попробую использовать их через несколько часов.   -  person Chris    schedule 01.02.2013
comment
Выведите на консоль определение каждой вершины, нормали и грани и проверьте, соответствует ли оно содержимому файла OBJ. Таким образом, мы можем исключить проблему с парсером.   -  person Vinícius Gobbo A. de Oliveira    schedule 01.02.2013
comment
@ ViníciusGobboA.deOliveira: Но имеется около 780 векторов нормалей и 155 вершин: / Как мне проверить 780 векторов нормалей? Мне сделать прорамку или начать проверять на глаз?   -  person Chris    schedule 01.02.2013
comment
@ViníciusGobboA.deOliveira: я нашел свою ошибку! Посмотрите на функцию отображения закомментированных строк. Я хотел загрузить нормали и вызывал glVertex3f, а не glNormal :/ Но элемент все равно выглядит так, как будто у него нет тени (как на 1-м рисунке).   -  person Chris    schedule 02.02.2013
comment
Просто проверить несколько координат может быть достаточно. Не могли бы вы опубликовать новое изображение с новыми результатами (или оно отображается так же, как первое изображение?)? Используете ли вы направленный свет? Если вы используете только окружающий свет, у вашей модели не будет теней.   -  person Vinícius Gobbo A. de Oliveira    schedule 02.02.2013
comment
@ViníciusGobboA.deOliveira: Нужна ли координата w? Я не сохранил его из-за использования glVertex-3-f. Я проверил некоторые координаты вершин, нормалей и граней, и они выглядят нормально. Я также добавил код моей функции настройки.   -  person Chris    schedule 02.02.2013
comment
Когда вы говорите о направленном свете, вы имеете в виду координату w == 1.0? Кроме того, я использую Ambient, Diffuse и Specular, но, как я только что проверил, комментируя эти glLightfv( GL_LIGHT0, GL_AMBIENT, ambientLight ); //glLightfv( GL_LIGHT0, GL_DIFFUSE, diffuseLight ); //glLightfv( GL_LIGHT0, GL_SPECULAR, specularLight); , результат тот же. Значит, что-то не так с освещением?   -  person Chris    schedule 02.02.2013
comment
Может быть так же, как и нет. В зависимости от того, как установлены коэффициенты затухания света, некоторые эффекты могут не достичь вашей модели. Кроме того, ваш коэффициент блеска может быть установлен неправильно. Несмотря на это, весь ваш код кажется мне правильным.   -  person Vinícius Gobbo A. de Oliveira    schedule 02.02.2013
comment
@ViníciusGobboA.deOliveira: Это действительно расстраивает :/ Фактор блеска? Какой это? Спасибо за помощь!! Обновление: Пробовал с движущимся источником света и заметил некоторые различия в дереве, но не большие.   -  person Chris    schedule 02.02.2013
comment
Взгляните на эту страницу: glprogramming.com/red/chapter05.html Здесь объясняется как настроить все затухания и блеска. Блеск связан с зеркальным светом.   -  person Vinícius Gobbo A. de Oliveira    schedule 03.02.2013
comment
Каков статус по этому поводу? Убедитесь, что окружающий свет не слишком яркий, и если ничего не помогает, попробуйте добавить glEnable(GL_NORMALIZE) рядом с тем местом, где вы объявляете glClearColor.   -  person giogadi    schedule 06.02.2013


Ответы (2)


Разве у вас не должно быть в коде отрисовки следующее?

glNormal3f(normals[it->norm_indices[0] -1 ].x, normals[it->norm_indices[0] -1 ].y, normals[it->norm_indices[0] -1 ].z);
glVertex3f(vectors[it->vert_indices[0] -1 ].x, vectors[it->vert_indices[0] -1 ].y, vectors[it->vert_indices[0] -1 ].z);
glNormal3f(normals[it->norm_indices[1] -1 ].x, normals[it->norm_indices[1] -1 ].y, normals[it->norm_indices[1] -1 ].z);
glVertex3f(vectors[it->vert_indices[1] -1 ].x, vectors[it->vert_indices[1] -1 ].y, vectors[it->vert_indices[1] -1 ].z);
glNormal3f(normals[it->norm_indices[2] -1 ].x, normals[it->norm_indices[2] -1 ].y, normals[it->norm_indices[2] -1 ].z);
glVertex3f(vectors[it->vert_indices[2] -1 ].x, vectors[it->vert_indices[2] -1 ].y, vectors[it->vert_indices[2] -1 ].z);

РЕДАКТИРОВАТЬ: ой, вы уже поняли, что

Если вы хотите проверить правильность нормалей, раскрасьте каждую вершину в соответствии с ее нормалью. Используйте glColor3f, но укажите нормали.

person Hannesh    schedule 06.02.2013
comment
Если я это сделаю, какой результат ожидать? Много цветов? - person Chris; 07.02.2013
comment
Лица будут окрашены в соответствии с нормалями. Например, грани, обращенные вверх, будут зелеными, поскольку компонент нормалей y положителен. - person Hannesh; 07.02.2013

когда вы используете стирание, он делает недействительным итератор

//erase both of the "//"
it = line.erase(it);
it = line.erase(it);
//add a space between the numbers
it = line.insert(it, ' ');

однако вы можете стереть один раз, а затем заменить

//erase both of the "//"
it = line.erase(it);
//add a space between the numbers
*it = ' ';
person ratchet freak    schedule 28.04.2014