6.5.4  Objeto Isosuperficie (Isosurface)

Una isosuperficie es un objeto muy versátil cuya superficie se define matemáticamente mediante una función. Si hay un modo de describir su superficie mediante una función, una forma podrá generarse como un objeto isosuperficie. Este tipo de objeto puede ser deformado y ser sometido a desplazamientos de superficie.

Todos los puntos comprobados por una función definida, e iguales a un valor de tolerancia requerido, pertenecen a la superficie del objeto. Es obvio que POV-Ray no puede comprobar todos los puntos en el infinito espacio de un objeto antes de que se consuma todo el hidrógeno del Sol, se expanda su masa y acabe con todos los planetas del sistema Solar, así que para abreviar un poco las cosas, los puntos son muestreados en un área definida y con un rango de precisión determinado. Luego, la superficie se crea mediante interpolación entre los puntos coincidentes. Esto significa que una isosuperficie es una aproximación (la exactitud depende de los ajustes) a la situación exacta de la superficie de la función. Para la gran mayoría de las escenas esta precisión es más que suficiente.

6.5.4.1  Sintaxis de la Isosuperficie

La sintaxis para una isosuperficie es:

isosurface {
  function { ELEMENTOS_DE_FUNCIÓN }
  [contained_by { ESFERA | CAJA }]
  [threshold VALOR_DECIMAL]
  [accuracy VALOR_DECIMAL]
  [max_gradient VALOR_DECIMAL]
  [evaluate P0, P1, P2]
  [open]
  [max_trace ENTERO] | [all_intersections]
  [MODIFICANTES_DE_OBJETO...]
}

Los valores por defecto para las isosuperficies son:

contained_by : box{-1,1}
threshold    : 0.0
accuracy     : 0.001
max_gradient : 1.1

function { ... } (función) Ésta debe ser especificada en primer lugar en una declaración isosurface. Aquí colocaremos todas las funciones matemáticas que describan la superficie.

contained_by { ... } El 'objeto' contained_by (contenido por) limita el área donde POV-Ray recogerá muestras de la superficie de la función. Este contenedor puede ser una esfera o una caja que usan la sintáxis estándar de POV-Ray para tales objetos. Si no se especifica nada, se utilizará box {<-1,-1,-1>, <1,1,1>} por defecto.

contained_by { sphere { CENTRO, RADIO } }
contained_by { box { ESQUINA1, ESQUINA2 } }

threshold (tolerancia) Determina cuánta solidez o sustancia tendrá la isosuperficie. La superficie aparece donde el valor de la función es igual al valor de tolerancia. La tolerancia por defecto es 0.

function = threshold

accuracy (precisión) Para localizar los puntos de la superficie en el objeto, se utiliza un método de subdivisión recursiva. Esta subdivisión se repite hasta que la longitud del intervalo donde POV-Ray encuentra la superficie es menor que la precisión especificada. El valor por defecto es 0.001. Se consiguen superficies más precisas con valores más pequeños pero conllevan más tiempo de proceso.

N. del T.: Se llama gradiente de una función al vector cuyas coordenadas son las derivadas parciales de dicha función.

max_gradient POV-Ray puede localizar el punto de intersección entre un rayo y una isosurface de cualquier función continua si se conoce el gradiente máximo de la función. Aquí se puede expecificar un max_gradient para la función. El valor por defecto es 1.1. Cuando el max_gradient utilizado para encontrar el punto de intersección es muy alto, el proceso se ralentiza considerablemente. Si es demasiado bajo pueden aparecer agujeros o defectos en la isosuperficie o, en algunos casos, no se mostrará toda la superficie del objeto. Mientras se genera la isosuperficie, POV-Ray revisa los valores gradientes encontrados y avisa si éstos son mucho más altos o mucho más bajos que el gradiente máximo especificado:

Warning: The maximum gradient found was 5.257, but max_gradient of
the isosurface was set to 5.000. The isosurface may contain holes!
Adjust max_gradient to get a proper rendering of the isosurface.


Trad: Atencion: El gradiente máximo encontrado fue 5.257, pero el max_gradient
de la isosuperficie fue ajustado a 5.000. ¡La isosuperficie puede contener agujeros!
Ajuste max_gradient para obtener un mejor cálculo de la isosuperficie.
Warning: The maximum gradient found was 5.257, but max_gradient of
the isosurface was set to 7.000. Adjust max_gradient to
get a faster rendering of the isosurface.


Trad: Atención: El máximo gradiente encontrado fue 5.257, pero el max_gradient
de la isosuperficie fue ajustado a 7.000. Ajuste max_gradient para un cálculo
más rápido de la isosuperficie.

Para un mejor rendimiento, se debe especificar un valor próximo al gradiente real máximo.

evaluate (evaluar) POV-Ray puede adaptar dinámicamente el máximo gradiente utilizado. Para activar esta técnica se ha de especificar la palabra clave evaluate seguida de tres parámetros:

En este caso POV-Ray empieza con el valor de max_gradient P0 y cambia dinámicamente durante el proceso a los valores P1 y P2. En el proceso de evaluación, los parámetros P1 y P2 son utilizados en funciones cuadráticas. Esto significa que la sobre-estimación crece más rápidamente con valores altos, y la atenuación con valores pequeños. Con max_gradient dinámico también pueden aparecer agujeros o defectos.

Si no se está seguro de qué valores usar, empiece un render sin evaluate para obtener un valor de max_gradient. A continuación utilícelo con evaluate de esta forma:

Cuando aparecen artefactos y/o agujeros en la isosuperficie, una solución es incrementar el min_factor y/o P2 un poco. Ejemplo: cuando se "compila" un fichero y se encuentra un max_gradient de 356, empezar con

  #declare Min_factor= 0.6;
  isosurface {
     ...
     evaluate 356*Min_factor,  sqrt(356/(356*Min_factor)),  0.7
     //evaluate 213.6, 1.29, 0.7
     ...
   }

Este método es sólo una aproximación de lo que sucede internamente, pero proporciona mayor velocidad de cálculo con la mayoría de las isosuperficies.

open (abierto) Cuando la isosuperficie no está por completo en el interior del objeto contained_by, se producirá una sección donde, en lugar de la isosuperficie, veremos la superficie del contenedor. Con la palabra clave open, estas secciones se eliminan, y en su lugar veremos el interior de la isosuperficie.

Aviso: open ralentiza la velocidad de proceso. Además no se recomienda utilizarlo con operaciones CSG.

max_trace Las Isosuperficies pueden utilizarse con (y como) formas CSG, dado que son objetos finitos sólidos (si no son finitos per se, sí están limitados cuando atraviesan al área delimitada por su contenedor). POV-Ray busca, por defecto, la primera superficie que intersecta con un rayo. Pero cuando se utilizan isosuperficies en operaciones CSG también se han de hallar el resto de superficies. Aquí se ha de añadir, en la declaración isosurface, la palabra clave max_trace seguida de un valor entero. Para comprobar todas las superficies, hay que utilizar en su lugar la palabra clave all_intersections. Con all_intersections POV-Ray seguirá buscando hasta hallar todas las superficies, mientras que con max_trace, sólo se comprueban superficies hasta llegar al número dado.

6.5.4.2  Funciones en las isosuperficies

Las funciones utilizadas para definir la isosuperficie se escriben en el bloque function(...).

Se permite lo siguiente:

Funciones definidas por el usuario (como ecuaciones). Se pueden usar todas las expresiones de coma flotante y operadores (ver sección "Funciones Definidas por el Usuario") que sean legales en POV-Ray.
Con la ecuación de una esfera "x^2+y^2+z^2 = Threshold" tendríamos:

isosurface {
function {pow(x,2) + pow(y,2) + pow(z,2)}
  threshold Threshold
  ...
}

Se pueden declarar las funciones primero (ver sección "Declarando Funciones"), y luego usarlas en la isosuperficie.

#declare Sphere = function {pow(x,2) + pow(y,2) + pow(z,2)}
isosurface {
  function { Sphere(x,y,z) }
  threshold Threshold
  ...
}

Una función, por defecto, tiene tres parámetros (x,y,z) que no se han de especificar explicitamente al realizar la declaración. Cuando se utiliza el identificador, es cuando se han de especificar los parámetros. Por otro lado, si se necesitan más, o menos, de tres parámetros al declarar la función, también se han de especificar explicitamente los nombres de los parámetros.

#declare Sphere = function(x,y,z,Radius) {
    pow(x,2) + pow(y,2) + pow(z,2) - pow(Radius,2) 
}
isosurface {
  function { Sphere(x,y,z,1) }
  ...
}

Para hacérnoslo más fácil, POV-Ray tiene gran cantidad de funciones predefinidas, principalmente superficies algebraicas, aunque también hay una función de malla y una función de ruido 3d. Ver sección "Funciones Internas" para una lista completa y explicaciones sobre cómo utilizar los parámetros. Estas funciones internas se utilizan mediante la inclusión del fichero functions.inc.
Para la forma interna del paraboloide usaremos:

#include "functions.inc"
isosurface {
  function  { f_paraboloid(x,y,z, -1) }
  ...
}

Ya que los pigmentos pueden ser declarados como funciones, tambien pueden utilizarse en isosuperficies siempre que se declaren antes. Ademas, cuando se usa un identificador se ha de especificar que componente del vector color será utilizado. Para ello, se utiliza la siguiente notación de punto: Function (x,y,z).red

#declare FBozo = function { 
    pigment { bozo color_map { [0 rgb 0] [1 rgb 1] }}
}
isosurface {
  function  { FBozo(x,y,z).gray }
  ...
}

Un vector color tiene cinco componentes. Los tipos de punto soportados para acceder a estos componentes son:

Se permiten las directivas condicionales

#declare Rough = yes;
#include "functions.inc"
isosurface {
  function { y #if(Rough=1)-f_noise3d(x/0.5,y/0.3,z/0.4)*0.8 #end }
  ...
}

y también los bucles:

#include "functions.inc"
#declare Thr = 1/1000;
#declare Ang = radians(45);
#declare Offset = 1.5;
#declare Scale = 1.2;
#declare TrSph = function { f_sphere(x-Offset,y,z,0.7*Scale) }

function {
  (1-Thr)
  #declare A = 0;
  #while (A<8)
  -pow(Thr, TrSph(x*cos(A*Ang) + y*sin(A*Ang),
                  y*cos(A*Ang) -x*sin(A*Ang), z) )
    #declare A=A+1;
  #end
}

Por supuesto que las funciones pueden combinarse y los parámetros ser sustituidos. Aprenda más de ello en las próximas secciones.

6.5.4.3  Transformaciones en las funciones

Transformar un objeto isosuperficie es igual que transformar cualquier tipo de objeto de POV-Ray. Sólo hay que utilizar los modificadores de objeto (scale, translate, rotate, ...).

Sin embargo, cuando queremos transformar funciones en el interior de un objeto contained_by, hemos de sustituir parámetros en las funciones, teniendo en cuenta que los resultados pueden parecer invertidos a lo que normalmente esperamos. Veamos porqué:

Tenemos una Esfera(x,y,z) y la queremos desplazar hacia la derecha. Sabemos que ahora está centrada en el origen porque x=0. Si la queremos en x=2 (moverla 2 unidades hacia la derecha), debemos escribir esta nueva ecuación de modo que también sea igual a 0 (como si estuviera centrada) x-2=0. Ahora que ambas ecuaciones están igualadas a 0, podemos reemplazar el parámetro x con x-2. Así, nuestra Esfera(x-2,y,z) se mueve dos unidades a la derecha.

Otro ejemplo: ajustemos la altura de nuestra Esfera a 0.5 en la dirección Y. El tamaño por defecto es y=1 (una unidad). Necesitamos y=0.5. Para despejar esta ecuación del mismo modo que la anterior, multiplicaremos ambos términos de la ecuación por dos: y*2=0.5*2, con lo que nos queda, que y*2=1. Si reemplazamos el parámetro Y en nuestra esfera tenemos: Esfera(x,y*2,z). Esto reduce la altura de la esfera a la mitad.

Ésta es la idea general de las sustituciones. A continuación veremos un resumen de algunas sustituciones útiles, utilizando un objeto ya declarado P(x,y,z).

6.5.4.3.1  Funciones, Escalado

Escalar x : sustituir "x" con "x/scale" (lo mismo para otros parámetros)

scale x*2 se escribe P(x/2,y,z)
6.5.4.3.2  Escalado Infinito

Escalar x infinitamente : sustituir "x" con "0" (cero) (lo mismo para otros parámetros)

scale y infinitamente se escribe P(x,0,z)
6.5.4.3.3  Funciones, Traslación

Mover x: sustituir "x" con "x - translation" (lo mismo para otros parámetros)

translate z*3 se escribe P(x,y,z-3)
6.5.4.3.4  Funciones, Estirar (shear)

Deformar, estirar en el plano XY : sustituir "x" con "x + y*tan(radians(Angle))" (lo mismo para otros parámetros)

Deformar el objeto 45 grados hacia la izquierda se escribe P(x+y*tan(radians(45)), y, z)
6.5.4.3.5  Funciones, Rotar

Aviso: las sustituciones de rotación funcionan igual que las rotaciones normales de POV-Ray: ya están compensadas para trabajar inversamente

rotar sobre X
: sustituir "y" con "z*sin(radians(Angle)) + y*cos(radians(Angle))"
: sustituir "z" con "z*cos(radians(Angle)) - y*sin(radians(Angle))"

rotar sobre Y
: sustituir "x" con "x*cos(radians(Angle)) - z*sin(radians(Angle))"
: sustituir "z" con "x*sin(radians(Angle)) + z*cos(radians(Angle))"

rotar sobre Z
: sustituir "x" con "x*cos(radians(Angle)) + y*sin(radians(Angle))"
: sustituir "y" con "-x*sin(radians(Angle)) + y*cos(radians(Angle)) "

  rotar z*75 se escribe:
  P(x*cos(radians(75)) + y*sin(radians(75)),
    -x*sin(radians(75)) + y*cos(radians(75)), z)
 
6.5.4.3.6  Funciones, Invertir

Invertir X - Y : sustituir "x" con "y" y sustituir "y" con "-x"

Invertir Y - Z : sustituir "y" con "z" y sustituir "z" con "-y"

Invertir X - Z : sustituir "x" con "-z" y sustituir "z" con "x"

invertir x e y se escribe  P(y, -x, z)
6.5.4.3.7  Funciones, Torsion (Twist)

Retorcer N vueltas/unidad sobre x
: sustituir "y" con "z*sin(x*2*pi*N) + y*cos(x*2*pi*N)"
: sustituir "z" con "z*cos(x*2*pi*N) - y*sin(x*2*pi*N)"

6.5.4.4  Combinando Funciones

Las operaciones CSG se pueden realizar sobre isosuperficies ya que también son objetos sólidos finitos (si no son finitos por sí mismos, lo son a partir de la sección que delimita su contenedor). Se hace del modo normal.

Sin embargo, cuando se necesita hacer operaciones del tipo CSG en las funciones dentro del objeto contained_by, las funciones se han de combinar mediante los operadores apropiados.

He aquí un resumen de combinaciones útiles de funciones:

6.5.4.4.1  Funciones, Fusión (Merge)

Una fusión se puede obtener con "min(A, B, ...)"

function{min(Function_A(x,y,z),Function_B(x,y,z))}
function{min(Function_A(x,y,z),Function_B(x,y,z),Function_C(x,y,z))}

6.5.4.4.2  Funciones, Intersección

Un modo de hacerlo: utilizando "max(A,B,...)"

function{max(Function_A(x,y,z),Function_B(x,y,z))}
function{max(Function_A(x,y,z),Function_B(x,y,z),Function_C(x,y,z))}

6.5.4.4.3  Funciones, Diferencia

Un modo de hacer esto es utilizar "max(A, -(B-2*Threshold))"

function{max( Function_A(x,y,z), -(Function_B(x,y,z) -2*Threshold))}
threshold Threshold
Si se está utilizando la tolerancia por defecto (=0), no se necesita restar 2*Threshold, ya que 2*0=0

6.5.4.4.4  Funciones, Burbuja (Blob)

Hay dos modos posibles de hacer esto:

  1.   utilizando "(A*B)- Blob_threshold"
  2.   utilizando "(1+Blob_threshold) -Blob_threshold^A -Blob_threshold^B"
function{ (Function_A(x,y,z) * Function_B(x,y,z)) -Blob_threshold)}
function{
  (1+Blob_threshold)
  -pow(Blob_threshold, Function_A(x,y,z))
  -pow(Blob_threshold, Function_B(x,y,z))
}

6.5.4.4.5  Funciones, Burbuja Negativa (Negative Blob)

usar "A +(Blob_threshold ^(B + Strength)^(C + Strength))"

function{Function_A + pow(Blob_threshold,(Function_B + Strength))}

6.5.4.4.6  Funciones, Mezclar

usar "A + B" or "A - B"
Esto produce una especie de mezcla de las dos funciones.

  function { Function_A +  Function_B }

6.5.4.5  Mejorando la velocidad de la isosuperficie

La velocidad de generación de las isosuperficies puede variar considerablemente dependiendo de los parámetros utilizados. Normalmente se generan más deprisa si los ajustes están optimizados. He aquí algunas reglas para recordar cuando diseñemos isosuperficies:

6.5.4.5.1  Utilizar Precisión (Accuracy)

Ajustar accuracy a 0.1 (el valor por defecto es 0.001), es un buen valor para empezar. No se notará la diferencia en isosuperficies cuya superficie varíe gradualmente, pero se renderizan dos veces más rápido. Se necesitará un valor accuracy más alto cuando la superficie tenga cambios bruscos o una mayor frecuencia de cambios en las partes visibles por la cámara (y cuando la precisión de estos detalles realmente importe). Posiblemente se necesite una precisión elevada cuando se esté dibujando sobre la isosuperficie o cuando la superficie deba coincidir con la función muy cerca.
Normalmente la precisión (accuracy) se puede ajustar más baja que el valor por defecto, sin observarse diferencias notables en el aspecto la isosuperficie.

6.5.4.5.2  Contenedor

Asegurarse que el objeto contained_by se ajusta lo más posible al contorno. Un contenedor sobredimensionado puede disparar el tiempo de cálculo necesario.
Cuando el contenedor tiene un gran cantidad de espacio vacío alrededor de la isosuperficie actual, POV-Ray tiene que realizar un montón de muestreo superfluo: especialmente con funciones complejas esto consume mucho tiempo. Y aún más, el máximo gradiente necesario para obtener una superficie correcta también se incrementa rápidamente (casi proporcional al sobretamaño!).
Se puede usar una copia transparente del container (utilizando exactamente las mismas trasnformaciones) para comprobar cómo se ajusta. Utilizar las extensiones mínima y máxima (min_extent y max_extent) de la isosuperficie no es útil debido a que sólo se obtiene la extensión del container, no la de la isosuperficie actual.

6.5.4.5.3  Gradiente Máximo

Es importante especificar un valor de max_gradient correcto. Si se ajusta demasiado alto, se ralentiza el proceso. Si es demasiado bajo, la superficie no se genera correctamente, mostrando defectos o agujeros. Así pues, hay que encontrar el gradiente máximo real y utilizarlo. POV-Ray avisará si utilizamos un max_gradient incorrecto. Normalmente es mejor utilizar el valor mostrado en el aviso como nuevo valor de gradiente máximo, pero puede ocurrir que este valor sea insuficiente.

Cuando utilizamos evaluate, POV-Ray utiliza un método de cálculo dinámico para el valor max_gradient. Esto puede ayudar a conseguir un proceso más rápido que un max_gradient correcto en algunas situaciones. Optimizar los parámetros de evaluate significa el equilibrio entre tener defectos en la isosuperficie y cálculos lentos. Se requiere mucha paciencia y alguna experiencia para encontrar los mejores valores.