Неправильно нарисованные лица

Обновить

Похоже, что мои нормали работают нормально, и это связано с тем, как я рисую свои лица (рисуется только половина), и я не могу понять, почему —

Вершины, нормали нарисованы правильно

Если бы вы могли взглянуть на мой код ранее (показано ниже)


Оригинальный пост

В настоящее время я работаю над парсером / рендерером для типов файлов .obj. Я сталкиваюсь с проблемой с отображением нормальных векторов:

Без нормалей:

С нормалями:

По какой-то причине я не могу понять, почему только половина нормальных векторов оказывает влияние, а другая половина действует так, как будто лица вообще нет.

Вот мой код для загрузки в файл obj:

    void ObjModel::Load(string filename){
ifstream file(filename.c_str());

if(!file) return;

stringstream ss;
string param, line;
float nparam, cur;

vector<vector<float> > coords;
vector<float> point;

while(getline(file, line)){
ss.clear();
ss.str(line);

ss >> param;

//vertex
if(param == "v"){
for(int i = 0; i < 3; i++){
ss >> nparam;
this->vertices.push_back(nparam);
}
}

//face
else if(param == "f"){
coords.clear();
point.clear();

for(int i = 0; i < 3; i++){
ss >> nparam;
nparam--;

for(int j = 0; j < 3; j++){
cur = this->vertices[nparam * 3 + j];

this->faces.push_back(cur);
point.push_back(cur);
}

coords.push_back(point);
}

point = this->ComputeNormal(coords[0], coords[1], coords[2]);

for(int i = 0; i < 3; i++) this->normals.push_back(point[i]);
}

else continue;
}
}
void ObjModel::Render(){
glEnableClientState(GL_VERTEX_ARRAY);
glEnableClientState(GL_NORMAL_ARRAY);

glVertexPointer(3, GL_FLOAT, 0, &this->faces[0]);
glNormalPointer(GL_FLOAT, 0, &this->normals[0]);

glDrawArrays(GL_TRIANGLES, 0, this->faces.size() / 3);

glDisableClientState(GL_NORMAL_ARRAY);
glDisableClientState(GL_VERTEX_ARRAY);
}

А вот функция для вычисления вектора нормалей:

vector<float> ObjModel::ComputeNormal(vector<float> v1, vector<float> v2, vector<float> v3){
vector<float> vA, vB, vX;
float mag;

vA.push_back(v1[0] - v2[0]);
vA.push_back(v1[1] - v2[1]);
vA.push_back(v1[2] - v2[2]);

vB.push_back(v1[0] - v3[0]);
vB.push_back(v1[1] - v3[1]);
vB.push_back(v1[2] - v3[2]);

vX.push_back(vA[1] * vB[2] - vA[2] * vB[1]);
vX.push_back(vA[2] * vB[0] - vA[0] * vB[2]);
vX.push_back(vA[0] * vB[1] - vA[1] * vB[0]);

mag = sqrt(vX[0] * vX[0] + vX[1] * vX[1] + vX[2] * vX[2]);

for(int i = 0; i < 3; i++) vX[i] /= mag;

return vX;}

Я уже проверил, чтобы убедиться, что есть одинаковое количество нормальных векторов и граней (которые должны быть, если я прав).

Заранее спасибо! 🙂

редактировать Вот как я включаю / отключаю функции OpenGL:

glEnable(GL_DEPTH_TEST);
glDepthFunc(GL_LESS);
glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST);
GLfloat amb_light[] =  0.1, 0.1, 0.1, 1.0 ;
GLfloat diffuse[] = {0.6, 0.6, 0.6, 1};
GLfloat specular[] = {0.7, 0.7, 0.3, 1};
glLightModelfv(GL_LIGHT_MODEL_AMBIENT, amb_light);
glLightfv(GL_LIGHT0, GL_DIFFUSE, diffuse);
glLightfv(GL_LIGHT0, GL_SPECULAR, specular);
glEnable(GL_LIGHT0);
glEnable(GL_COLOR_MATERIAL);
glShadeModel(GL_SMOOTH);
glLightModeli(L_LIGHT_MODEL_TWO_SIDE, GL_FALSE);
glDepthFunc(GL_LEQUAL);
glEnable(GL_DEPTH_TEST);
glEnable(GL_LIGHTING);
glEnable(GL_LIGHT0);
glDisable(GL_CULL_FACE);

2

Решение

Вы используете элементы? Файлы Obj начинают считать с 1, а OpenGL начинает считать с 0. Просто вычтите 1 из каждого элемента, и вы получите правильный рендеринг.

1

Другие решения

Ориентация норм имеет значение. Похоже, что ориентация лица вашего объекта не соответствует, поэтому нормали соседних граней, с одинаковыми плоскостями, указывают в противоположных направлениях.

Если вы импортировали эту модель из файла модели, я советую вам не рассчитывать нормали в вашем коде — вы все равно не должны этого делать, так как художники могут вносить ручные корректировки в нормали для локально точной настройки освещения — но храните их в файл модели также. Все 3D моделисты имеют функцию, чтобы перевернуть нормали в общую ориентацию. Например, в Blender эта функция достигается с помощью горячей клавиши CTRL + N в режиме редактирования.

1

for(int i = 0; i < 3; i++) this->normals.push_back(point[i]);

Это обеспечивает только одну нормаль для каждого лица. Вам нужен один нормальный для каждого вершина.

0
По вопросам рекламы ammmcru@yandex.ru
Adblock
detector