Pregunta

Estoy haciendo algunas formas bastante básicas en OpenGL-ES basado en el código de muestra de Apple. Han utilizado una variedad de puntos, con una variedad de índices en la primera matriz y cada conjunto de tres índices crea un polígono. Eso es genial, puedo hacer las formas que quiero. Para sombrear las formas correctamente, creo que necesito calcular las normales para cada vértice en cada polígono. Al principio, las formas eran cuboidales, por lo que era muy fácil, pero ahora estoy haciendo (ligeramente) formas más avanzadas que quiero crear esas normales automáticamente. Parece bastante fácil si obtengo vectores para dos bordes de un polígono (todas las polyes son triángulos aquí) y uso su producto cruzado para cada vértice en ese polígono. Después de eso, uso el código como el siguiente para dibujar la forma.

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);

Lo que tengo problemas para entender es por qué tengo que hacer esto manualmente. Estoy seguro de que hay casos en los que quieres algo más que un vector perpendicular a la superficie, pero también estoy seguro de que este es el caso de uso más popular, entonces, ¿no debería haber una manera más fácil? ¿Me he perdido algo obvio? GlcalculateNormals () sería genial.

// y aquí hay un pase de respuesta en un glkvector3 [] que desea llenar con sus normales, otro con los vértices (cada tres se agrupan en polígonos) y luego el recuento de los vértices.

- (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;
    }
}
¿Fue útil?

Solución

Y nuevamente la respuesta es: OpenGL no es una biblioteca de administración de escenas ni una biblioteca de geometría, sino solo una API de dibujo Eso dibuja buenas imágenes en la pantalla. Para iluminar, necesita normales y le das las normales. Eso es todo. ¿Por qué debería calcular las normales si esto puede ser hecho por el usuario y no tiene nada que ver con el dibujo real?

A menudo no los calcula en tiempo de ejecución de todos modos, pero cargue desde un archivo. Y hay muchas formas de calcular las normales. ¿Quieres normales por cara o normales por vértice? ¿Necesita algún bordes duros específicos o algún parche suave específico? Si desea promediar a las normales para obtener el vértice normales, ¿cómo quiere promediar estos?

Y con el advenimiento de los sombreadores y la eliminación del atributo normal y los cálculos de iluminación construidos en versiones más nuevas de OpenGL, toda esta pregunta se vuelve obsoleta de todos modos, ya que puede iluminar cualquier forma que desee y no necesariamente necesita más necesariamente las normales tradicionales.

Por cierto, parece que en este momento está usando normales por cara, lo que significa que cada vértice de una cara tiene lo mismo normal. Esto crea un modelo muy facetado con bordes duros y tampoco funciona muy bien con índices. Si desea un modelo suave (no lo sé, tal vez realmente desee un aspecto facetado), debe promediar la cara normales de las caras adyacentes para que cada vértice calcule las normales por vértice. Ese en realidad sería el caso de uso más habitual y no las normales por cara.

Entonces puedes hacer algo como este pseudo-código:

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

para generar normales lisos por vértice. Incluso en código real, esto debería dar lugar a algo entre 10 y 20 líneas de código, lo que no es realmente complejo.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top