6.1.4  Expresiones vectoriales

POV-Ray requiere muy amenudo que especifiques vectores. Un vector en un conjunto de valores de coma flotante relacionados. Los vectores pueden especificarse usando literales, identificadores o funciones que devuelvan valores de tipo vector. También puedes crear expresiones muy complejas usando combinaciones de los anteriores, usando los operadores tradicionales.

Los vectores de POV-Ray pueden tener de 2 a 5 componentes, pero la mayoría tienen 3 componentes. Salvo que se especifique lo contrario, debes asumir que la palabra "vector" se refiere a un vector de tres componentes. POV-Ray opera en un sistema de coordenadas de tres dimensiones (x, y y z), y tienes que usar vectores de tres componentes para especificar los valores x,y y z. En algunas ocasiones, POV_Ray necesita sólo dos coordenadas, que se especifican normalmente usando un vector 2D llamado "vector UV". Los objetos fractales usan vectores de 4 dimensiones. Las expresiones de color utilizan vectores 5D, aunque te permiten especificar 3, 4 ó 5 componentes y usar los valores por defecto para los no especificados. Salvo que se indique lo contrario, los vectores de 2, 4 ó 5 componentes funcionan igual que los vectores 3D, excepto que tienen un número diferente de componentes.

La sintaxis para combinar literales de vector en las expresiones vectoriales es prácticamente idéntica a la de las expresiones de coma flotante. En la sintaxis de expresiones vectoriales a continuación, algunos de los items de sintaxis se definen en la sección referente a expresiones de coma flotante. Vea "Expresiones de coma flotante" para conocer esas definiciones. En las siguientes subsecciones se detallan las características específicas de vectores.

VECTOR:
    NUMERIC_TERM [SIGN NUMERIC_TERM]
NUMERIC_TERM:
    NUMERIC_FACTOR [MULT NUMERIC_FACTOR]
NUMERIC_FACTOR:
    VECTOR_LITERAL        | 
    VECTOR_IDENTIFIER     | 
    SIGN NUMERIC_FACTOR   | 
    VECTOR_FUNCTION       |
    VECTOR_BUILT-IN_IDENT | 
    ( FULL_EXPRESSION )   | 
    ! NUMERIC_FACTOR      | 
    FLOAT
VECTOR_LITERAL:
    < FLOAT , FLOAT , FLOAT >
VECTOR_FUNCTION:
    min_extent ( OBJECT_IDENTIFIER )         |
    max_extent ( OBJECT_IDENTIFIER )         |
    trace(OBJECT_IDENTIFIER, VECTOR, VECTOR, [VECTOR_IDENTIFIER] )|
    vaxis_rotate( VECTOR , VECTOR , FLOAT )  |
    vcross( VECTOR , VECTOR )                |
    vrotate( VECTOR , VECTOR )               | 
    vnormalize( VECTOR )                     |
    vturbulence(FLOAT, FLOAT, FLOAT, VECTOR)
VECTOR_BUILT-IN_IDENT:
     x | y | z | t | u | v

Nota: VECTOR_IDENTIFIERS identificadores previamente declarados que contienen valores vectoriales.

6.1.4.1  Literales de vector

Los literales vectoriales consisten en un conjunto de entre 2 y 5 expresiones de coma flotante, encerradas entre los corchetes < y >, separadas por comas. Por ejemplo, he aquí un típico vector de tres componentes:

 < 1.0, 3.2, -5.4578 >

Las comas separando los componentes son necesarias para prevenir que el programa crea que el segundo componente es la expresion 3.2-5.4578 y que no hay tercer componente. Sabrás que has olvidado poner una coma si ves un mensaje de error como "Float expected but '>' found instead" (se esperaba un valor de coma flotante pero se encontró '>' en su lugar).

A veces POV-Ray requiere que especifiques en la misma expresión valores de coma flotante y vectores. Las reglas de sintaxis de las expresiones vectoriales permiten mezclar vectores con vectores o vectores con valores de coma flotante, así que deberás usar comas siempre que no sea el caso, pues se daría una ambigüedad. Por ejemplo, <1,2,3>-4 se evalúa como una expresion mixta, donde se resta 4 de cada componente del vector, dando como resultado <-3,-2,-1>. Sin embargo, al usar una coma, <1,2,3>,-4 representa un vector seguido de un valor de coma flotante.

Cada componente puede ser una expresion de coma flotante completa. Por ejemplo, <This+3,That/3,5*Other_Thing> es un vector válido.

6.1.4.2  Identificadores de vectores

Los identificadores de vectores pueden declarase para hacer las escenas más legibles y parametrizarlas de forma que, cambiando una simple declaracion, se cambien muchos valores. Un identificador se declara de la siguiente forma:

VECTOR_DECLARATION:
    #declare IDENTIFIER = EXPRESSION; |
    #local IDENTIFIER = EXPRESSION;

Donde IDENTIFIER es el nombre del identificador, de hasta 40 caracteres de largo, y EXPRESSION es cualquier expresion válida que se evalúe a un valor de vector.

Nota: Debe haber un punto y coma detrás de la expresión en una declaración de vector. Si se omite se genera un aviso, y algunas macros pueden no funcionar correctamente. Véase la sección " #declare frente a #local" para más información acerca del alcance de los identificadores.

He aquí algunos ejemplos:

 #declare Here = <1,2,3>;
 #declare There = <3,4,5>;
 #declare Jump = <Foo*2,Bar-1,Bob/3>;
 #declare Route = There-Here;
 #declare Jump = Jump+<1,2,3>;

Nota: los identificadores de vector se invocan por su nombre, sin los corchetes angulares. Como se muestra en el último ejemplo, puedes redeclarar un identificador de vector, e incluso utilizar su valor previo en la redeclaracion. Existen varios identificadores predefinidos que POV-Ray declara por ti. Mira la sección  "Identificadores predefinidos de vectores" para conocer más detalles.

6.1.4.3  Operadores de vectores

Los literales, identificadores y funciones de vectores pueden combinarse para formar expresiones de la misma forma que los valores de coma flotante. Las operaciones se realizan componente a componente. Por ejemplo,  <1,2,3> + <4,5,6> se evalúa igual que <1+4,2+5,3+6> o <5,7,9>. El resto de operaciones se realizan de la misma forma, componente a componente. Por ejemplo, (<1,2,3> = <3,2,1>) da como resultado <0,1,0> ya que sólo los componentes centrales son iguales. Hay que admitir que esto no es tal vez demasiado útil, pero es consistente con el resto de operaciones de vectores.

Las expresiones condicionales como (C ? A : B) requieren que C sea una expresion de coma flotante, pero A y B pueden ser expresiones vectoriales. El resultado es que toda la expresion condicional se evalúa como un vector válido. Por ejemplo, si tenemos los números de coma flotante Foo y Bar entonces (Foo < Bar ? <1,2,3> : <5,6,7>) se evalúa como el vector <1,2,3> cuando Foo es menor que Bar, y como <5,6,7> en caso contrario.

Puedes usar el operador punto para extraer un componente como un valor de coma flotante. Supón que has desclarado previamente el identificador Spot como vector. Entonces, Spot.x es un valor de coma flotante que representa el primer componente del vector <x,y,z>. De forma similar, Spot.y y Spot.z referencian al segundo y tercer componentes. En el caso de un vector de cuatro componentes, puedes usar .t para extraer el cuarto componente. El operador punto se usa también en expresiones de color, que se detallan más adelante.

6.1.4.4  Promoción de operadores

Se puede usar una expresión con un solo valor de coma flotante para definir un vector cuyos componentes son todos iguales. POV-Ray sabe cuándo necesita un vector con determinados componentes, asi que promoverá el valor de coma flotante a un vector. Por ejemplo, la sentencia scale necesita un vector de tres componentes, asi que si especificas scale 5 POV-Ray interpreta que quieres decir scale <5,5,5>, o sea, que quieres escalar por 5 en todas las direcciones.

Las versiones de POV-Ray anteriores a la 3.0 sólo permitían este uso de número de coma flotante como vectores de forma limitada, sólo en sitios como scale y turbulence, pero ahora puedes usar este truco en cualquier parte. Por ejemplo:

 box{0,1}  // lo mismo que box{<0,0,0>,<1,1,1>}
 sphere{0,1} // lo mismo que sphere{<0,0,0>,1}

Cuando se promociona un número de coma flotante a vector de 2, 3, 4 ó 5 componentes, todos los componentes se igualan al valor de coma flotante. Sin embargo, cuando se promociona un vector de menos componentes a otro de más componentes, los componentes adicionales se rellenan con 0. Por ejemplo, si POV-Ray espera un vector 4D, al especificar el valor 9 el resultado es <9,9,9,9>, pero si especificas <7,6> el resultado es <7,6,0,0>.

6.1.4.5  Identificadores predefinidos de vectores

Existen varios identificadores predefinidos de vectores. Puedes usarlos para especificar valores o para crear expresiones, pero no puedes redeclararlos para cambiar sus valores. Son los siguientes:

VECTOR_BUILT-IN_IDENT:
    x | y | z | t | u | v

Todos los identificadores predefinidos de vectores tienen valores fijos que nunca cambian. Se definen de forma que es como si incluyeras al principio de tus escenas el siguiente código:

 #declare x = <1, 0, 0>;
 #declare y = <0, 1, 0>;
 #declare z = <0, 0, 1>;
 #declare t = <0, 0, 0, 1>;
 #declare u = <1, 0>;
 #declare v = <0, 1>;

Los identificadores predefinidos x, y, y z pueden hacer tus escenas mucho más legibles si los usas en expresiones de vectores, como por ejemplo:

 plane { y, 1}    // El vector normal es obviamente "y".
 plane { <0,1,0>, 1} // Esto es lo mismo, pero mas difícil de entender.

 translate 5*x    // Mover 5 unidades en la direccion "x".
 translate <5,0,0>  // Lo mismo, pero menos obvio.

Una expresión como por ejemplo 5*x, se evalúa como 5*<1,0,0> o <5,0,0>.

De forma similar, u y v pueden usarse con los vectores 2D. Para vectores 4D debes usar x, y, z, and t. POV-Ray promoverá x, y, y z a un vector 4D cuando éste sea necesario.

6.1.4.6  Funciones de vectores

POV-Ray tiene varias funciones predefinidas para manipular números de coma flotante, vectores y cadenas. Las llamadas a las funciones consisten en el nombre de la función seguido de una lista de parámetros, separados por comas y encerrados entre paréntesis. Por ejemplo:

 keyword(param1,param2)

Las siguientes son funciones que devuelven valores de tipo vector. Toman uno o más parámetros de coma flotante, enteros, vectores o cadenas. Supón que A y B son expresiones vectoriales válidas y F es una expresión de coma flotante.

min_extent ( OBJECT_IDENTIFIER ), max_extent ( OBJECT_IDENTIFIER ). Las funciones min_extent y max_extent devuelven las coordenadas mínimas y máximas de la caja de acotacion de un objeto previamente declarado (esquina inferior izquierda y esquina superior derecha), permitiéndote determinar las dimensiones y localizacion del objeto.

Nota: el funcionamiento no es perfecto, y en algunos casos (como en intersecciones y diferencias de CSG o en isosuperficies) la caja de acotación puede no representar exactamente las dimensiones reales del objeto.

Ejemplo:

#declare Sphere =
sphere {
  <0,0,0>, 1
  pigment { rgb <1,0,0> }
}
#declare Min = min_extent ( Sphere );
#declare Max = max_extent ( Sphere );
object { Sphere }
box {
    Min, Max
    pigment { rgbf <1,1,1,0.5> }
}

trace(OBJECT_IDENTIFIER, A, B, [VECTOR_IDENTIFIER]). Esta función te ayudará a encontrar el punto exacto en el que un rayo intersecta con la superficie de un objeto. Traza un rayo empezando en el punto A y en la dirección especificada por el vector B. Si el rayo toca el objeto especificado, la función devuelve las coordenadas del punto donde el rayo intersecta con el objeto. Si no, devuelve <0,0,0>. Si se proporciona un cuarto parámetro en forma de un identificador de vector, se almacenará en él el valor de la normal en el punto de interseccion (sin incluir la perturbacion causada por las normales de las texturas).

Nota: La única manera fiable de determinar si ha habido intersección es comprobando que la normal devuelta sea <0,0,0>, ya que las intersecciones pueden ocurrir en cualquier coordenada, incluyendo <0,0,0>.

Ejemplo:

#declare MySphere = sphere { <0, 0, 0>, 1 } 
#declare Norm = <0, 0, 0>; 
#declare Start = <1, 1, 1>; 
#declare Inter= 
  trace ( MySphere, Start, <0, 0, 0>-Start, Norm ); 
  object { 
    MySphere 
    texture { 
      pigment { rgb 1} 
    } 
  } 
  #if (vlength(Norm)!=0) 
  cylinder { 
    Inter, Inter+Norm, .1 
    texture { 
      pigment {color red 1} 
    } 
  } 
 #end

vaxis_rotate(A,B,F) Rotar F grados A alrededor de B. Dadas las coordenadas x,y,z de un punto en el espacio designado por el vector A, rotar este punto alrededor de un eje arbitrario definido por el vector B. El ángulo de rotación se especifica en grados con el valor de coma flotante F. El resultado es un vector que contiene las coordenadas x,y,z del nuevo punto.

vcross(A,B) Producto cruzado de A por B. Devuelve un vector que es el producto cruzado de dos vectores. Éste es perpendicular a los dos vectores pasados como parámetros, y su longitud es igual al área del paralelogramo definido por éstos. La fórmula es la siguiente: AxB = |A| * |B| * sin(angle(A,B)) * vector_perpendicular_unitario(A,B). Así, la longitud del vector resultante es proporcional al seno del ángulo que hay entre A y B. Renderiza la escena animada de demostración VECT2.POV para verlo ilustrado.

vnormalize(A) Normaliza el vector A. Devuelve un vector longitud unitaria que tiene la misma dirección que A. La fórmula es vnormalize(A)=A/vlength(A).

Nota:vnormalize(<0,0,0>)genera un error.

vrotate(A,B) Rotar A alrededor del origen B grados. Dadas las coordenas x,y,z de un punto en el espacio designado por el vector A, rotar este punto alrededor del origen la cantidad de grados especificada por el vector B. Esto es, se rotará B.x grados alrededor del eje x,B.y grados alrededor del eje y, y B.z grados alrededor del eje z. El resultado es un vector que contiene las coordenadas del nuevo punto.

vturbulence(Lambda, Omega, Octaves, A) Vector de turbulencia en el punto A. Dadas las coordenadas de un punto en el espacio designado por el vector A, devolverá el vector de turbulencia para ese punto basándose en los valores de lambda,omega y octaves suministrados. La cantidad de turbulencia puede controlarse multiplicando el vector de turbulencia por un múltiplo. La frecuencia con la que cambia el vector de turbulencia se puede controlar multiplicando A por un múltiplo. El vector de turbulencia devuelto por la función puede sumarse al punto A original para obtener una versión perturbada de ese punto. Por ejemplo:

#declare MyVector = MyVector + Amount*vturbulence( 2, 0.5, 6,MyVector*Frequency );

Véase la sección "Funciones de coma flotante" para conocer otras funciones relacionadas con los vectores, pero que devuelven valores de coma flotante. Además de las funciones predefinidas citadas aqui, puedes tambien definir tus propias funciones mediante la directiva  #macro. Mira la sección "Macros definidas por el usuario" para obetener más información.