Перевернутые вычисленные нормали граней после загрузки iOS OpenGl ES .obj единичного куба

Я пытаюсь экспортировать и загрузить модель из Maya в очень простую установку iOS OpenGL ES. Для этого я написал анализатор объектов ruby, который в основном берет вершины и нормали и вычисляет их в заголовке 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 треугольника, которые разделяют четырехугольник, и эта грань нормальна в противоположном направлении. Если я добавлю их, чтобы вычислить позже, их сумма, конечно, будет нулевым вектором. Я знаю, что это происходит потому, что в некоторых случаях две вершины имеют неправильный порядок, это означает, что 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}. Это правильное поведение или есть другой способ рассчитать это?

Спасибо большое за помощь!


person Thomas Fankhauser    schedule 04.08.2011    source источник
comment
Возможно, публикация обычного вычислительного кода поможет решить вашу проблему.   -  person Christian Rau    schedule 11.08.2011
comment
Я добавил обычный расчет, но у меня остались небольшие проблемы. Спасибо за ваш второй совет, чтобы сделать все вычисления за 2 поездки туда и обратно, я собираюсь попробовать это дальше.   -  person Thomas Fankhauser    schedule 12.08.2011
comment
Хорошо, обновил свой ответ. Кстати, на самом деле это три обхода, так как вам, конечно, нужно инициализировать нормали вершин равными нулю (но простота все равно того стоит).   -  person Christian Rau    schedule 12.08.2011


Ответы (1)


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

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

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

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

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

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

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

РЕДАКТИРОВАТЬ: В вашем случае вы можете просто заказать его, чтобы каждые два треугольника образовывали четырехугольник. Затем при обычном вычислении вы всегда обрабатываете два треугольника, вычисляете нормаль одного из них, а затем обновляете нормали вершин только четырех различных вершин.

person Christian Rau    schedule 04.08.2011
comment
Хорошо, большое спасибо за уделенное время. Теперь я понял суть несовершенного куба посредством триангуляции, просто хотел убедиться, что я на правильном пути. OpenGL ES поддерживает только треугольники a.f.a.i.k, поэтому я не могу идти четвертым путем. Сейчас я выполняю расчет трех обходов, как вы и предполагали, и поскольку моя целевая сетка носит более органичный характер, нормали, вероятно, будут работать довольно хорошо. - person Thomas Fankhauser; 15.08.2011