6.5.2  Primitivas de Parche Finitas

Hay seis de ellas totalmente aceptables, objetos finitos que no possen un interior bien definido. Éstas son:  bicubic patch (parche bicúbico), disc (disco), smooth triangle (triángulo suavizado), triangle (triángulo), polygon (polígono) y mesh / mesh2 (malla, de dos tipos). Todos se pueden combinar en la unión CSG pero no pueden usarse en otros tipos de CSG (o en el interior de una declaración clipped_by ). A causa de ello, POV- Ray puede usar la acotación automática sobre estos objetos para aumentar la velocidad en el tiempo de trazado. Como con todas las demás figuras, éstas pueden ser trasladadas, rotadas y escaladas.

6.5.2.1  Parches Bicúbicos

Un bicubic_patch (parche bicúbico) es una superficie curvada 3D creada a partir de mallas de triángulos. POV-Ray soporta un tipo de parche bicúbico llamado parche de Bezier. Un parche bicúbico se define de la siguiente manera:

BICUBIC_PATCH:
    bicubic_patch
    {
        PATCH_ITEMS...
        <Point_1>,<Point_2>,<Point_3>,<Point_4>,
        <Point_5>,<Point_6>,<Point_7>,<Point_8>,
        <Point_9>,<Point_10>,<Point_11>,<Point_12>,
        <Point_13>,<Point_14>,<Point_15>,<Point_16>
        [OBJECT_MODIFIERS...]
    }
PATCH_ITEMS:
    type Patch_Type | u_steps Num_U_Steps | v_steps Num_V_Steps |
    flatness Flatness
Los valores por defecto en un parche bicúbico son:
flatness : 0.0
u_steps  : 0
v_steps  : 0

La sentencia type va seguida de un valor en coma flotante Patch_Type el cual actualmente debe de ser 0 o 1. Si usamos el tipo 0, POV-Ray únicamente retiene los puntos de control. Esto significa que únicamente será necesaria una mínima cantidad de memoria pero por contra, POV-Ray necesitará realizar una gran cantidad de cálculos cuando analice un parche para trazarlo. El tipo 1 preprocesará el parche en muchos sub-parches. Esto se traducirá en un significativo aumento de la velocidad de trazado a cambio de usar más memoria.

Los cuatro parámetros type, flatness, u_steps y v_steps se pueden colocar en cualquier orden. El único que es necesario es type. Éstos van a continuación de 16 vectores (4 filas de 4) que definen las coordenadas x, y, z  de los 16 puntos de control los cuales formarán el parche. El parche toca los cuatro puntos de la esquina <Point_1>, <Point_4>, <Point_13> y <Point_16> mientras que los otros 12 puntos estiran y encogen el parche hacia el interior de la figura. La superficie de Bezier es acotada por un casco convexo formado por 16 puntos de control, lo cual es conocido como la propiedad del casco convexo.

Las palabras claves u_steps y v_steps van cada una seguidas de un valor entero que indica cuántas filas y columnas de triángulos son las mínimas a usar para formar la superficie, ambas por defecto son 0. El máximo número de piezas individuales del parche que se comprueban en POV-Ray se puede calcular con la siguiente fórmula: piezas = 2^u_steps * 2^v_steps.

Esto significa que realmente podríamos mantener u_steps y v_steps por debajo de 4. La mayoría de los parches tienen una apariencia aceptable con u_steps 3 y v_steps 3, lo cual se traduce en 64 subparches (128 triángulos suaves).

Tal como POV-Ray va procesando los parches de Bezier, hace un test de la pieza actual para comprobar si ésta es lo bastante plana como para simular un rectángulo. El parámetro que controla este test se especifica con la palabra clave flatness seguida de un valor en coma flotante. Los valores típicos de aplanamiento varían en un rango comprendido entre 0 y 1 (cuanto más pequeño más lento). El valor por defecto si no se especifica ninguno es 0.0.

Si el valor de flatness es 0 POV-Ray siempre subdividirá el parche según los valores especificados por u_steps y v_steps. Si el valor de flatness es mayor que 0 entonces, cada vez que el parche es dividido, POV-Ray lo chequeará para ver si hay alguna necesidad de efectuar la división.

Hay ventajas y desventajas en el uso de valores distintos de cero para flatness. Las ventajas incluyen:

- Si el parche no es muy curvado, POV-Ray lo detectará y no derrochará más tiempo mirando las piezas erróneas.

- Si el parche está sumamente curvado en un par de zonas solamente, POV-Ray mantendrá la subdivisión allí y concentrará sus esfuerzos sobre la parte plana.

La mayor desventaja está en que si POV-Ray detiene la subdivisión en un nivel particular sobre una parte del parche y en un nivel diferente sobre una parte adyacente del parche, puede aparecer en potencia una "grieta". Esto es típicamente perceptible como un lugar dentro del parche donde podemos ver a través de él. La aparición de este mal depende en gran medida del ángulo desde el que estamos viendo el parche.

Al igual que los triángulos, el parche bicúbico no está pensado para generarlo a mano. Estas formas deben ser creadas con una utilidad especial. Puedes encontrar normalmente estas utilidades en el mismo sitio donde has obtenido POV-Ray.

Aquí tenemos un ejemplo de parche bicúbico:

  bicubic_patch {
    type 0
    flatness 0.01
    u_steps 4
    v_steps 4
    <0, 0, 2>, <1, 0, 0>, <2, 0, 0>, <3, 0,-2>,
    <0, 1  0>, <1, 1, 0>, <2, 1, 0>, <3, 1, 0>,
    <0, 2, 0>, <1, 2, 0>, <2, 2, 0>, <3, 2, 0>,
    <0, 3, 2>, <1, 3, 0>, <2, 3, 0>, <3, 3, -2>
  }
Los triángulos en un bicubic_patch de POV-Ray son automáticamente suavizados usando la interpolación normal, pero es trabajo del usuario (o de las utilidades del usuario) el crear puntos de control que se unan suavemente para crear la superficie.

6.5.2.2  Disc (Disco)

Otro objeto plano finito disponible con POV-Ray es el disc (disco). El disco es infinitamente fino, no tiene grosor. Si queremos un disco con cierto grosor deberíamos usar un cilindro con poca altura. Una figura disco puede ser definida por::
DISC:
    disc
    {
        <Center>, <Normal>, Radius [, Hole_Radius]
        [OBJECT_MODIFIERS...]
    }
Los valores por defecto son:
HOLE RADIUS : 0.0
El vector <Center>  define las coordenadas x, y, z del centro del disco. El vector <Normal> indica su orientación describiendo su vector perpendicular a la superficie. Éste va seguido por un valor en coma flotante que especifica el radio (Radius) del disco. Este valor puede estar seguido opcionalmente por otro valor en coma flotante especificando el radio del agujero que se recorta del centro del disco.

Nota: El interior del disco está dentro del plano que contiene al disco. Observa también que éste no está forzado por el radio del disco.

6.5.2.3  Mesh (Malla)

El objeto mesh (malla) se puede usar eficazmente para almacenar un gran número de triángulos. Su sintaxis es:
MESH:
    mesh
    {
        MESH_TRIANGLE...
        [MESH_MODIFIER...]
    }
MESH_TRIANGLE:
    triangle
    {
        <Corner_1>, <Corner_2>, <Corner_3>
        [uv_vectors <uv_Corner_1>, <uv_Corner_2>, <uv_Corner_3>]
        [MESH_TEXTURE]
    } |
    smooth_triangle
    {
        <Corner_1>, <Normal_1>,
        <Corner_2>, <Normal_2>,
        <Corner_3>, <Normal_3>
        [uv_vectors <uv_Corner_1>, <uv_Corner_2>, <uv_Corner_3>]
        [MESH_TEXTURE]
    }
MESH_TEXTURE:
    texture { TEXTURE_IDENTIFIER }
MESH_MODIFIER:
    inside_vector <direction> | hierarchy [ Boolean ] |
    OBJECT_MODIFIER
Los valores por defecto son:
hierarchy : on
Puede usarse cualquier número de declaraciones triangle (triángulos) y/o smooth_triangle (triángulos suavizados), y cada uno de esos triángulos puede texturizarse individualmente, asignándo a cada uno de ellos un identificador de textura. La textura ha de ser declarada antes de que la malla sea analizada. No es posible usar definiciones de textura en el interior de las declaraciones del triángulo o del triángulo suavizado. Ésta es una restricción necesaria para un almacenamiento eficiente de las texturas asignadas. Ver "Triángulos y Triángulos Suavizados" para más información.

El objeto mesh (malla) puede soportar uv_mapping. Para ello, se tiene que añadir la palabra clave uv_vectors, conjuntamente con tres uv-vectores de dos dimensiones. Cada vector especifica una localización en el plano XY desde la cual la textura ha de ser mapeada para que se corresponda con los puntos del triángulo. Ver también el capítulo uv_mapping.

Los componentes de la malla son acotados internamente por una caja, para aumentar la velocidad de los tests de intersección. La acotación puede desactivarse con la palabra clave hierarchy off. Esto únicamente se debería hacer si tenemos poca memoria RAM, o si la malla estuviese formada por unos pocos triángulos. El valor por defecto es hierarchy on.

Las copias de objetos malla hacen referencia a los mismos datos de triángulos, y por ello consumen muy poca memoria. Podríamos trazar cientos de copias de 10000 mallas de triángulos sin quedarnos sin memoria (asumiendo que la primera malla quepa en memoria). Los objetos malla tienen dos ventajas sobre la unión de triángulos: necesitan menos memoria y se transforman más rápidamente. La memoria requerida se reduce al almacenar eficientemente los vértices y normales de los triángulos. El tiempo de analizar el cálculo de la escena para las transformaciones de la malla se reduce puesto que únicamente el objeto malla es el que se transforma y no cada triángulo individual como es necesario en la unión.

Los objetos malla sólo pueden incluir actualmente triángulos y triángulos suavizados. Esta restricción puede cambiar, incluyendo componentes poligonales, en algún momento del futuro.

6.5.2.3.1  Mallas Sólidas

Los objetos malla (mesh y mesh2) se pueden usar ahora en operaciones CSG tales como diferencia e intersección, añadiendo para ello la palabra clave inside_vector, teniendo así definido un 'interior'. Esto únicamente funcionará bien con mallas que tengan un volumen completamente cerrado. Si las mallas tienen cualquier agujero, podría funcionar, pero el resultado no está garantizado.

Para determinar si un punto está en el interior de un triángulo de la malla, POV-Ray lanza un rayo desde el punto en una dirección arbitraria. Si el vector se intersecta con un número impar de triángulos, el punto está dentro de la malla. Si se intersecta con un número par de triángulos, el punto está fuera de la malla. Podemos especificar la dirección de este vector. Por ejemplo, para usar +z como la dirección, podríamos añadir la siguiente línea a la definición de la malla (a continuación de todos los datos de la malla, pero antes de los modificadores del objeto).

  inside_vector <0, 0, 1>
Este cambio no tiene ningún efecto sobre la unión de triángulos... ésta siempre será hueca.

6.5.2.4  Mesh2 (Malla2)

La nueva sintaxis del objeto malla está diseñada para usarse en la conversión a POV_Ray de objetos modelados en otros formatos.

  MESH2 :
      mesh2{
        VECTORS...
        LISTS...   |
        INDICES... |
        MESH_MODIFIERS
      }
  VECTORS :
      vertex_vectors 
      {
        number_of_vertices,
        <vertex1>, <vertex2>, ...
      }|
      normal_vectors 
      {
        number_of_normals,
        <normal1>, <normal2>, ...
      }|
      uv_vectors 
      {
        number_of_uv_vectors,
        <uv_vect1>, <uv_vect2>, ...
      }
  LISTS :
      texture_list 
      {
        number_of_textures,
        texture { Texture1 },
        texture { Texture2 }, ...
      }|
  INDICES :
      face_indices 
      {
        number_of_faces,
        <index_a, index_b, index_c> [,texture_index [,
                                    texture_index, texture_index]],
        <index_d, index_e, index_f> [,texture_index [,
                                    texture_index, texture_index]],
        ...
      }|
      normal_indices 
      {
        number_of_faces,
        <index_a, index_b, index_c>,
        <index_d, index_e, index_f>,
        ...
      }|
      uv_indices {
        number_of_faces,
        <index_a, index_b, index_c>,
        <index_d, index_e, index_f>,
        ...
      }
  MESH_MODIFIER :
      inside_vector <direction> | object_modifiers
mesh2 tiene que especificarse en el siguiente orden VECTORS..., LISTS..., INDICES.... Los normal_vectors, uv_vectors, y texture_list son partes opcionales. Si el número de normales es igual al número de vértices, entonces el apartado normal_indices es opcional y los índices del apartado de face_indices se usan en lugar de ellos. Lo mismo ocurre con los uv_indices.

Nota: el número de uv_indices debe ser igual al de caras.

¡Los índices son base de cero! Así, el primer objeto de cada lista tiene un índice 0.

6.5.2.4.1  Triángulos suaves y planos en la misma malla
Podemos especificar ambos tipos en la misma malla. Para hacer esto, se especifican primero los triángulos suavizados en el apartado de face_indices, seguido por los triángulos planos. Además, hay que especificar los índices normales (en el apartado de normal_indices) para los triángulos suavizados únicamente. Cualquier triángulo sobrante que no tenga asociado un índice normal se asumirá que es un triángulo plano.
6.5.2.4.2  Texturizando Mallas Triangulares
Para especificar una textura para un triángulo individual de la malla, especificamos un simple número entero en el índice de la textura a continuación del vector índice de la cara para ese triángulo.

Para especificar tres texturas interpoladas, especificamos tres números enteros en el índice de texturas a continuación del vector índice de la cara para ese triángulo.

Las texturas interpoladas en los vértices y las texturas simples para un triángulo individual se pueden mezclar en la misma malla

6.5.2.5  Polygon (Polígonos)

El objeto polygon es útil para crear rectángulos, cuadrados y cualquier otra forma plana con más de tres aristas. Su sintaxis es:
POLYGON:
    polygon
    {
        Number_Of_Points, <Point_1> <Point_2>... <Point_n>
        [OBJECT_MODIFIER...]
    }
El valor Number_Of_Points (número de puntos) especifica cuántos puntos se usan para definir el polígono. Los puntos <Point_1> hasta <Point_n> describen al polígono o polígonos. Un polígono puede contener cualquier número de sub-polígonos, superpuestos o no. En el lugar donde hay un número par de polígonos superpuestos aparece un hueco. Cuando repetimos el primer punto de un sub-polígono, termina y empieza una nueva secuencia de puntos de otro sub-polígono. Esto significa que todos los puntos de un sub-polígono son diferentes.

Si el último sub-polígono no está cerrado, se emite una señal de advertencia y el programa automáticamente cierra el polígono. Esto es útil debido a que los polígonos importados de otros programas pueden no estar cerrados, es decir, su primer y último punto no son el mismo.

Todos los puntos de un polígono son vectores tridimensionales que se sitúan sobre el mismo plano. Si éste no es el caso, aparecerá un error. Es común usar vectores de dos dimensiones para describir un polígono. POV-Ray asume que el valor z es en este caso 0.

Un polígono cuadrado que se corresponde con un mapa de imagen plano es sencillamente:

  polygon {
    4,
    <0, 0>, <0, 1>, <1, 1>, <1, 0>
    texture {
      finish { ambient 1 diffuse 0 }
      pigment { image_map { gif "test.gif"  } }
    }
    //aquí, escale y rote si es necesario
  }
La característica sub-polígono se puede usar para generar formas complejas como la letra "P", donde es cortado un hueco dentro de otro polígono:
  #declare P = polygon {
    12,
    <0, 0>, <0, 6>, <4, 6>, <4, 3>, <1, 3>, <1,0>, <0, 0>, 
    <1, 4>, <1, 5>, <3, 5>, <3, 4>, <1, 4>
  }
El primer sub-polígono (en la primera línea) define la forma exterior de la letra "P". El segundo sub-polígono (en la segunda línea) define el hueco rectangular que se corta de la parte superior de la letra "P". Ambos rectángulos son cerrados es decir, el primer punto y el último son los mismos.

La característica de recortar huecos del interior de un polígono está basado en el test que se usa para daterminar el interior/exterior de un polígono. Un punto se considera que es del interior de un polígono si una línea recta trazada desde este punto en una dirección arbitraria atraviesa un número impar de aristas (esto se conoce como el teorema de las curvas de Jordan).

Otro ejemplo más complejo mostrando un triángulo con tres pequeños huecos triangulares y tres pequeños triángulos que se encuentran en el exterior:

  polygon {
    28,
    <0, 0> <1, 0> <0, 1> <0, 0>          // triángulo exterior más grande
    <.3, .7> <.4, .7> <.3, .8> <.3, .7>  // t. exterior pequeño #1
    <.5, .5> <.6, .5> <.5, .6> <.5, .5>  // t. exterior pequeño #2
    <.7, .3> <.8, .3> <.7, .4> <.7, .3>  // t. exterior pequeño #3
    <.5, .2> <.6, .2> <.5, .3> <.5, .2>  // t. interior #1
    <.2, .5> <.3, .5> <.2, .6> <.2, .5>  // t. interior #2
    <.1, .1> <.2, .1> <.1, .2> <.1, .1>  // t. interior #3
  }

6.5.2.6  Triángulos y triángulos Suavizados

La primitiva triangle está disponible para hacer objetos más complejos que los que nos permitirían las figuras propias del sistema. Los triángulos se crean a mano normalmente, sino que son conversiones de otros archivos o generados por otras utilidades. Un triángulo se define por:

TRIANGLE:
    triangle
    {
        <Corner_1>, <Corner_2>, <Corner_3>
        [OBJECT_MODIFIER...]
    }
donde <Corner_n>  es un vector que define las coordenadas x, y, z de cada vértice del triángulo.

Puesto que los triángulos son superficies perfectamente planas se requeriría un número extremadamente grande de triángulos muy pequeños para simular una superficie curvada suave. Sin embargo, nuestra percepción de superficie suave depende en gran medida de la dirección de la luz y del sombreado. Modificando artificialmente las normales de la superficie, podemos simular una superficie suavizada y esconder las aristas afiladas entre las juntas de los triángulos individuales.

La primitiva smooth_triangle se usa justamente para tal propósito. Los triángulos suavizados usan la fórmula llamada "Phong normal interpolation"  para calcular la normal a la superficie de cualquier punto del triángulo basándose en los vectores normales los cuales definimos para cada uno de los tres vértices. Esto hace que el triángulo parezca ser una superficie curvada suave. Un triángulo suavizado se define por:

SMOOTH_TRIANGLE:
    smooth_triangle
    {
        <Corner_1>, <Normal_1>, <Corner_2>,
        <Normal_2>, <Corner_3>, <Normal_3>
        [OBJECT_MODIFIER...]
    }
donde los vértices se definen como en un triángulo normal y <Normal_n>  es un vector que describe la dirección de la normal a la superficie en cada vértice.

Estos vectores normales son prohibitivamente difíciles de calcular a mano. En consecuencia, los triángulos suavizados son casi siempre generados por utilidades externas. Para lograr resultados suaves, aquellos triángulos que compartan un vértice común deberían tener el mismo vector normal en ese vértice. Generalmente, las normales suavizadas deben de ser el promedio de todas las normales actuales de los triángulos que comparten ese punto.

Los objetos  mesh son una forma de combinar muchos objetos triangle y smooth_triangle conjuntamente de una manera muy eficiente. Ver "Mesh" para más detalles.