|
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.
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:
max_gradient*min_factor
, siendo
'min_factor' un valor de coma flotante entre 0 y 1 para reducir
max_gradient a un "max_gradient mínimo". El valor ideal para P0
sería la media de los max_gradient encontrados, pero no se
puede, en la práctica, acceder a esta información. Un buen punto
de partida es min_factor=0.6.sqrt(valor_hallado_de_max_gradient/(valor_hallado_de_max_gradient*min_factor))
,
siendo 'min_factor' el mismo valor utilizado en P0; esto nos dará
un factor de sobre-estimación mayor que 1, basado en nuestro
max_gradient mínimo y en el max_gradient hallado.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.
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 sí 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).re
d
#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:
x
| F( ).u
| F( ).red
y
| F( ).v
| F( ).green
z
| F( ).blue
filter
| F( ).t
transmit
gray
hf
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.
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).
Escalar x : sustituir "x
" con "x/scale
"
(lo mismo para otros parámetros)
scale x*2 se escribe P(x/2,y,z)
Escalar x infinitamente : sustituir "x
" con "0
"
(cero) (lo mismo para otros parámetros)
scale y infinitamente se escribe P(x,0,z)
Mover x: sustituir "x
" con "x - translation
"
(lo mismo para otros parámetros)
translate z*3 se escribe P(x,y,z-3)
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)
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)
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)
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)
"
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:
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))}
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))}
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 ThresholdSi se está utilizando la tolerancia por defecto (=0), no se necesita restar 2*Threshold, ya que 2*0=0
Hay dos modos posibles de hacer esto:
(A*B)- Blob_threshold
"(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)) }
usar "A +(Blob_threshold ^(B + Strength)^(C + Strength))
"
function{Function_A + pow(Blob_threshold,(Function_B + Strength))}
usar "A + B" or "A - B
"
Esto produce una especie de mezcla de las dos funciones.
function { Function_A + Function_B }
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:
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.
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.
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.
|