Автоматически вычислять нормали в GLKit / OpenGL-ES - PullRequest
4 голосов
/ 05 декабря 2011

Я делаю несколько довольно простых фигур в OpenGL-ES на основе примера кода от Apple. Они использовали массив точек, с массивом индексов в первом массиве, и каждый набор из трех индексов создает многоугольник. Это все замечательно, я могу делать формы, которые я хочу. Чтобы правильно затенить фигуры, я считаю, что мне нужно вычислить нормали для каждой вершины каждого многоугольника. Сначала формы были кубовидными, поэтому это было очень легко, но теперь я делаю (немного) более сложные формы, я хочу автоматически создавать эти нормали. Это кажется достаточно простым, если я получу векторы для двух ребер многоугольника (здесь все многоугольники являются треугольниками) и использую их перекрестное произведение для каждой вершины этого многоугольника. После этого я использую код, как показано ниже, чтобы нарисовать форму.

glEnableVertexAttribArray(GLKVertexAttribPosition);
glVertexAttribPointer(GLKVertexAttribPosition, 3, GL_FLOAT, GL_FALSE, 0, triangleVertices);

glEnableVertexAttribArray(GLKVertexAttribColor);
glVertexAttribPointer(GLKVertexAttribColor, 4, GL_FLOAT, GL_FALSE, 0, triangleColours);

glEnableVertexAttribArray(GLKVertexAttribNormal);
glVertexAttribPointer(GLKVertexAttribNormal, 3, GL_FLOAT, GL_FALSE, 0, triangleNormals);

glDrawArrays(GL_TRIANGLES, 0, 48);

glDisableVertexAttribArray(GLKVertexAttribPosition);
glDisableVertexAttribArray(GLKVertexAttribColor);
glDisableVertexAttribArray(GLKVertexAttribNormal);

Мне трудно понять, почему я должен делать это вручную. Я уверен, что бывают случаи, когда вам нужно что-то другое, чем просто вектор, перпендикулярный поверхности, но я также уверен, что это самый популярный вариант использования на сегодняшний день, разве не должно быть более простого способа? Я что-то упустил очевидное? glCalculateNormals () было бы здорово.

// А вот и ответ Передайте GLKVector3 [], который вы хотите заполнить своими нормалями, другой вершинами (все три сгруппированы в многоугольники) и затем количество вершин.

- (void) calculateSurfaceNormals: (GLKVector3 *) normals forVertices: (GLKVector3 *)incomingVertices count:(int) numOfVertices
{

    for(int i = 0; i < numOfVertices; i+=3)
    {
        GLKVector3 vector1 = GLKVector3Subtract(incomingVertices[i+1],incomingVertices[i]);
        GLKVector3 vector2 = GLKVector3Subtract(incomingVertices[i+2],incomingVertices[i]);        
        GLKVector3 normal = GLKVector3Normalize(GLKVector3CrossProduct(vector1, vector2));
        normals[i] = normal;
        normals[i+1] = normal;
        normals[i+2] = normal;
    }
}

1 Ответ

3 голосов
/ 05 декабря 2011

И снова ответ: OpenGL не является ни библиотекой управления сценами, ни библиотекой геометрии, а просто API рисования , который рисует красивые картинки на экране. Для освещения нужны нормалы, а вы даете нормалы. Это все. Зачем ему вычислять нормали, если это может сделать только пользователь и не имеет ничего общего с фактическим рисунком?

Часто вы все равно не вычисляете их во время выполнения, а загружаете их из файла. И есть много способов вычислить нормали. Вы хотите индивидуальные нормали или нормали вершин? Вам нужны какие-то особые твердые края или какие-то особые гладкие пятна? Если вы хотите усреднить нормали лица, чтобы получить нормали вершин, как вы хотите их усреднить?

А с появлением шейдеров и удалением встроенных нормальных атрибутов и вычислений освещения в новых версиях OpenGL весь этот вопрос в любом случае устареет, поскольку вы можете делать освещение любым способом и больше не нуждаетесь в традиционных нормалях.

Кстати, это звучит так, как будто в данный момент вы используете индивидуальные нормали, что означает, что каждая вершина грани имеет одну и ту же нормаль. Это создает очень граненую модель с жесткими краями, а также не очень хорошо работает с индексами. Если вам нужна гладкая модель (я не знаю, может, вам действительно нужен граненый вид), вы должны усреднить нормали граней смежных граней для каждой вершины, чтобы вычислить нормали для каждой вершины. Это на самом деле более обычный вариант использования, а не индивидуальные нормы.

Таким образом, вы можете сделать что-то вроде этого псевдокода:

for each vertex normal:
    intialize to zero vector

for each face:
    compute face normal using cross product
    add face normal to each vertex normal of this face

for each vertex normal:
    normalize

для генерации гладких нормалей для каждой вершины. Даже в реальном коде это должно привести к примерно 10-20 строкам кода, что не очень сложно.

...