Representación 3D: normales de cara y normales de vértice

Ahora que hemos revisado los parámetros que afectan la apariencia de los objetos (su brillo, color, etc.), estamos listos para comenzar a analizar algunas técnicas simples de sombreado.

inserte la descripción de la imagen aquí

Recomendación: utilice el editor NSDT para crear rápidamente escenas 3D programables

1. normales

Los normales juegan un papel central en el sombreado. Todos sabemos que si apuntamos un objeto hacia una fuente de luz, se volverá más brillante. La orientación de la superficie de un objeto juega un papel importante en la cantidad de luz que refleja (y en lo brillante que parece ser). Esta dirección en cualquier punto P de la superficie del objeto se puede expresar mediante la normal N perpendicular a la superficie, como se muestra en la Figura 1.
inserte la descripción de la imagen aquí

Figura 1: Observe cómo la esfera se oscurece a medida que aumenta el ángulo entre la dirección normal y la dirección de la luz.

Observe en la Figura 1 cómo el brillo de la esfera disminuye a medida que aumenta el ángulo entre la dirección de la luz y la dirección normal. Esta caída en el brillo es un fenómeno que vemos todos los días, pero probablemente pocas personas sepan por qué sucede. Explicaremos el por qué de este fenómeno más adelante. Por ahora solo recuerda:

  • Lo que llamamos normal (que denotamos con N mayúscula) es un vector perpendicular a la tangente a la superficie en el punto P. En otras palabras, para encontrar la normal en el punto P, necesitamos trazar una línea tangente a la superficie y luego tomar el vector perpendicular a esa tangente (tenga en cuenta que en 3D este sería el plano tangente).
  • El brillo de un punto en la superficie de un objeto depende de la dirección normal, que define la dirección de la superficie del objeto en ese punto con respecto a la luz. Otra forma de decir esto es que el brillo de cualquier punto dado en la superficie de un objeto depende del ángulo entre la normal a ese punto y la dirección de la luz.

Ahora la pregunta es ¿cómo calculamos esta normalidad? La complejidad de la solución a este problema puede variar mucho según el tipo de geometría que se representa. La normal de una esfera suele ser fácil de encontrar. Si conocemos la posición y el centro de un punto en la superficie de una esfera, podemos calcular la normal a ese punto restando la posición del punto del centro:

Vec3f N = P - sphereCenter;

Si el objeto es una malla de triángulos, cada triángulo define un plano, y un vector perpendicular a ese plano es la normal a cualquier punto que se encuentre sobre la superficie de ese triángulo. El vector perpendicular al plano del triángulo se puede obtener fácilmente mediante el producto cruz de los dos lados del triángulo. Recuerde v1xv2 = -v2xv1. Entonces la elección del borde afectará la dirección de la normal. Si declara los vértices del triángulo en orden antihorario, puede utilizar el siguiente código:

Vec3f N = (v1-v0).crossProduct(v2-v0);

inserte la descripción de la imagen aquí

Figura 2: La cara normal de un triángulo se puede calcular tomando el producto cruzado de los dos lados del triángulo.
Si el triángulo está en el plano xz, la normal resultante debería ser (0,1,0) en lugar de (0,-1,0), como se muestra en la Figura 2.

Calcular la normal de esta manera nos da lo que llamamos una cara normal (ya que la normal es la misma para toda la cara, sin importar qué punto elijas en esa cara o triángulo). Las normales de una malla de triángulos también se pueden definir en los vértices de los triángulos, en cuyo caso nos referimos a estas normales como normales de vértice. Las normales de vértice se utilizan en una técnica llamada sombreado suave, cuya descripción encontrará al final de este capítulo. Actualmente, sólo tratamos con caras normales.

No importa cómo y cuándo se calculan en el programa las normales de superficie en los puntos a sombrear. Es importante e importante tener esta información a la mano cuando vayas a colorear esto. En esta sección donde hacemos algo de sombreado básico, implementamos un método especial llamado getSurfaceProperties() en cada clase de geometría donde calculamos la normal en el punto de intersección (si usamos trazado de rayos) y otras variables como las coordenadas de textura que discutiremos más adelante en Esta lección. Para los tipos de geometría de malla de esfera y triángulo, la implementación de estos métodos es la siguiente:

class Sphere : public Object 
{ 
    ... 
public: 
    ... 
    void getSurfaceProperties( 
        const Vec3f &hitPoint, 
        const Vec3f &viewDirection, 
        const uint32_t &triIndex, 
        const Vec2f &uv, 
        Vec3f &hitNormal, 
        Vec2f &hitTextureCoordinates) const 
    { 
        hitNormal= Phit - center; 
        hitNormal.normalize(); 
        ... 
    } 
    ... 
}; 
 
class TriangleMesh : public Object 
{ 
    ... 
public: 
    void getSurfaceProperties( 
        const Vec3f &hitPoint, 
        const Vec3f &viewDirection, 
        const uint32_t &triIndex, 
        const Vec2f &uv, 
        Vec3f &hitNormal, 
        Vec2f &hitTextureCoordinates) const 
    { 
        // face normal
        const Vec3f &v0 = P[trisIndex[triIndex * 3]]; 
        const Vec3f &v1 = P[trisIndex[triIndex * 3 + 1]]; 
        const Vec3f &v2 = P[trisIndex[triIndex * 3 + 2]]; 
        hitNormal = (v1 - v0).crossProduct(v2 - v0); 
        hitNormal.normalize(); 
        ... 
    } 
    ... 
}; 

2. Efecto colorante simple: relación de superficie

Ahora que sabemos cómo calcular la normal de un punto en la superficie de un objeto, tenemos suficiente información para crear un efecto de sombreado simple llamado relación de encaramiento. La técnica consiste en calcular el producto escalar de la normal del punto que queremos sombrear y la dirección de visión. Calcular la dirección de visión también es muy sencillo. Cuando se utiliza el trazado de rayos, es justo la dirección opuesta al rayo en P, donde cruza la superficie. Sin utilizar el trazado de rayos, la dirección de visión también se puede encontrar simplemente trazando una línea desde el punto P en la superficie hasta el ojo:

Vec3f V = (E - P).normalize(); // or -ray.dir if you use ray-tracing

Recuerde que el producto escalar de dos vectores devuelve 1 si son paralelos y apuntan en la misma dirección, y 0 si los dos vectores son perpendiculares entre sí. Si los vectores apuntan en la dirección opuesta, el producto escalar es negativo, pero si usamos el resultado de ese producto escalar como color, entonces no nos interesan los valores negativos de todos modos. Si necesita una introducción a los productos escalares, consulte el curso de geometría. Para evitar resultados negativos, debemos limitar los resultados a 0:

float facingRatio = std::max(0, N.dotProduct(V));

inserte la descripción de la imagen aquí

El producto escalar devuelve 1 cuando la normal y el vector V apuntan en la misma dirección. El resultado es 0 si los dos vectores son perpendiculares. Si utilizamos esta sencilla técnica para sombrear una esfera en el medio del marco, el centro de la esfera será blanco y, a medida que nos alejemos de su centro hacia los bordes, la esfera se volverá más oscura, como se muestra a continuación.
inserte la descripción de la imagen aquí

Vec3f castRay( 
    const Vec3f &orig, const Vec3f &dir, 
    const std::vector<std::unique_ptr<Object>> &objects, 
    const Options &options) 
{ 
    Vec3f hitColor = options.backgroundColor; 
    float tnear = kInfinity; 
    Vec2f uv; 
    uint32_t index = 0; 
    Object *hitObject = nullptr; 
    if (trace(orig, dir, objects, tnear, index, uv, &hitObject)) { 
        Vec3f hitPoint = orig + dir * tnear;  //shaded point 
        Vec3f hitNormal; 
        Vec2f hitTexCoordinates; 
        // compute the normal of the point we want to shade
        hitObject->getSurfaceProperties(hitPoint, dir, index, uv, hitNormal, ...); 
        hitColor = std::max(0.f, hitNormal.dotProduct(-dir));  //facing ratio 
    } 
 
    return hitColor; 
} 

¡Felicidades! Acabas de aprender sobre tu primera técnica de sombreado. Veamos ahora un enfoque más realista del sombreado que simulará el efecto de la luz sobre objetos difusos. Pero antes de comprender este método, primero debemos presentar y comprender el concepto de luz.

3. Sombreado plano, sombreado suave y normales de vértice

El problema de las mallas triangulares es que no pueden representar superficies perfectamente lisas (a menos que los triángulos sean muy pequeños). Si deseamos aplicar la técnica de relación de aspecto que acabamos de describir a una malla poligonal, necesitamos calcular la normal del triángulo intersectado por el rayo y calcular la relación de aspecto como el producto escalar entre la normal de la cara y la dirección de la vista. El problema con este enfoque es que le da al objeto una apariencia facetada, como se muestra en la imagen siguiente. Por eso este método de sombreado se llama sombreado plano.
inserte la descripción de la imagen aquí

Como se mencionó muchas veces en lecciones anteriores, la normal a un triángulo se puede encontrar simplemente calculando el producto cruzado de los vectores v0v1 y v0v2, donde v0, v1 y v2 representan los vértices del triángulo. Para resolver este problema, Henri Gouraud introdujo un método en 1971, ahora llamado sombreado suave o sombreado de Gouraud.

La idea detrás de esta técnica es producir sombras continuas en la superficie de una malla poligonal, incluso si el objeto representado por la malla no es continuo porque está construido a partir de una colección de superficies planas (polígonos o triángulos). Con este fin, Gouraud introdujo el concepto de normales de vértice. La idea es sencilla. En lugar de calcular o almacenar normales para caras, almacenamos normales en cada vértice de la malla, donde la dirección de la normal está determinada por la superficie lisa subyacente desde la que se convirtió la malla triangular. Cuando queremos calcular el color de un punto en la superficie de un triángulo, podemos calcular normales "falsas suaves" interpolando linealmente las normales de los vértices definidas en los vértices del triángulo usando las coordenadas baricéntricas del punto de impacto, en lugar de usar las normales de la cara.
inserte la descripción de la imagen aquí

La técnica se muestra en el diagrama de arriba. Las normales a los vértices se definen en los vértices del triángulo. Puede ver que están orientados perpendicularmente a la superficie lisa subyacente sobre la que está construida la malla triangular. A veces, las mallas triangulares no se convierten directamente a partir de superficies lisas y las normales de los vértices deben calcularse sobre la marcha. Existen diferentes técnicas para calcular las normales de los vértices cuando no hay una superficie lisa para calcular las normales de los vértices, pero no las veremos en esta lección. Ahora, usa software como Maya o Blender para hacer esto por ti, en Maya puedes seleccionar la malla poligonal y elegir la opción Suavizar bordes en el menú Normales.

De hecho, desde un punto de vista práctico y técnico, cada triángulo tiene su propio conjunto de 3 vértices normales. Esto significa que el número total de normales de vértice para una malla de triángulos es igual al número de triángulos multiplicado por 3. En algunos casos, las normales de vértice definidas en vértices compartidos por 2, 3 o más triángulos son las mismas (apuntan en la misma dirección), pero puedes lograr diferentes direcciones dándoles diferentes efectos de dirección. Por ejemplo, algunos bordes duros pueden falsificarse en la superficie.

El código fuente para calcular la normal interpolada de cualquier punto de la superficie del triángulo es muy sencillo, siempre que conozcamos la normal al vértice del triángulo, las coordenadas baricéntricas del punto del triángulo y el índice del triángulo. Tanto la rasterización como el trazado de rayos pueden brindarle esta información. Las normales de vértice se generan en el modelo mediante el programa 3D que utilizó para crear el modelo. Luego se exportan a archivos de geometría, que contienen la información de conexión de los triángulos, las posiciones de los vértices y las coordenadas de textura de los triángulos. Luego, todo lo que necesita hacer es combinar las coordenadas baricéntricas del punto y las normales del vértice del triángulo para calcular las normales suaves interpoladas del punto (líneas 17 a 20 a continuación):

void getSurfaceProperties( 
    const Vec3f &hitPoint, 
    const Vec3f &viewDirection, 
    const uint32_t &triIndex, 
    const Vec2f &uv, 
    Vec3f &hitNormal, 
    Vec2f &hitTextureCoordinates) const 
{ 
    // face normal
    const Vec3f &v0 = P[trisIndex[triIndex * 3]]; 
    const Vec3f &v1 = P[trisIndex[triIndex * 3 + 1]]; 
    const Vec3f &v2 = P[trisIndex[triIndex * 3 + 2]]; 
    hitNormal = (v1 - v0).crossProduct(v2 - v0); 
 
#if 1 
    // compute "smooth" normal using Gouraud's technique (interpolate vertex normals)
    const Vec3f &n0 = N[trisIndex[triIndex * 3]]; 
    const Vec3f &n1 = N[trisIndex[triIndex * 3 + 1]]; 
    const Vec3f &n2 = N[trisIndex[triIndex * 3 + 2]]; 
    hitNormal = (1 - uv.x - uv.y) * n0 + uv.x * n1 + uv.y * n2; 
#endif 
 
    // doesn't need to be normalized as the N's are normalized but just for safety
    hitNormal.normalize(); 
 
    // texture coordinates
    const Vec2f &st0 = texCoordinates[trisIndex[triIndex * 3]]; 
    const Vec2f &st1 = texCoordinates[trisIndex[triIndex * 3 + 1]]; 
    const Vec2f &st2 = texCoordinates[trisIndex[triIndex * 3 + 2]]; 
    hitTextureCoordinates = (1 - uv.x - uv.y) * st0 + uv.x * st1 + uv.y * st2; 
} 

Tenga en cuenta que esto sólo dará la impresión de una superficie lisa. Si observas la esfera poligonal en la imagen de abajo, aún puedes ver que el contorno está facetado, aunque las superficies internas parecen ser lisas. Esta técnica mejora la apariencia de las mallas triangulares, pero por supuesto no resuelve por completo el problema de su apariencia facetada. La única solución a este problema es usar superficies de subdivisión (que discutiremos en una sección diferente) o, por supuesto, aumentar la cantidad de triángulos usados ​​al convertir una superficie lisa en una malla triangular.

inserte la descripción de la imagen aquí

No estamos preparados para aprender a reproducir el aspecto de una superficie difusa. Aunque las superficies difusas requieren que la luz sea visible. Entonces, antes de analizar esta técnica, primero debemos comprender cómo abordar el concepto de fuentes de luz en un motor 3D.


Enlace original: Superficie normal y vértice normal - BimAnt

Supongo que te gusta

Origin blog.csdn.net/shebao3333/article/details/132690273
Recomendado
Clasificación