Перевернутые вычисленные нормали лица после iOS OpenGl ES .obj загрузка единичного куба - PullRequest
2 голосов
/ 04 августа 2011

Я пытаюсь экспортировать и загрузить модель из Maya в очень простую настройку iOS OpenGL ES.Для этого я написал ruby ​​obj parser, который в основном берет вершины и нормали и вычисляет их в заголовок C, который я просто включаю.Вывод простого триангулированного единичного куба имеет следующую структуру:

Vertex3D cubeVertices[] = {
   {{-0.500000f, -0.500000f, 0.500000f},{0.000000f, 0.000000f, 1.000000f},{0.5f, 0.5f, 0.5f, 1},{{0,1,2},{0,6,7},{0,7,1},{0,6,4},{0,4,2}},5},
   {{0.500000f, -0.500000f, 0.500000f},{0.000000f, 0.000000f, 1.000000f},{0.5f, 0.5f, 0.5f, 1},{{1,0,2},{1,2,3},{1,0,7},{1,7,3}},4},
   {{-0.500000f, 0.500000f, 0.500000f},{0.000000f, 0.000000f, 1.000000f},{0.5f, 0.5f, 0.5f, 1},{{2,0,1},{2,1,3},{2,3,4},{2,4,0}},4},
   {{0.500000f, 0.500000f, 0.500000f},{0.000000f, 0.000000f, 1.000000f},{0.5f, 0.5f, 0.5f, 1},{{3,2,1},{3,2,4},{3,4,5},{3,1,7},{3,7,5}},5},
   {{-0.500000f, 0.500000f, -0.500000f},{0.000000f, 1.000000f, 0.000000f},{0.5f, 0.5f, 0.5f, 1},{{4,2,3},{4,3,5},{4,5,6},{4,6,0},{4,0,2}},5},
   {{0.500000f, 0.500000f, -0.500000f},{0.000000f, 1.000000f, 0.000000f},{0.5f, 0.5f, 0.5f, 1},{{5,4,3},{5,4,6},{5,6,7},{5,3,7}},4},
   {{-0.500000f, -0.500000f, -0.500000f},{0.000000f, 1.000000f, 0.000000f},{0.5f, 0.5f, 0.5f, 1},{{6,4,5},{6,5,7},{6,7,0},{6,0,4}},4},
   {{0.500000f, -0.500000f, -0.500000f},{0.000000f, 1.000000f, 0.000000f},{0.5f, 0.5f, 0.5f, 1},{{7,6,5},{7,6,0},{7,0,1},{7,1,3},{7,3,5}},5}
};

GLubyte cubeFaceIndices[] = {
   0, 1, 2,
   2, 1, 3,
   2, 3, 4,
   4, 3, 5,
   4, 5, 6,
   6, 5, 7,
   6, 7, 0,
   0, 7, 1,
   1, 7, 3,
   3, 7, 5,
   6, 0, 4,
   4, 0, 2
};

Определение для Vertex3D:

struct Vertex3D {
   vec3 position;
   vec3 normal;
   vec4 color;
   Index3D connected_faces[100];
   int connectedFaceCount;
};
typedef struct Vertex3D Vertex3D;

Теперь мне нужно пересчитать нормали вершин, потому что я хочу анимироватьдвижение некоторых вершин.Для этого я просто добавил все индексы связанных вершин в каждую вершину, для этого предназначен индексный массив connected_faces.

Для вычисления я просто вычисляю все нормали граней с перекрестным произведением.Для этого мне нужно всего лишь использовать 3 вершины, хранящиеся в Index3D, загрузить позиции, вычесть первую вершину, чтобы у меня были векторы и вычислить перекрестное произведение.Затем я складываю все перекрестные произведения, которые принадлежат этой вершине, и нормализую вектор, это моя последняя нормальная вершина.

Проблема, с которой я сталкиваюсь, заключается в том, что бывает, что 2 грани, которые будут иметь одинаковыеНормальная грань, например, у триангулированного куба всегда есть 2 треугольника, которые разделяют четырехугольник, и имеют эту нормальную грань в противоположном направлении.Если я добавлю их, чтобы вычислить позже, конечно, их сумма будет нулевым вектором.Я знаю, что это происходит потому, что в некоторых случаях 2 вершины не имеют правильного порядка, это означает, что A следует заменить на B, но я не знаю, какую из них мне нужно перевернуть.

Есть лиматематический способ оценить, в каком направлении идет нормаль, и вычисляю ли я AxB или BxA?Я дважды проверил нормали в Maya, они там просто идеальны.

РЕДАКТИРОВАТЬ: Я заказал соединенные грани сейчас, что прекрасно работает.Я вычисляю нормали следующим образом:

// every vertex
GLsizei vertexCount = sizeof(cubeVertices) / sizeof(Vertex3D);
for (int i = 0; i < vertexCount; i++) {
    vec3 newNormal = {0.0f, 0.0f, 0.0f};

    // every vertex connected to the current vertex
    GLsizei faceCount = cubeVertices[i].connectedFaceCount;
    for(int j = 0; j < faceCount; j++){

        Index3D index = cubeVertices[i].connected_faces[j];

        vec3 vectorA = cubeVertices[index.a].position;
        vec3 vectorB = cubeVertices[index.b].position;
        vec3 vectorC = cubeVertices[index.c].position;
        vec3 vectorNormal = {0.0f, 0.0f, 0.0f};

        substractVectors(&vectorB, &vectorA);
        substractVectors(&vectorC, &vectorA);

        makeNormal(&vectorB, &vectorC, &vectorNormal);
        addVectors(&newNormal, &vectorNormal);
    }

    // set normal for current vertex
    normalize(&newNormal);
    cubeVertices[i].normal = newNormal;
}

Но теперь у меня проблема в том, что из-за триангуляции у меня иногда есть 2 нормали, указывающие в одном и том же направлении, что не приводит к моему ожидаемому {0.33f, 0.33f, 0.33f} нормали вершин.Это правильное поведение, или есть какой-то другой способ рассчитать это?

Большое спасибо за вашу помощь!

1 Ответ

1 голос
/ 05 августа 2011

Это зависит от порядка вершин граней.Если они упорядочены против часовой стрелки (если смотреть снаружи на лицо), то вы вычисляете нормаль лица как AxB, с A = (v1-v0) и B = (v2-v0), если упорядочить по часовой стрелке, вы должны переключить A и B.

Но если вы делаете это последовательно для каждого лица, это должно работать.В противном случае грани в кубе не ориентированы последовательно, может быть, кто-то (экспортер?) Испортил ориентацию при преобразовании четырехугольников в треугольники или что-то в этом роде.

И, кстати, вы можете вычислить их без *Массива 1008 *, просто пройдя один раз массив грани / индекса, вычислив нормаль грани для каждой грани и добавив ее в нормали соответствующих трех вершин, после чего следует один обход массива вершин для нормализации нормали.

РЕДАКТИРОВАТЬ: Вы можете попытаться отрендерить их в OpenGL с отбраковкой либо передних граней, либо задних граней (используя glCullFace(GL_BACK) и glEnable(GL_CULL_FACE)).Если некоторые треугольники внутри (или снаружи, в зависимости от режима отбраковки) выделены, а некоторые нет, то треугольники не ориентированы согласованно и данные куба нарушены.

РЕДАКТИРОВАТЬ: Из вашего обновленного вопроса я предполагаю, что по крайней мере у вас больше нет 0-нормалей.Код также выглядит хорошо.Тот факт, что не каждая нормаль имеет три одинаковые координаты (кстати, это не 0,33, а 1 / sqrt (3), но я знаю, что вы имеете в виду), естественен для куба, построенного из треугольников.В крайних случаях вы можете получить вершины, связанные с 6 или только 3 треугольниками.Во всех других случаях (и это должно произойти) вы не получите идеальный угол в норме.

Это связано с триангуляцией куба.Вы больше не видите куб (построенный из 6 граней и 8 вершин, соединенных ровно с 3 гранями каждая), но треугольная сетка с вершинами, соединенными с любым числом от 3 до 6 треугольников.Ваша логика программы не знает, что некоторые из треугольников принадлежат друг другу и образуют четырехугольник.Это также общая проблема с общими сетками.Например, выполнение любого алгоритма деления на четырехугольной сетке (построенной из четырехугольников) приводит к другой геометрии, чем выполнение того же подразделения для триангуляции этой сетки (с двумя треугольниками для каждого четырехугольника).

Если вам действительно нужночтобы работать с квадраторами, вам нужен более высокий уровень абстракции для представления четырехугольного слоя (возможно, другая структура данных сверху или просто специальное упорядочение треугольников, например, каждая последующая пара трис образует квад).В противном случае вы также можете полностью работать с квадраторами, так как OpenGL может визуализировать квады напрямую (хотя я не уверен, что недекларированный GL или, по крайней мере, ES прекратил поддержку квадов).

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

...