Manual POV Ray
Manual POV Ray
(POV-Ray)
Documentación del usuario 3.0
Versión (incompleta) en Castellano
1 de diciembre de 1997
1. Introducción
Este documento detalla el uso del Trazador de Rayos Persistence of Vision, (POV-Ray). Se
compone de cuatro partes: la guía de instalación, el tutorial, la guía de referencia y los apéndices. La
primera parte (ver secciones "Descripción del Programa" y "Comienzo Rápido") cuenta como obtener y
como instalar POV-Ray. También da una breve introducción al trazado de rayos. El tutorial explica
paso a paso como usar las diferentes características de POV-Ray (ver sección "Tutorial para
Principiantes"). La referencia da una completa descripción de todas las características de POV-Ray
explicando todas las opciones disponibles (activadas por parámetros de la línea de comandos o por
sentencias en archivos INI) y del lenguaje de descripción de escena (ver sección "Referencia de POV-
Ray", sección "Opciones de POV-Ray" y sección "Lenguaje de descripción de escena"). Los apéndices
incluyen trucos y pistas, lecturas sugeridas, direcciones de contacto e información legal.
1.1. Notación
A lo largo de este documento se seguirá la siguiente notación para denotar palabras clave del lenguaje de
descripción de escena, parámetros de la línea de comandos, palabras clave de archivos INI y nombres
de archivos.
Para cada pixel en la imagen final se disparan uno o más rayos en la escena y se comprueba la
intersección con cada uno de los objetos de la escena. Los rayos se originan en el observador,
representado por la cámara, y pasan a través de la ventana de visión (que representa la imagen final).
Cada vez que el rayo golpea a un objeto, se calcula el color de la superficie en ese punto. Para ello se
determina la cantidad de luz que proviene de cada fuente luminosa para ver si el objeto permanece en la
sombra o no. Si la superficie es reflectora o traslúcida se trazan nuevos rayos para determinar la
contribución de la luz reflejada o refractada en el color final de la superficie.
Los efectos especiales como la luz difusa (radiosidad), efectos atmosféricos y luces extendidas hacen
necesario el trazado de muchos rayos adicionales por cada pixel de la escena.
El paquete POV-Ray incluye instrucciones detalladas para usar el trazador y crear escenas. Se han
incluido muchas escenas asombrosas con POV-Ray para que puedas empezar a crear imágenes
inmediatamente. Estas escenas pueden ser modificadas para que no tengas que empezar desde cero.
Además de las escenas predefinidas, también se suministra una gran biblioteca de formas predefinidas y
de materiales. Puedes incluir estas formas y materiales en tus propias escenas simplemente incluyendo el
nombre de la forma o material y el nombre del archivo fuente correspondiente.
Las ultimas versiones de los archivos necesarios están disponibles en CompuServe, Internet, América
On-line y varios BBS. Vea la sección "Donde Encontrar los archivos de POV-Ray" para obtener más
información.
PERSISTENCE OF VISION RAYTRACER 13
2.3.1.1. MS-Dos
La versión para MS-DOS corre bajo MS-DOS o como una aplicación DOS bajo Windows 95,
Windows NT, Windows 3,1 o Windows para Trabajo en Grupo 3.11. También corre bajo OS/2 y
OS/2 WARP.
2.3.1.2. Windows
La versión para Windows corre bajo Windows 95, Windows NT y bajo Windows 3.1 o 3.11 si se
agregan las extensiones Win32s. También corre bajo OS/2 WARP.
2.3.1.3. Linux
Requerimientos de hardware y software:
♦ POVLINUX.TGZ o POVLINUX.TAR.GZ, un archivo que contiene el binario oficial para cada uno de los
modos SVGALib y X-Windows. También contiene ejemplos de escenas, los archivos .INC
estándar y la documentación.
Recomendado:
♦ 8 Mb o más RAM.
♦ Monitor SVGA preferiblemente con capacidad de usar los modos Hi color (color de 16 bits ) o
True color (color de 24 bits).
♦ Si quieres previsualización, requerirá o SVGALib o X-Windows.
♦ Un visor de archivos gráficos capaz de visualizar archivos en formato PPM, TGA o PNG.
Optativo: el código fuente no es necesario para usar POV-Ray. Se proporciona para curiosos y
aventureros.
♦ Una CPU 68020 o superior sin una unidad del punto flotante (serie LC, Performa o Centris) y
por lo menos 8 Mb de RAM, o
♦ Una CPU 68020 o superior con una unidad de punto flotante (series Mac II o Quadra) y por lo
menos 8 Mb de RAM, o
♦ Cualquier ordenador Power Macintosh y por lo menos 8 Mb de RAM.
♦ System 7 o más nuevo y color QuickDraw (el System 6 ya no es soportado).
♦ Aproximadamente 6 Mb de espacio libre en el disco para la instalación y de 2 a 10 Mb de espacio
libre adicional como espacio de trabajo.
♦ Una utilidad para visualizar archivos gráficos que soporte los formatos Mac PICT, GIF y quizás
TGA y PNG (las aplicaciones shareware GIFConverter o GraphicConverter son buenas.)
Archivos de POV-Ray requeridos:
Recomendado:
♦ 68030/33 o más rápido con unidad de punto flotante, o cualquier Power Macintosh.
♦ 8 Mb o más de RAM para Macintosh 68K, 16 Mb o más para sistemas Power Macintosh.
♦ Monitor preferentemente en color: de 256 colores esta bien, pero de miles o millones de colores
está incluso mejor.
Optativo: el código fuente no es necesario para usar POV-Ray. Se proporciona para curiosos y
aventureros. POV-Ray se puede compilar usando Apple's MPW 3.3, Metrowerks CodeWarrior 8 o
Symantec 8.
Requerimientos:
♦ 8 Mb o más de RAM.
♦ Procesador 68030, 68882 o superior.
♦ Tarjeta gráfica de 24-bits (con soporte para la biblioteca CyberGFX)
Tan pronto como se haga público un compilador estable para sistemas Amiga PowerPC, los planes son
agregar este a la lista de sabores.
Optativo: el código fuente no es necesario para usar POV-Ray. Se proporciona para curiosos y
aventureros.
PERSISTENCE OF VISION RAYTRACER 17
♦ POVLHA_S.ZIP, el código fuente en C de POV-Ray para Amiga Contiene partes genéricas y partes
específicas Amiga. No incluye ejemplos de escenas, archivos .INC estándar ni la documentación
por lo que también deberás obtener el archivo ejecutable.
2.3.4. SunOS
Requerimientos de hardware y software:
♦ 8 Mb de RAM o más.
♦ Si quieres previsualización, requerirá X-Windows o un terminal X.
♦ Preferiblemente capacidad para visualizar color verdadero de 24 bits(True Color), aunque se sabe
que el código X-Windows funciona con cualquier resolución y número de colores.
♦ Un visor de archivos gráficos capaz de visualizar formatos PPM, TGA o PNG.
Optativo: el código fuente no es necesario para usar POV-Ray. Se proporciona para curiosos y
aventureros.
♦ Co-procesador matemático.
♦ 8 Mb o más de memoria RAM.
♦ Un visor de archivos gráficos capaz de visualizar formatos PPM, TGA o PNG.
Opcional:
Todas las versiones del programa comparten las mismas formas, iluminación y texturas. En otras
palabras, un IBM-PC puede crear las mismas imágenes qué un superordenador Cray siempre que tenga
bastante memoria.
Cada usuario deseará obtener el ejecutable que mejor se adapte al hardware de su ordenador. Consulta
la sección “Donde encontrar los archivos de POV-Ray” para ver donde encontrar estos archivos.
Puedes contactar con estas fuentes para encontrar la mejor versión para ti y tu ordenador
La primera pregunta qué debes hacerte antes de proceder es ¿realmente necesito compilar POV-Ray?
Las versiones ejecutables oficiales del POV-Ray Team están disponible para MS-DOS, Windows
3.1x/95/NT, Mac 68k, Mac Power PC, Amiga, Linux para Intel x86, y SunOS. Otras compilaciones no
oficiales para otras plataformas estarán pronto disponibles. Si no piensas agregar cualquier característica
personalizada o experimental al programa y si ya existe un ejecutable para tu plataforma, entonces no
necesitas compilar este programa.
Si quieres proceder deberás estar muy seguro de ti mismo. Las secciones siguientes y otra
documentación relacionada a la compilación asumen que sabes lo qué estas haciendo. Asumen qué
tienes un compilador de C adecuado instalado y funcionando. Asumen que sabes como compilar y
enlazar programas de múltiples partes usando una utilidad make o un archivo de proyecto IDE si tu
compilador los soporta. Ya que los archivos make y los archivos de proyecto a menudo especifican
PERSISTENCE OF VISION RAYTRACER 19
información sobre unidades, directorios o paths, no podemos prometerte qué nuestros archivos make o
de proyectos trabajarán en tu sistema. Asumimos que sabes hacer cambios en los archivos make y de
proyectos para especificar donde se localizan tus bibliotecas de sistema y otros archivos necesarios.
En general no debes esperar ningún apoyo técnico del POV-Ray Team sobre cómo compilar el
programa. Todo se provee tal como esta. Todo lo qué podemos decir con certeza es qué pudimos
compilar él código en nuestros sistemas. Si no trabaja para ti probablemente no podamos decirte
porqué.
No hay ninguna documentación técnica para el código fuente mismo salvo los comentarios en los
archivos fuente. Intentamos hacer lo mejor para escribir código claro y bien comentado, pero algunas
secciones están apenas comentadas y algunos comentarios pueden estar desactualizados. No
proporcionamos ningún soporte técnico para ayudarte a agregar características. No explicamos cómo
trabaja una característica en particular. En algunos casos la persona qué escribió una parte del programa
ya no esta hace tiempo activamente en el Equipo y no sabemos exactamente cómo trabaja.
Cuando hagas cualquier versión personalizada de POV-Ray o cualquier compilación extraoficial, por
favor asegúrate de haber leído y seguir todas las provisiones de nuestra licencia en la sección
"Copyright". En general puedes modificar y usar POV-Ray para ti mismo, sin embargo si quieres
distribuir tu versión extraoficial debes seguir nuestras reglas. No puedes bajo cualquier circunstancia
usar porciones del código fuente de POV-Ray en otros programas.
En general, hay archivos separados para cada plataforma de hardware y sistema operativo, pero cada
uno de estos archivos soporta más de un compilador. Por ejemplo aquí esta la estructura de directorios
para el archivo MS-DOS.
SOURCE
SOURCE\LIBPNG
SOURCE\ZLIB
SOURCE\MSDOS
SOURCE\MSDOS\PMODE
SOURCE\MSDOS\BORLAND
SOURCE\ MSDOS\DJGPP
SOURCE\MSDOS\WATCOM
El directorio SOURCE contiene archivos fuente para las partes genéricas de POV-Ray qué son comunes
a todas las plataformas. El directorio SOURCE\LIBPNG contiene archivos para compilar una biblioteca de
rutinas utilizadas en la lectura y escritura de archivos gráficos en formato PNG (Portable Network
Graphic). El directorio SOURCE\ZLIB contiene archivos para compilar una biblioteca de rutinas utilizada
por libpng para comprimir y descomprimir flujos de datos. Todos estos archivos son usados por todas
las plataformas y compiladores. Están en cada versión de los archivos fuente.
El directorio SOURCE\MSDOS contiene todos los archivos fuente de la versión para MS-DOS común a
todos los compiladores MS-DOS soportados. El subdirectorio PMODE contiene archivos fuente para
PMODE.LIB qué son necesarios para todas las versiones de MS-DOS. Los subdirectorios BORLAND, DJGPP
y WATCOM contienen fuente, archivos make y archivos de proyecto para compiladores de C de Borland,
DJGPP y Watcom.
2. DESCRIPCIÓN DEL PROGRAMA 20
Por ejemplo, sistemas operativos diferentes usan caracteres diferentes como separador entre directorios
y nombres del archivo. MS-DOS usa una barra invertida(\), Unix una barra normal(/) y Mac una
coma(,). El archivo CONFIG.H para MS-DOS y Windows contienen lo siguiente:
#define FILENAME_SEPARATOR '\'
qué instruye a la parte genérica de POV-Ray para usar una barra invertida(\).
Cada personalización que la parte genérica del código requiere tiene un valor por defecto en el archivo
SOURCE\FRAME.H, qué también se incluye en cada módulo después de CONFIG.H. El archivo de cabecera
FRAME.H contiene muchos grupos de definiciones como esta:
#ifndef FILENAME_SEPARATOR
#define FILENAME_SEPARATOR '/'
#endif
el cual básicamente dice qué si no está definido previamente en CONFIG.H, entonces este es su valor por
defecto. Verifica FRAME.H para ver qué otros valores puedes querer configurar.
Si se usa cualquier definición para especificar una función especifica de una plataforma también se
deberá incluir un prototipo para esa función. El archivo SOURCE\MSDOS\CONFIG.H, por ejemplo, no
sólo contiene el macro:
#define POV_DISPLAY_INIT(w,h) MSDOS_Display_Init ((w), (h));
para definir el nombre de la función de inicialización de visualización de gráficos, también contiene el
prototipo:
void MSDOS_Display_Init (int w, int h);
Si piensas portar POV-Ray hacia una plataforma no soportada debes comenzar probablemente con la
versión más simple para Unix sin previsualización. Después agrega nuevos trozos personalizados a
través del archivo CONFIG.H.
2.3.7.3. Conclusión
Comprendemos que las secciones anteriores son solo los primeros pasos, pero la mitad de la diversión
de trabajar en los fuentes de POV-Ray es escarbar en ellos y figurártelo por ti mismo. Así es como los
PERSISTENCE OF VISION RAYTRACER 21
miembros del POV-Ray Team comenzaron. Hemos tratado de hacer el código tan claro como
pudimos.
¡Buena suerte !
2.4.2. Internet
El hogar en Internet de POV-Ray está disponible a través del world wide web a través de la dirección
http://www.povray.org y vía ftp como ftp.povray.org. Por favor, visítala a menudo para conocer los
últimos archivos, utilidades, noticias e imágenes del sitio oficial de POV-Ray en Internet.
2.4.5. PCGNet
La red Profesional de CAD y Gráficos (PCGnet) sirve a ambas comunidades, CAD y Gráficos
haciendo ampliamente disponible información útil.
Anteriormente conocida como ADEnet, PCGnet es una red nueva que incorpora nodos nuevos y
enfoca uniformemente ambos tópicos relacionados, CAD y Gráficos, incluyendo, pero no limitada a,
los temas siguientes: diseño, dibujo, ingeniería, modelado 2d y 3d, multimedia, sistemas, imagen raster,
trazado de rayos, rendering y animación 3d.
PCGnet esta diseñada para servir las necesidades de todos los visitantes estimulando el interés y
generando foros de soporte para usuarios activos qué tienen un interés en los temas relacionados al
CAD y los gráficos previamente mencionados; el interés y soporte se genera a través de las conferencias
de mensajes de PCGnet, compartiendo archivos a través de la red, noticias de la industria y boletines de
prensa. Las conferencias de mensajes de PCGnet son foros moderados diseñados acomodar discusiones
amistosas, y aun así profesionales e informativas sobre los asuntos relacionados con el CAD y los
gráficos.
TGA BBS sirve como eje central para una gran red de sistemas BBS orientados a los gráficos alrededor
del mundo. La siguiente es una descripción concisa de los nodos activos de PCGNet al momento qué
este documento fue escrito. El POV-Team no puede responder sobre la validez de esta información, ni
verificar qué cualquiera de estas BBS distribuyan POV-Ray.
EE.UU. y Canadá
411-Exchange Alpharetta GA 404-345-0008
Autodesk Global Village San Rafael CA 415-507-5921
CAD/Engineering Services Hendersonville TN 615-822-2539
Canis Major Nashville TN 615-385-4268
CEAO BBS Columbus OH 614-481-3194
CHAOS BBS Columbia MO 314-874-2930
Joes CODE BBS West Bloomfield MI 810-855-0894
John's Graphics Brooklyn Park MN 612-425-4436
PC-AUG Phoenix AZ 602-952-0638
SAUG BBS Bellevue WA 206-644-7115
Space Command BBS Kennewick WA 509-735-4894
The CAD/fx BBS Mesa AZ 602-835-0274
The Drawing Board BBS Anchorage AK 907-349-5412
The Graphics Alternative El Cerrito CA 510-524-2780
The Happy Canyon Denver CO 303-759-3598
Los New Graphics BBS Piscataway NJ 908-271-8878
The University Shrewsbury Twp NJ 908-544-8193
The virtual Dimension Oceanside CA 619-722-0746
Los libros listados abajo se han sido descatalogados recientemente, pero pueden encontrarse todavía en
algunas librerías o bibliotecas (Visita http://www.dnai.com:80waite/ para más detalles).
Ray Tracing Creations, 2d Ed.
Chris Young and Drew Wells
ISBN 1-878739-69-7
Waite Group Press, 1994
700 paginas con insertos en color y POV-Ray 2.2 en discos MS-DOS de 3.5".
Ray Tracing Worlds with POV-Ray
Alexander Enzmann, Lutz Kretzschmar, Chris Young
ISBN 1-878739-64-6
Waite Group Press, 1994
Incluye el modelador Moray 1.5x y POV-Ray 2.2 en discos MS-DOS de 3.5".
Ray Tracing for the Macintosh CD
Eduard Schwan
ISBN 1-878739-72-7
Waite Group Press, 1994
Viene con un CD-ROM lleno de escenas, imágenes, películas QuickTime, y una referencia de palabras
clave interactiva. También un disco flexible con POV-Ray para aquellos que no tienen un lector de CD-
ROM.
Es un buen recurso para aquellos qué están aprendiendo sobre POV-Ray, así como aquellos que ya
tienen experiencia, y contiene un tutorial interactivo basado en Windows. El disco viene con un poster
desplegable y una hoja de referencia. El CD es compatible con los formatos DOS/Windows y
Macintosh.
3. Comienzo rápido
La siguiente sección describe como instalar rápidamente POV-Ray y trazar escenas de ejemplo en tu
ordenador. Se asume que estás usando un ordenador compatible con IBM-PC con MS-DOS. Para otras
plataformas debes buscar la documentación específica incluida en el archivo que contiene POV-Ray.
[Ten en cuenta que usamos la palabra “directorio”. Tu sistema operativo puede que use otro término
(subdirectorio, carpeta, etc.)]
1) La forma chapucera: crea un directorio llamado POVRAY y copia todos los archivos de POV-Ray en
el. Edita y ejecuta todos los archivos y programas desde este directorio. Este método funciona, pero no
es el recomendado.
O la forma recomendada:
2) Crea un directorio llamado POVRAY y varios subdirectorios llamados INCLUDE, DEMO, SCENES, UTIL.
Los archivos autoextraíbles de algunas versiones del programa crean estos directorios por ti. Si los creas
tú mismo, el árbol de directorios debería quedar parecido a esto:
\--
|
+POVRAY --
|
+INCLUDE
|
+DEMO
|
+SCENES
|
+UTIL
Copia los ejecutables y la documentación al directorio POVRAY. Copia los archivos de inclusión estándar
en el subdirectorio INCLUDE. Copia las escenas de ejemplo en el subdirectorio SCENES. Y copia cualquier
utilidad relacionada con POV-Ray en el subdirectorio UTIL. Las escenas que crees irán en el
subdirectorio SCENES. También tendrás que añadir los directorios \POVRAY y \POVRAY\UTIL a tu “path”,
para que los programas puedan ser ejecutados desde cualquier directorio.
Ten en cuenta que algunos sistemas operativos no tienen soporte para múltiples trayectorias de
búsqueda.
El segundo método es un poco más complicado de poner a punto, pero es el preferido. Hay muchos
archivos asociados a POV-Ray que son mucho más fáciles de manejar cuando están separados en varios
directorios.
El propósito básico de POV-Ray es leer una descripción de una escena escrita en el lenguaje de POV y
escribir un archivo conteniendo la imagen. Estos archivos de escena son texto ASCII que puedes crear
usando un editor de texto. Con el paquete se incluyen docenas de archivos de ejemplo para ilustrar las
características.
Nota: los ejemplos en esta documentación asumen que has instalado POV-Ray en el directorio
C:\POVRAY3. El instalador te permitirá instalar POV-Ray en cualquier sitio y configurará el programa
para la unidad y directorio que especifiques. Simplemente sustituye esa unidad y directorio donde te
digamos que uses C:\POVRAY3. Cámbiate a ese directorio ahora. Luego teclea la siguiente línea de
comando y pulsa [ENTER}.
POVRAY +ISHAPES +D1
El parámetro +I (de input) le dice al programa que archivo debe leer como entrada. Si no le das una
extensión al nombre del archivo, se asume .POV. De modo que +Ishapes le dice que lea SHAPES.POV
para ser trazado.
El parámetro +D (de display) le dice al programa que active la previsualización gráfica. El parámetro -D
la desactivaría. El número “1” le dice que tipo de adaptador gráfico usar. El tipo “1” es el antiguo
adaptador estándar VGA a 320 por 200 puntos de resolución y 256 colores. Totalmente garantizado
que funcionará en cualquier tarjeta de vídeo VGA.
Hay otras opciones activas además de las que especificaste en la línea de comandos. Se guardan en un
archivo llamado POVRAY.INI que es creado por el programa de instalación. POV-Ray busca
automáticamente este archivo en el mismo directorio donde reside POVRAY.EXE. Mira las secciones
“Archivos INI” y “Usando los archivos INI” para obtener más información sobre POVRAY.INI y otros
archivos INI.
Al ejecutar el comando anterior, verás aparecer brillantes formas geométricas a medida que POV-Ray va
calculando el color de cada pixel línea a línea. Probablemente estarás descontento con el resultado
gráfico. Esto es debido a que es únicamente una previsualización. La imagen actual contiene 24 bits de
color pero no se puede mostrar tan alta calidad usando una simple tarjeta VGA con un conjunto de 256
colores fijos. Si tu hardware soporta el interface estándar VESA o si tienes un controlador VESA
instalado, prueba a ejecutar con el parámetro +DG en lugar de +D1. Esto te dará acceso a los varios
modos que tu tarjeta de vídeo puede usar. Si tienes capacidad para color de 15 o 16 bits prueba +DGH,
o si tienes capacidad para color de 24 bits prueba +DGT para ver la imagen en todo su esplendor.
Consulta la sección “Tipos de visualización” más adelante para obtener más información sobre la
previsualización gráfica.
PERSISTENCE OF VISION RAYTRACER 27
Cuando el programa termine oirás unos pitidos. Después de admirar la imagen pulsa [ENTER]. Verás
una pantalla de texto con estadísticas. Si el texto es demasiado largo para caber en la pantalla puedes
pulsar las teclas “cursor arriba” o “cursor abajo” para leer más texto. Fíjate en las pestañas que hay en la
parte inferior de la pantalla. Pulsa las teclas “cursor derecha” o “cursor izquierda” para leer otra
información interesante. Pulsa [ENTER] de nuevo para salir de POV-Ray.
PERSISTENCE OF VISION RAYTRACER 29
Las siguientes secciones explican las características de POV más o menos en el mismo orden en que
aparecen en el capítulo de Referencia.
Este tipo de sistema de coordenadas se llama "de mano izquierda". Si usas los dedos de tu mano
izquierda puedes ver fácilmente porque se llama así. Apunta el pulgar hacia la dirección positiva del eje
X, el dedo índice hacia la dirección positiva del eje Y, y el dedo medio hacia la dirección positiva del eje
Z. Sólo puedes hacer esto con la mano izquierda. Si hubieras usado la mano derecha no habrías sido
capaz de apuntar el dedo medio hacia la dirección correcta.
4. TUTORIAL PARA PRINCIPIANTES 30
La mano izquierda se puede usar también para determinar las direcciones de rotación. Para hacer esto
debes practicar el famoso ejercicio de Aerobic Infográfico. Toma tu mano izquierda, y apunta el pulgar
hacia la dirección positiva del eje de rotación. El resto de los dedos se curvarán en la dirección positiva
de rotación. Del mismo modo, si apuntas hacia la dirección negativa del eje, los dedos se curvarán sobre
la dirección negativa de rotación.
En la ilustración, la mano izquierda se curva sobre el eje X. El dedo pulgar apunta hacia la dirección
positiva del eje X y los dedos se curvan sobre la dirección positiva de rotación.
Si quieres usar un sistema de coordenadas de mano derecha, como hacen algunos sistemas de CAD
como AutoCAD, has de modificar el vector right en la especificación de la cámara. Mira la descripción
detallada en la sección "Sistemas de coordenadas levógiros y dextrógiros". En un sistema de mano
derecha debes usar tu mano derecha para el Aerobic.
Ten en cuenta que hay alguna controversia sobre si el método que usa POV-Ray para obtener un
sistema de coordenadas de mano derecha es realmente válido. Si quieres evitarte problemas te
sugerimos que uses el sistema de mano izquierda, sobre el que no hay disputa.
Sólo debes incluir aquellos archivos que realmente uses en tu escena. Algunos de los archivos de
inclusión que vienen con POV-Ray son bastante largos, y es mejor que ahorres memoria y tiempo de
interpretación si no los vas a usar. En los siguientes ejemplos solo vamos a usar COLORS.INC, FINISH.INC
y STONES.INC, así que mejor que quites el resto de las líneas de tu archivo de escena.
Puedes tener tantos archivos de inclusión como sea necesario. Los archivos de inclusión pueden incluso
contener a otros archivos, pero esto está limitado a diez niveles de profundidad.
Los nombres de archivos en las sentencias de inclusión se buscan primero en el directorio actual. Si no
se encuentran, se buscan en los directorios especificados por el parámetro +L o por la opción
Library_Path. Esto facilita el tener todos los archivos de inclusión en un directorio aparte, y especificar
con el parámetro +L donde se encuentran.
También look_at <0, 1, 2> rota la cámara hasta apuntar a las coordenadas <0, 1, 2>. Es decir, un
punto a 5 unidades enfrente de la cámara y 1 unidad más abajo que la cámara. El punto look_at es el
centro de atención de tu imagen.
El color que tu defines es el que tendrá el objeto cuando esté totalmente iluminado. Si estuvieras
haciendo un dibujo de una esfera usarías tonos oscuros para indicar las zonas sombreadas, y tonos
brillantes para indicar las zonas iluminadas. Sin embargo, el trazador se ocupa ya de eso. Tú eliges el
color inherente al objeto y POV-Ray lo aclara u oscurece dependiendo de la iluminación de la escena.
Como estamos definiendo el color que el objeto tiene en lugar del color aparente, el parámetro usado se
llama pigment.
Hay muchos tipos de distribuciones de color que se pueden usar en la sentencia pigment {...}. La
palabra clave color indica que todo el objeto es de un único color, en lugar de tener una distribución de
colores. Puedes usar uno de los colores definidos previamente en el archivo de inclusión colors.inc.
Si no hay un color estándar disponible para tus necesidades, puedes definir tu propio color usando la
palabra clave color seguida de red, green y blue, que especifican las cantidades de rojo, verde y
azul de que se compone el color. Por ejemplo, un bonito tono rosa se puede indicar como:
color red 1.0 green 0.8 blue 0.8
Los valores después de cada palabra han de estar comprendidos entre 0.0 y 1.0. Cualquiera de los tres
componentes no especificadas se toman como 0 por defecto. También se puede usar una notación más
corta. Lo siguiente también produce el mismo tono rosa:
color rgb <1.0, 0.8, 0.8>
Los colores se explican con más detalle en la sección "Especificando Colores".
camera {
location <0, 2, -3>
look_at <0, 1, 2>
}
sphere {
<0, 1, 2>, 2
texture {
pigment { color Yellow }
}
}
Esto es todo. Graba el archivo y traza una pequeña imagen con la orden
povray +w160 +h120 +p +x +d0 -v -idemo.pov
Si tu ordenador no usa la línea de comandos, consulta la documentación específica de tu plataforma
para ver como trazar la escena.
También puedes especificar otras opciones en la línea de comandos, si quieres. La escena será escrita al
archivo DEMO.TGA (o con otro sufijo si tu ordenador usa un formato por defecto diferente).
La escena que acabas de trazar no es ninguna obra de arte, pero tenemos que empezar por lo básico
antes de que exploremos características y escenas mucho más fascinantes.
#version 3.0
global_settings {
assumed_gamma 2.2 // para la mayoría de los monitores de PC
max_trace_level 5
}
pigment {NeonBlue}
}
plane { y, -1.0
pigment {
checker color Gray65 color Gray30
}
}
El ajuste de la apertura puede considerarse como el área enfocada. Aumentar la apertura tiene como
efecto el hacer más pequeña el área donde todo está enfocado, mientras de disminuirla hace que el área
enfocada sea mayor. Así es como controlamos donde comienza a desenfocarse la imagen alrededor del
punto focal.
El valor de blur_samples determina cuantos rayos se trazan para muestrear cada pixel. Básicamente,
cuantos más rayos se usen mayor será la calidad de la imagen, y consecuentemente mayor tiempo
tardará en trazarse. Cada escena es diferente, así que tendremos que experimentar. En este tutorial
tenemos ejemplos de 4 y 20 muestras, pero podemos usar más para imágenes de alta resolución. No
deberíamos usar más muestras que las necesarias para obtener la calidad deseada, porque más muestras
suponen más tiempo para el trazado. Los ajustes de confidencia y varianza están cubiertos en la sección
"Desenfoque".
Experimenta con el punto focal, la apertura y el valor del muestreo. La escena tiene líneas con varios
valores, y puedes probarlos comentando las líneas por defecto, y quitando el comentario a la línea que
quieras probar. Haz un cambio de cada vez para que puedas ver el efecto sobre la escena.
Dos cosas sobre el trazado de escenas con desenfoque. No necesitamos especificar antialias (el
parámetro +a) porque el desenfoque en sí ya es un método de sobremuestreo. El desenfoque sólo
puede usarse con la cámara de perspectiva (perspective camera).
PERSISTENCE OF VISION RAYTRACER 35
4.3.1. Caja
La caja es uno de los objetos más utilizados. Sustituyamos la esfera por el texto del siguiente ejemplo:
box {
<-1, 0, -1>, // Esquina delantera inferior izquierda
< 1, 0.5, 3> // Esquina trasera superior derecha
texture {
T_Stone25 // Predefinida en stones.inc
scale 4 // Escalamos en todas las direcciones el mismo factor
}
4.3.2. Cono
Aquí tenemos otro ejemplo mostrando cómo usar un cono.
cone {
<0, 1, 0>, 0.3 // Centro y radio de una base
<1, 2, 3>, 1.0 // Centro y radio de la otra base
4.3.3. Cilindro
Podemos definir también un cilindro como sigue:
cylinder {
<0, 1, 0>, // Centro de una base
4. TUTORIAL PARA PRINCIPIANTES 36
4.3.4. Plano
Probemos a crear un objeto típico de los gráficos por ordenador: el suelo ajedrezado. Añadimos el
objeto siguiente a la primera versión del archivo DEMO.POV, el que incluye la esfera.
plane { <0, 1, 0>, -1
pigment {
checker color Red, color Blue
}
}
El objeto definido aquí es un plano infinito. El vector <0, 1, 0> marca la dirección normal a la
superficie del plano (si estuviésemos de pie sobre la superficie, la dirección apuntaría desde nuestros
pies hacia nuestra cabeza). El número situado tras el vector marca la distancia a la que el plano está
situado del origen de coordenadas medido sobre la dirección normal. En este caso, el suelo está situado
en y=-1, una unidad por debajo del centro. Como la esfera tiene radio 2 y está centrada a una unidad de
altura, reposa sobre el suelo.
Observemos que, aunque no hay una declaración de textura, hay una textura implícitamente declarada
aquí. Teclear continuamente instrucciones anidadas del tipo de texture{pigment{....}} es muy
agotador, de forma que POV-Ray nos permite omitir la instrucción textura en muchas ocasiones. De
hecho, sólo deberemos usarla cuando englobemos una textura predefinida (como T_Stone25 del
ejemplo anterior), o cuando apilemos varias texturas (como veremos más adelante).
Este pigmento usa el patrón de color ajedrezado y especifica que los colores usados serán el rojo y el
azul.
Como los vectores <1, 0, 0>, <0, 1, 0> y <0, 0, 1> se usan frecuentemente, POV-Ray tiene tres
identificadores reservados (x, y, z) que se pueden usar como abreviatura. Así, un plano puede definirse
como
plane { y, -1
pigment { ... }
}
Observa que no usamos los símbolos < y > alrededor de los identificadores de vectores.
Mirando al suelo, descubrimos que la esfera produce una sombra en él. El trazador de rayos calcula las
sombras de forma muy precisa y esto crea sombras con bordes muy definidos. En el mundo real
habitualmente se aprecia una zona de penumbra o sombra "suave". Más adelante aprenderemos cómo
usar luces avanzadas para suavizar el borde de las sombras.
object {
UnitBox
texture { T_Stone25 scale 4 }
PERSISTENCE OF VISION RAYTRACER 37
scale 0.75
rotate <-20,25,0>
translate y
}
Debemos tener en cuenta que las formas definidas en adelante no son sencillas de entender. No
debemos preocuparnos por no saber usarlas, o no conocer su aspecto. Sólo probaremos unos ejemplos
que juegan con las características descrita más ampliamente en el capítulo de referencias. No hay nada
mejor para aprender que practicar.
4.4.2. Burbuja
Las burbujas se pueden describir como esferas y cilindros que tienden a fusionarse unos con otros
cuando están próximos. Ideales para modelar átomos y moléculas, estos objetos son también
herramientas poderosas que nos permiten crear variadas formas orgánicas.
Una manera más matemática de describir una burbuja es decir que es un objeto hecho de dos o más
componentes, de forma que cada componente se comporta como un campo de fuerza invisible que
comienza con una intensidad determinada y decae a cero a cierto radio. Donde esos campos se solapan,
sus intensidades se suman (algunos de esos componentes pueden tener intensidad negativa, también).
Lo que nosotros vemos de este objeto es la superficie en la que esa intensidad es igual a un determinado
valor. Por supuesto, podemos tener un solo componente en una burbuja, pero su aspecto es idéntico a
una esfera (o a un cilindro, si ésa es la forma del campo). La verdadera belleza de este objeto es la forma
en la que unos componentes interactúan con los otros.
Tomemos un ejemplo simple de burbuja para empezar. Para simplificar este primer ejemplo, sólo
usaremos componentes esféricos. Escribamos el siguiente código, compuesto de una cámara sencilla,
luz, y una burbuja con sólo dos componentes. Esta escena se llama BLOBDEM1.POV:
#include "colors.inc"
camera {
angle 15
location <0,2,-10>
look_at <0,0,0>
}
blob {
threshold .65
sphere { <.5,0,0>, .8, 1 pigment {Blue} }
sphere { <-.5,0,0>,.8, 1 pigment {Pink} }
finish { phong 1 }
}
4. TUTORIAL PARA PRINCIPIANTES 38
Observemos que el componente esférico parece una esfera. De hecho, indicamos su centro y su radio.
Pero ¿qué es el último valor numérico? Es la intensidad de ese componente, el valor que alcanza en su
centro. Decae siguiendo una progresión lineal hasta alcanzar el valor cero exactamente a una distancia
igual al radio de la esfera.
Antes de trazar esta imagen, observemos que le hemos dado a cada componente una pigmentación
distinta. POV-Ray permite que los componentes tengan distintas texturas. Hemos hecho esto para dejar
claro cuál es cada componente en la imagen. También podemos aplicar texturas al final, lo que afectará
a todos los componentes, como el acabado indicado en el ejemplo, fuera de ambas esferas. Cuando
tracemos la imagen, encontraremos una burbuja típica formada por dos esferas unidas.
La imagen que vemos muestra una esfera en cada lado, pero están suavemente unidas por una sección
puente en el centro. Este puente representa dónde los campos se solapan, por lo que su intensidad
aumenta con respecto a lo que valdría si sólo hubiese un componente. Por si esto no está totalmente
claro, añadiremos dos objetos más y la trazaremos de nuevo (archivo BLOBDEM2.POV). Observa que las
dos nuevas esferas se introducen como un objeto a parte, no como componentes de la burbuja.
sphere { <.5,0,0>, .8
pigment { Yellow transmit .75 }
}
sphere { <-.5,0,0>, .8
pigment { Green transmit .75 }
}
PERSISTENCE OF VISION RAYTRACER 39
Ahora el secreto de las dos esferas unidas se pone de manifiesto. Estas esferas semitransparentes
muestran dónde están realmente las componentes de la burbuja. Si no hemos trabajado nunca con este
tipo de objetos quizá nos sorprenda que las esferas se extiendan mucho más allá de donde vemos
nosotros realmente los componentes. Esto es debido a que lo que muestran las superficies de las esferas
es dónde la fuerza de los campos llega a cero, mientras que la burbuja marca dónde esta intensidad es
igual a 0.65. El resto de la esfera es exterior a la burbuja y, por tanto, no es visible.
¿Ves dónde se solapan ambas esferas? Observa que se corresponde precisamente con el "puente" entre
las dos esferas. Esta es la región donde la intensidad de ambos componentes está contribuyendo a la
intensidad total, por lo que el puente aparece así: una región en la que la intensidad supera el valor de
umbral (0.65), debido a que se combina la de las dos esferas.
Antes de empezar con los cilindros, deberíamos mencionar que la forma clásica de enunciar las
componentes de anteriores versiones de POV-Ray aún sirve. Entonces, todas las componentes eran
esféricas, de forma que no era necesario citar su forma. La forma clásica tiene el siguiente aspecto:
component intensidad, radio,
Esto tiene el mismo efecto que un componente esférico, como los que hemos mostrado antes. Esto
sólo se mantiene por compatibilidad. Si tenemos archivos de POV-Ray de anteriores versiones, lo
necesitaremos para que reconozca las componentes. Observa que el estilo clásico no pone llaves
encerrando la intensidad, el radio y el centro, y, por supuesto, no podemos aplicarles individualmente
texturas o transformaciones. De manera que si estás modificando un trabajo antiguo, tal vez sea
interesante cambiar la sintaxis a la actual para conseguir algunas ventajas.
4. TUTORIAL PARA PRINCIPIANTES 40
Ahora intentemos crear algo con las componentes cilíndricas. Se podría argumentar que podríamos
hacer un cilindro con una burbuja, usando algunas componentes esféricas alineadas. Esto es cierto, pero
sería delicado calcular el valor de los centros, y deberíamos teclear mucho más.
Sustituye la burbuja del último ejemplo con lo siguiente y trázalo. Podemos borrar las esferas
transparentes también.
blob {
threshold .65
pigment { Blue }
finish { phong 1 }
}
Tenemos sólo un componente cilíndrico para que veamos el aspecto que tiene aislado. No es realmente
un cilindro, pues acaba en dos semiesferas. Podemos pensar en él como una esfera alargada en cierta
dirección.
En cuanto a la sintaxis, es lo que podíamos esperar: el cilindro está descrito como los cilindros
anteriormente vistos: dos vectores que indican los centros de sus bases y un valor que indica el radio. El
otro número, por supuesto, indica la intensidad del campo en el centro del cilindro. Este valor indica
cómo interactúa con otras componentes, si tiene alguna con la que interactuar.
camera {
angle 20
location<0,2,-10>
look_at<0,0,0>
}
blob {
threshold .65
pigment { Flesh }
}
Como podemos ver por los comentarios, estamos construyendo una mano. Cuando tracemos esta
imagen, veremos que hay ciertos problemas con esta. La palma y la parte baja se pueden hacer más
realistas si usamos una docena de componentes pequeñas en lugar de media docena de componentes
grandes, y cada dedo debería tener tres segmentos en lugar de dos, pero como ejemplo nos sirve. Sin
embargo, hay una cosa que realmente debemos añadir: los dedos aparecen unidos por una especie de
membrana.
Una revisión de lo que sabemos de las burbujas nos revela rápidamente qué sucede. Esta membrana
está formada por lugares donde las componentes se solapan, por lo que la intensidad de las
componentes se suma y la superficie se extiende hacia ellos. Lo que necesitamos es añadir aquí algunas
componentes más que tengan intensidad negativa y contrarresten parte de la intensidad combinada.
Añadiremos las siguientes componentes a nuestro objeto (ver archivo BLOBDEM4.POV):
sphere { <-.65,.28,-.05>, .26, -1 } //anula el bulto del nudillo del meñique
sphere { <-.65,-.28,0>, .26, -1 } //anula el bulto de la palma junto al
meñique
global_settings {
assumed_gamma 2.2
hf_gray_16
}
La palabra clave hf_gray_16 hace que la salida sea codificada de un modo especial (16 bits en escala
de grises) que es ideal para generar campos de alturas. Las superficies construidas con 8 bits son mucho
menos suaves, ya que se trabaja con menos alturas diferentes (256 frente a 65536 de los 16 bits).
Ahora situamos una cámara que apunta desde la parte negativa del eje z al origen.
camera {
location <0, 0, -10>
look_at 0
}
Después, situamos un plano como un muro en z=0, que llenará totalmente la pantalla. Lo coloreamos
con manchas con forma de arrugas grises sobre fondo blanco.
plane { z, 10
pigment {
wrinkles
PERSISTENCE OF VISION RAYTRACER 43
color_map {
[0 0.3*White]
[1 White]
}
}
}
Finalmente, añadiremos una luz.
light_source { <0, 20, -100> color White }
Trazamos esta escena con las opciones +h480 +w640 +a0.1 +fT. Obtendremos una imagen que
producirá un excelente campo de alturas. Creamos ahora un archivo llamado HFDEMO.POV y escribimos
en él lo siguiente:
#include "colors.inc"
Añadimos una cámara dos unidades sobre el origen y diez unidades por detrás...
camera{
location <0, 2, -10>
look_at 0
angle 30
}
... y una luz.
light_source{ <1000,1000,-1000> White }
Ahora añadimos el campo de alturas. En la sintaxis siguiente se especifica que usamos un archivo Targa,
que se suaviza el cambio entre alturas, se colorea de blanco, y se traslada para centrarlo en el origen y
escalarlo de forma que simule montañas y llene la pantalla.
height_field {
tga "image.tga"
smooth
pigment { White }
translate <-.5, -.5, -.5>
scale <17, 1.75, 17>
}
Guardamos el archivo y trazamos a 320 por 240, sin antialias (-a). Después, si estamos satisfechos con
el resultado, probaremos a crear una imagen de mayor resolución y con antialias.
Aquí incluimos algo de código para crear una pieza torneada muy sencilla (llamada LATHDEM1.POV).
#include "colors.inc"
camera {
angle 10
location <1, 9, -50>
look_at <0, 2, 0>
}
light_source {
<20, 20, -20> color White
}
lathe {
linear_spline
6,
<0,0>, <1,1>, <3,2>, <2,3>, <2,4>, <0,4>
pigment { Blue }
finish {
ambient .3
phong .75
}
}
Trazamos esto, y lo que veremos es un objeto muy sencillo, similar a una peonza. Veamos cómo este
código produce dicho efecto.
Primero, se declaran seis puntos que el programa conecta con líneas. Observa que sólo indicamos dos
componentes en los vectores que describen esos puntos. Se asume que las líneas están trazadas sobre el
plano x-y, como si la tercera componente fuese siempre cero. Es obligatorio usar vectores de dos
PERSISTENCE OF VISION RAYTRACER 45
componentes (usar vectores de tres componentes ocasionará un error, excepto en un caso que
exploraremos posteriormente, relacionado con la discusión de las curvas spline).
Una vez que las líneas están determinadas, podemos imaginar que el trazador de rayos gira esta línea
alrededor del eje y, dejando la forma del objeto al paso de la línea (realmente, es como si cortara sobre
un cilindro de material azul usando esta línea de patrón, y descartara todo lo que queda en el exterior de
ésta).
Los puntos especificados están unidos por trazos rectos porque usamos la clave linear_spline. Hay
otros tipos de curvas permitidas para este fin, que producen curvas más suaves, redondeando las
transiciones entre un trazo y otro, pero volveremos a hablar de ello dentro de un momento.
Primero, estudiemos la diferencia entre un objeto torneado y una superficie de revolución (sor). La
superficie de revolución, descrito en un tutorial aparte, es terriblemente similar a primera vista. También
declara una serie de puntos, los une mediante líneas y después rota el resultado alrededor del eje y. El
objeto torneado tiene ciertas ventajas, como diferentes tipo de trazos de unión (lineales, cuadráticos y
cúbicos) y algo más.
Las sencillas matemáticas usadas en un SOR no permiten que la curva se doble y tome por dos veces el
mismo valor de y, es decir, que todo intento de que un objeto SOR se curve hasta volver a tomar la
misma altura produce un error. Por ejemplo, supongamos que queremos tornear una curva que sube de
<0, 0> hasta <2, 2>, y después baja hasta <4, 0>. Girado en torno al eje y, esto produciría algo similar
a un molde para gelatina (un semitoro), hundido en el centro. Sin embargo, en un SOR, el intento dará
un mensaje de error debido a intentar curvarse en la dirección equivocada.
Sin embargo, los objetos SOR utilizan matemática de inferior orden, por lo que su cálculo es más rápido
que el equivalente objeto torneado. De manera que es preferible usar un objeto SOR si sus limitaciones
no nos afectan, pero si necesitamos tornear de una forma más flexible, sólo podemos utilizar un objeto
torneado.
camera {
orthographic
up <0, 5, 0>
right <5, 0, 0>
location <2.5, 2.5, -100>
look_at <2.5, 2.5, 0>
}
finish { ambient 1 }
}
lathe {
linear_spline
5,
Red_Point,
Orange_Point,
Yellow_Point,
Green_Point,
Blue_Point
pigment { White }
finish { ambient 1 }
}
Ahora, retomamos el aliento. Vemos que tiene una apariencia un poco rara, pero con algunas simples
explicaciones, podemos ver fácilmente qué es lo que hace todo esto.
En primer lugar decir que estamos usando la cámara ortográfica. Si aún no hemos leído nada sobre ella,
aquí hay un breve resumen: traza la escena plana, eliminando la distorsión de la perspectiva para que en
PERSISTENCE OF VISION RAYTRACER 47
una vista lateral, los objetos tengan la misma apariencia que si hubieran sido dibujado en un plano de
papel (como en la vista lateral de un modelador o programa de CAD). Hay varios usos para este
práctico nuevo tipo de cámara, pero aquí nos permitirá ver nuestro torno y cilindros como si fueran una
sección transversal de la curva que forma el torno, más que el torno en sí mismo. Para reforzar el efecto
hemos eliminado el sombreado con el acabado ambient 1 que, en efecto también elimina la necesidad
de una fuente de luz. También hemos posicionado esta particular vista lateral para que el punto <0, 0>
aparezca en la esquina inferior izquierda de nuestra escena.
A continuación hemos declarado un conjunto de puntos. Nótese que hemos usado vectores de tres
componentes para estos puntos, en lugar de los vectores de dos que solemos usar en un torno. Esta es
una excepción que ya mencionamos antes. Cuando declaramos un punto 3D y lo usamos en un torno,
este solo usa las dos primeras componentes del vector y la tercera componente es ignorada. Esto es
práctico aquí, ya que hace posible este ejemplo.
Ahora hacemos dos cosas con los puntos declarados. Primeros los usamos para colocar cilindros de
pequeño diámetro con las bases apuntando a la cámara. Entonces volvemos a usar esos mismos
vectores para determinar el torno. Ya que intentar declarar vectores en 2D puede ocasionar resultados
no esperados y no es lo que necesitan nuestras declaraciones de cilindros, podemos aprovechar la
tendencia del torno a ignorar la tercera componente poniendo la coordenada z a 0 en los vectores en
3D.
El resultado final es: cuando trazamos este código, vemos un torno de color blanco contra un fondo
negro mostrándonos la forma de la curva que hemos declarado y las bases circulares de los cilindros nos
muestran nuestros puntos de control sobre el plano xy. En este caso, es muy simple. La spline lineal ha
sido usada de forma que nuestra curva está compuesta por una serie de líneas conectando los puntos.
Ahora cambiamos las declaraciones de Red_Point y Blue_Point de la siguiente forma (ver fichero
LATHDEM3.POV).
Trazamos de nuevo y lo que podemos ver es que los segmentos rectos se han movido para acomodarse
a las nuevas posiciones de los puntos rojo y azul.
Vamos a intentar algo distinto. Primero cambiamos los puntos por estos otros (ver fichero
LATHDEM4.POV).
4. TUTORIAL PARA PRINCIPIANTES 48
Bien, mientras que cualquier pareja de puntos puede determinar una línea recta, se necesitan tres para
determinar una curva cuadrática. POV-Ray no solo tiene en cuenta los dos puntos a ser conectados, si
no también el punto que los precede para determinar la fórmula de la curva cuadrática que será usada
para conectarlos. El problema está al principio de la curva. Más allá de su primer punto no hay punto
previo. Así que necesitamos declarar uno. Por lo tanto, cuando se usa una spline cuadrática, debemos
recordar que el primer punto que especificamos solo está allí para que POV-Ray pueda determinar la
curva para conectar los dos primeros puntos. No se mostrará como parte de la curva.
Solo hay una cosa más acerca de este ejemplo. A pesar de que nuestra curva está formada ahora por
líneas redondeadas, las transiciones entre estas líneas son... bueno, un poco picadas. Parece que las
líneas hubieran sido conectadas en los puntos de forma equivocada. Dependiendo de lo que intentemos
hacer, esto puede ser aceptable, o podemos desear una forma más redondeada. Afortunadamente
tenemos otra opción.
La spline cuadrática necesita más tiempo de trazado que la lineal. La fórmula matemática es más
compleja. Más tiempo necesita aún la spline cúbica, aunque para una figura realmente redondeada, esta
es la única opción. Volvemos a nuestro ejemplo y reemplazamos quadratic_spline por
cubic_spline (ver archivo LATHDEM5.POV). Trazamos una vez más y vemos lo que tenemos.
PERSISTENCE OF VISION RAYTRACER 49
Mientras que una spline cuadrática necesita tres puntos para determinar la curva, una cúbica necesita
cuatro. Así que, como esperábamos, el punto azul ha dejado de formar parte de la curva, como antes
pasó con el punto rojo. Ahora el primer y el último punto de la curva son solo puntos de control para
determinar las curvas entre los restantes puntos. Pero echemos un vistazo a las transiciones desde el
punto naranja hasta el punto amarillo y después hasta el verde. Ahora, en lugar de parecer equivocados,
los segmentos forman una sola y completamente redondeada curva.
El concepto de las splines es algo útil y necesario, que se volverá a ver de nuevo en los objetos prisma y
polígono. Con un poco de práctica podemos aprenderlo a usar rápidamente.
Casi todos los objetos se pueden aproximar usando triángulos, pero necesitaríamos muchos triángulos
para crear formas complejas. De modo que crearemos una malla muy simple como ejemplo. Este
ejemplo nos mostrará además una característica muy útil de las mallas de triángulos: se puede aplicar
una textura diferente a cada triángulo.
Comencemos. Crearemos una simple caja con caras de diferente color. Crea un archivo llamado
MESHDEMO.POV y añade las siguientes líneas:
camera {
location <20, 20, -50>
look_at <0, 5, 0>
}
Ahora añadimos la malla. Tres caras de la caja usarán textura individual, mientras que las otras tres
usarán la textura global de la malla.
mesh {
/* top side */
triangle { <-10, 10, -10>, <10, 10, -10>, <10, 10, 10>
texture { Red }
}
triangle { <-10, 10, -10>, <-10, 10, 10>, <10, 10, 10>
texture { Red }
}
/* bottom side */
triangle { <-10, -10, -10>, <10, -10, -10>, <10, -10, 10> }
triangle { <-10, -10, -10>, <-10, -10, 10>, <10, -10, 10> }
/* left side */
triangle { <-10, -10, -10>, <-10, -10, 10>, <-10, 10, 10> }
triangle { <-10, -10, -10>, <-10, 10, -10>, <-10, 10, 10> }
/* right side */
triangle { <10, -10, -10>, <10, -10, 10>, <10, 10, 10>
texture { Green }
}
triangle { <10, -10, -10>, <10, 10, -10>, <10, 10, 10>
texture { Green }
}
/* front side */
triangle { <-10, -10, -10>, <10, -10, -10>, <-10, 10, -10>
texture { Blue }
}
triangle { <-10, 10, -10>, <10, 10, -10>, <10, -10, -10>
texture { Blue }
}
/* back side */
triangle { <-10, -10, 10>, <10, -10, 10>, <-10, 10, 10> }
triangle { <-10, 10, 10>, <10, 10, 10>, <10, -10, 10> }
texture {
pigment { color rgb<0.9, 0.9, 0.9> }
finish { ambient 0.2 diffuse 0.7 }
}
}
Trazando la escena a 320x240 veremos que la cara superior, la derecha y la frontal tienen diferente
textura. De acuerdo que este no es un ejemplo impresionante de lo que podemos hacer con las mallas.
Puedes encontrar ejemplos más complejos, usando triángulos suavizados, en el directorio de escenas
con los nombres CHESMSH.POV y ROBOTMSH.POV.
4.4.6. Polígono
El objeto polígono se puede usar para crear formas planas de n lados, como cuadrados, rectángulos,
pentágonos, hexágonos, octógonos, etc.
PERSISTENCE OF VISION RAYTRACER 51
Un polígono se define por un determinado número de puntos que describen su forma. Como los
polígonos han de ser cerrados, el primer punto y el último deben coincidir.
Comenzaremos considerando los puntos que necesitamos para describir la forma deseada. Queremos
que las letras se encuentren sobre el plano x-y, con la letra O en el centro. Las letras se extienden desde
y=0 hasta y=1. De modo que tenemos los siguientes puntos para cada letra (la coordenada z se pone
automáticamente a 0).
Letra P (polígono externo):
<-0.8, 0.0>, <-0.8, 1.0>,
<-0.3, 1.0>, <-0.3, 0.5>,
<-0.7, 0.5>, <-0.7, 0.0>
Letra V:
<0.45, 0.0>, <0.30, 1.0>,
<0.40, 1.0>, <0.55, 0.1>,
<0.70, 1.0>, <0.80, 1.0>,
<0.65, 0.0>
Las letras P y O tienen un agujero, mientras que la letra V consiste sólo en un polígono. Empezaremos
por la letra V ya que es la más fácil de definir.
polygon {
8,
Después de crear la letra V continuaremos con la letra P. Como tiene un agujero hemos de encontrar
una manera de recortar este agujero de la forma original. Esto es muy fácil. Definimos la forma externa
de la letra P, que es un polígono cerrado, y añadimos la secuencia de puntos que definen el agujero, que
también es un polígono cerrado. Así tendremos un agujero en donde los dos polígonos se solapen.
En general obtendremos agujeros siempre que un número par de subpolígonos se solapen en una única
sentencia de polígono. Un subpolígono está definido por una secuencia cerrada de puntos.
La letra P consiste en dos subpolígonos, uno para la forma exterior y el otro para el agujero. Como el
polígono del agujero solapa al polígono externo, tendremos un agujero.
Una vez que sabemos como funcionan varios subpolígonos dentro de una única sentencia de polígono,
es bien fácil añadir la letra O.
4.4.7. Prisma
Un prisma es esencialmente un polígono o una curva cerrada barrida a lo largo de una trayectoria recta..
Podemos imaginarnos la figura como la superficie que dejaría la curva al arrastrarla por el espacio. La
curva o polígono que define un prisma puede estar formada por cualquier número de subformas, puede
usar cualquiera de los tres tipos de curvas spline, y puede incluso mantener una anchura constante a lo
largo del barrido o ir estrechándose lentamente hasta acabar en un punto. Pero antes de que todo esto
comience a ser confuso, vamos a ir paso a paso con la forma más simple de prisma. Tecleamos y
trazamos el siguiente trozo de código, (ver PRISMDM1.POV)
#include "colors.inc"
camera {
angle 20
location <2, 10, -30>
look_at <0, 1, 0>
}
prism {
linear_sweep
linear_spline
0, // barrer la siguiente curva desde aquí ...
1, // ... hasta aquí
7, // el número de puntos que forman la curva ...
pigment { Green }
}
4. TUTORIAL PARA PRINCIPIANTES 54
Esto produce un hexágono, que es barrido desde y=0 hasta y=1. En otras palabras, ahora tenemos un
hexágono con grosor. Un punto a tener en cuenta es que aunque esta sea una figura de seis caras,
hemos usado en total siete puntos. Esto es debido a que el polígono se supone que es cerrado, lo cual
hacemos que el último punto coincida con el primero. Técnicamente, con polígonos lineales, si no
hacemos esto POV-Ray uniría automáticamente los dos extremos con una línea para forzar el cerrado,
aunque nos daría una advertencia. Sin embargo, esto sólo funciona con splines lineales, así que no
debemos pasar por alto estos mensajes de advertencia.
Solo hay una cosa tener en cuenta y deberíamos leer esta sección con cuidado para no acabar tirándonos
de los pelos debido a misteriosos mensajes de que nos hacen falta puntos y que nos impiden renderizar
el prisma. Podemos adivinar a donde nos lleva todo esto: como cerrar una spline no lineal.
A diferencia de una spline lineal, que simplemente dibuja una línea entre el primer y último punto si
olvidamos hacer que estos sean el mismo, las splines cuadráticas y cúbicas son un poco más exigentes.
Antes que nada, recordemos que las splines cuadráticas determinan la ecuación de la curva que conecta
dos puntos cualesquiera basándose en esos dos puntos y el punto previo, de manera que el primer
punto en cualquier spline cuadrática es tan solo un punto de control y no será parte de la curva. Lo que
esto significa es: cuando construimos nuestra figura a partir de una spline cuadrática, debemos igualar el
segundo punto con el último, ya que el primer punto no está sobre la curva, solo es un punto de control
necesario por motivos computacionales.
Igualmente, las splines cúbicas necesitan que el primer y último punto sea un punto de control, por lo
tanto, para cerrar una figura construida a partir de una spline cúbica debemos igualar el segundo punto
con el penúltimo. Si no igualamos los puntos correctos en una figura cuadrática o cúbica, entonces
recibiremos los mensajes de error que nos idican que necesitamos más puntos para definir el prisma.
PERSISTENCE OF VISION RAYTRACER 55
POV-Ray espera que nosotros cerremos la figura y cuando termina de procesar todos los puntos sin
encontrar el cierre, se produrce un error.
¿ Confuso? ¿Qué tal un ejemplo? Reemplazamos el prisma en nuestro último fragmento de código por
este (ver archivo PRISMDM2.POV).
prism {
cubic_spline
0, // levantar la figura desde aqui ...
1, // ... hasta aqui
6, // el numero de puntos que formaran la figura ...
pigment { Green }
}
Este simple prisma produce lo que parece un triangulo grueso con sus vértices redondeados. Los
puntos dos, tres y cuatro son los vertices del triángulo y el punto cinco cierra la figura volviendo a la
posición del punto dos. En lo que respecta a los puntos uno y seis, son nuestros puntos de control y no
forman parte de la figura. Están allí para ayudar a computar que curvas serán usadas entre los otros
puntos.
Para generalizar, si queremos un cierre suave de una spline cúbica, hacemos que el primer punto de
control sea igual al tercero empezando por el final. Para una spline cuadrática el truco es similar, pero,
ya que solamente el primer punto es un punto de control, hay que hacer que sea igual al penúltimo
punto.
pigment { Green }
}
Por motivos de legibilidad, hemos empezado una nueva línea cada vez que cambiamos a la siguiente
subforma, pero el trazador de rayos determina donde termina cada subforma basándose en el cierre de
las figuras (como fue descrito antes). Renderizamos el nuevo prisma y vemos lo que tenemos. Es la
misma y familiar forma de antes, pero ahora parece que una pequeña versión de la forma haya sido
extraída del centro y dentro del espacio vacío haya sido colocada otra versión todavía más pequeña.
Simplemente, la región exterior está formada por la subforma #1, el agujero excavado es donde las
subforma #1 y la subforma #2 se superponen. En el centro el objeto reaparece debido a que las
PERSISTENCE OF VISION RAYTRACER 57
<4,4>,<-4,4>,<-4,-4>,<4,-4>,<4,4>
El pigmento gradiente fue seleccionado para dar algo de definición a nuestro objeto sin tener que fijar
las fuentes de luz y el ángulo de la cámara, pero cuando lo trazamos, ¿qué es lo que hemos creado?,
¡Una pirámide rayada horizontalmente! Por ahora podemos reconocer la spline lineal conectando los
cuatro puntos de un cuadrado y el familiar punto final que cierra la spline.
Notemos todas las transformaciones en la declaración del objeto. Esto va a necesitar una serie de
explicaciones. La rotación y la traslación son fáciles de entender. Normalmente, un barrido cónico
empieza con el máximo tamaño en la parte superior y se va estrechando hasta un punto en y=0, pero
por supuesto esto seria al reves si estamos haciendo una pirámide. Así que giramos el objeto respecto al
4. TUTORIAL PARA PRINCIPIANTES 58
eje x para colocarlo correctamente. Entonces, ya que hemos rotado respecto al vertice, trasladamos el
objeto hacia arriba para ponerlo en la misma posición en la que estaba cuando empezamos.
El escalado sirve para adecuar las proporciones a este ejemplo. La base mide ocho unidades por ocho
unidades, pero la altura (desde y=1 hasta y=0) es solode una unidad, así que la estiramos un poco.
Llegados a este punto, probablemente estaremos pensando, “¿Por que no simplemente hacer el barrido
desde y=0 hasta y=4 y evitar este escalado?”
Este es un error frecuente con los barridos cónicos. Para ver lo que está mal, pongámoslo en práctica
(ver archivo PRISMDM6.POV). Debemos asegurarnos de quitar el escalado y reemplazar la siguiente línea
1, // altura 2
por
4, // altura 2
Esto sitúa la segunda altura a y=4, así que rendericemos de nuevo y veamos si el efecto es el mismo.
Figura 18: Escogiendo una segunda altura mayor que uno para el
barrido cónico
Vaya... La altura es correcta, pero la base de nuestra pirámide es enorme. ¿Qué es lo que ha ido mal?
Simple, la base, tal como la hemos descrito con los puntos que hemos usado, está situada en y=1 sin
importar donde hayamos situado la segunda altura. Pero si definimos la segunda altura mayor que uno,
una vez que el barrido ha pasado por y=1, continua expandiendo el objeto a lo largo de las mismas
líneas que ha seguido hasta la base original, haciendo que la nueva base sea cada vez más grande.
Para evitar perder el control de un prisma construido a partir de un barrido cónico, es mejor dejar la
segunda altura en y=1 y hacer un escalado para ajustar la altura desde su tamaño unitario. De esta forma
siempre podremos estar seguros de que las esquinas de la base permanecen donde creemos que deben
estar.
Esto nos lleva a otro punto interesante acerca de los barridos cónicos. ¿Qué pasa si, por alguna razón,
no queremos que el estrechamiento llegue a un único punto? ¿Qué pasa si en lugar de una pirámide
completa, lo que queremos es algo mas parecido a un zigurat escalonado? Nada más fácil. Después de
poner la segunda altura otra vez a uno y poner de nuevo el escalado, cambiamos la siguiente línea
0, // altura 1
PERSISTENCE OF VISION RAYTRACER 59
por
0.9, // altura 1
Cuando trazamos de nuevo, vemos que el barrido termina poco antes de llegar al vértice, mostrándonos
una pirámide sin punta. La altura a la que es cortada la pirámide depende de lo cerca que esté la primera
altura de la segunda.
Para la siguiente prueba, intenta <1, 0.2>. La forma parece un cilindro, aunque los bordes de las caras
están redondeados.
4. TUTORIAL PARA PRINCIPIANTES 60
Intentémoslo ahora con <0.1, 1>. Es difícil describir esta figura, pero es interesante.
Finalmente, probemos <1, 1>. Bueno, esto es más familiar... ¡una esfera!
Debemos tener en cuenta algunas cosas para usar los superelipsoides. En primer lugar, no debemos
usar el valor cero para ninguno de los dos parámetros. Esto causaría el dibujo de una caja negra en lugar
de nuestra figura. En segundo lugar, valores muy próximos a cero de r y n producen resultados muy
extraños, así que es conveniente evitarlos. Finalmente, el método Sturm para resolver ecuaciones no
funcionará con estas figuras.
Los superelipsoides son objetos finitos, de forma que responden bien al encapsulado automático
(método que permite acelerar el cálculo de imágenes, evitando la necesidad de usar la instrucción
bounded_by). Pueden usarse bien en composición de objetos (CSG, uniones e intersección).
Ahora, usemos esta figura para hacer algo útil en una escena. Haremos un suelo agrupando varios,
usándolos como baldosas, y situaremos un puñado de ellos flotando encima. Podemos empezar con el
archivo anterior.
camera {
location <10, 5, -20>
look_at 0
angle 15
}
Para completar la escena, añadimos cinco superelipsoides diferentes, cada uno de un color, de forma
que floten sobre las baldosas reflejándose en ellas.
superellipsoid {
<0.1, 1>
pigment { Red }
translate <5, 3, 0>
scale .45
}
superellipsoid {
<1, 0.25>
pigment { Blue }
translate <-5, 3, 0>
scale .45
}
superellipsoid {
<0.2, 0.6>
pigment { Green }
translate <0, 3, 5>
scale .45
}
superellipsoid {
<0.25, 0.25>
pigment { Yellow }
translate <0, 3, -5>
scale .45
}
superellipsoid {
<1, 1>
pigment { Pink }
translate y*3
scale .45
}
Trazamos la escena a 320x 200 para ver el resultado. Si estamos contentos con él, la imagen final
podemos crearla a 640x480 y con antialias 0.2.
Empezamos pensando la forma del objeto final. Es bastante difícil obtener los puntos que describen
una curva dada sin la ayuda de un programa modelador que soporte este tipo de objetos. Si tal
programa está disponible podemos sacar mucho partido de él.
Usaremos la configuración de puntos que muestra la figura anterior. Hay ocho puntos que describen la
curva que será rotada alrededor del eje y para obtener la copa. La curva se calcula usando el método
descrito en la sección de referencia (ver "Superficie de Revolución").
camera {
location <10, 15, -20>
look_at <0, 5, 0>
angle 45
}
plane { y, 0
pigment { checker color Red, color Green scale 10 }
}
sor {
4. TUTORIAL PARA PRINCIPIANTES 64
8,
<0.0, -0.5>,
<3.0, 0.0>,
<1.0, 0.2>,
<0.5, 0.4>,
<0.5, 4.0>,
<1.0, 5.0>,
<3.0, 10.0>,
<4.0, 11.0>
texture { T_Gold_1B }
}
Esta escena contiene nuestra copa sobre un plano ajedrezado. Trazar la escena a una resolución de
320x200 produce la imagen siguiente:
La superficie de revolución se describe escribiendo, en primer lugar, el número de puntos, seguido por
los puntos en orden ascendente de altura. Cada punto determina el radio de la curva a una altura
determinada. Por ejemplo, el primero de ellos le dice a POV-Ray que a una altura de -0.5 el radio es 0.
Podemos observar que cada punto tiene una altura mayor que su predecesor. Si no se hace así el
programa se detendrá con un error.
4.4.10. Texto
Crear texto usando POV-Ray solía significar que las letras había que construirlas usando composición
de objetos (CSG), un proceso bastante pesado, o usando una imagen en blanco y negro de las letras
como campo de alturas, un método que no siempre es satisfactorio. Ahora, en POV-Ray 3.0, se ha
introducido un nuevo tipo de objeto que permite usar cualquier fuente de tipo True Type para crear
objetos de texto. Estos objetos se pueden usar en composición y transformarse en posición, tamaño y
apariencia como cualquier otra primitiva de POV-Ray.
En este tutorial haremos dos usos de este objeto. En primer lugar, colocaremos unas cuantas letras
sobre un plano ajedrezado. Podemos usar cualquier fuente TTF, aunque aquí se usará sólo las incluidas
con POV-Ray 3.0.
camera {
location <0, 1, -10>
look_at 0
angle 35
}
plane { y,0
pigment { checker Green White }
}
Ahora, incluyamos el objeto de texto. Usaremos el archivo TIMROM.TTF con la cadena POV-RAY 3.0.
De momento, haremos nuestras letras de color rojo. La sintaxis es muy sencilla. La primera cadena
entrecomillada es el nombre de la fuente, la segunda es el texto que aparecerá en el dibujo. Los dos
números decimales que las siguen son el grosor y el desplazamiento. El grosor determina el tamaño del
bloque sobre el que están recortadas las letras. Los valores apropiados pueden estar entre 0.5 y 2. El
desplazamiento es un valor que se añadirá al valor definido por la propia fuente para separar las letras.
De momento se dejará a cero.
text { ttf "timrom.ttf" "POV-RAY 3.0" 1, 0
pigment { Red }
}
Al trazar esta escena a 200x150, observamos que las letras se salen por la derecha de la imagen. Esto es
así porque POV-Ray sitúa el texto de forma que la esquina inferior izquierda delantera de la primera
letra coincide con el origen. Para centrarlo debemos desplazar el texto en el sentido negativo del eje x.
Pero ¿cuanta distancia? En la documentación vemos que la altura de las letras está entre 0.5 y 0.75
unidades. Si asumimos que la distancia entre una y otra ronda las 0.5 unidades, significa que la cadena
en total tendrá unas 6 unidades, de forma que trasladaremos el objeto 3 unidades en el sentido negativo
del eje x.
text { ttf "timrom.ttf" "POV-RAY 3.0" 1, 0
pigment { Red }
translate -3*x
}
Mucho mejor. Ahora vamos a jugar un poco con los parámetros del objeto. En primer lugar,
aumentaremos su grosor hasta un valor grande... ¡pongamos 25!
text { ttf "timrom.ttf" "POV-RAY 3.0" 25, 0
pigment { Red }
translate -2.25*x
}
Realmente, queda un tanto extraño. Devolvamos este valor a 1 e intentemos un valor diferente para el
desplazamiento. Pongamos 0.1 en lugar de 0 y volvamos a trazar.
¡Un momento! ¡Las letras se desplazan en ángulo! ¡Esto no es lo que describe el manual! Parece que el
valor de desplazamiento se aplica tanto en el eje x como en el eje y, en lugar de desplazarlas sólo en la
dirección x. ¿Se necesita aquí un vector en lugar de un solo número? Probemos. Reemplazaremos 0.1
por 0.1*x y probaremos de nuevo.
¡Ahora funciona! Las letras siguen en línea recta, aunque un poco más separadas de lo que lo estaban
antes. Verifiquemos esta propiedad haciendo que las letras se desplacen en otra dirección. Cambiando
0.1*x por 0.1*y, observamos que las letras suben un poco al desplazarnos de izquierda a derecha, sin
separarse horizontalmente más de lo que estaban. Ahora, probemos el eje z. Reemplacemos 0.1*y por
0.1*z. Trazar esto produce una pequeña desilusión: no hay tal desplazamiento, sólo funciona en las
direcciones x e y.
4. TUTORIAL PARA PRINCIPIANTES 66
Acabemos nuestra escena dando a las letras una textura mejor, usando un gran valor para el grosor y
añadiendo un pequeño desplazamiento vertical a nuestras letras. Para obtener un mejor resultado,
usaremos una esfera celeste, adornaremos un poco nuestro plano y buscaremos una situación de la
cámara mejor (trazamos la siguiente escena a 640x480 y con antialias).
#include "colors.inc"
camera {
location <-5,.15,-2>
look_at <.3,.2,1>
angle 35
}
plane { y,0
texture {
pigment { SeaGreen }
finish { reflection .35 specular 1 }
normal { ripples .35 turbulence .5 scale .25 }
}
}
#include "skies.inc"
sky_sphere { S_Cloud5 }
Ahora, vamos a usar un objeto de texto en una operación CSG. Intentaremos crear un bajorrelieve en
un bloque de piedra usando unas letras. Creamos un nuevo archivo llamado TEXTCSG.POV y lo editamos
de la siguiente forma:
#include "colors.inc"
#include "stones.inc"
camera {
location <-3, 5, -15>
look_at 0
angle 25
}
translate -3*x
}
Recordemos que, por defecto, el texto se coloca de forma que su cara frontal se apoya en el plano x-y.
Como el frontal del bloque se inicia en 0.1, resulta que nuestro texto penetra en la piedra un total de
0.05 unidades. Ahora, basta situar alrededor de ambos objetos una operación de diferencia y tendremos
nuestro objetivo:
difference {
box { <-3.5, -1, 0.1>, <3.5, 1, 1>
texture { T_Stone10 }
}
text { ttf "timrom.ttf" "POV-RAY 3.0" 0.15, 0
pigment { BrightGold }
finish { reflection .25 specular 1 }
translate -3*x
}
}
Lo trazamos a 200x150. Nos fijamos si se aprecia realmente la profundidad del texto, y su textura en
oro brillante. Lo volvemos a trazar, esta vez a 640x480 y con antialias para ver el resultado más
claramente, pero seamos pacientes, porque esta imagen tardará algo de tiempo en estar lista.
4.4.11. Toro
Podemos pensar en un toro como en un "donut" o un neumático. Es una forma que se usa mucho en
operaciones de composición de objetos, de forma que POV-Ray ha adoptado esta forma polinómica de
cuarto grado como forma primitiva. Su sintaxis es muy sencilla, así que es sencillo aprender a usarla una
vez que se ha comprendido lo que significan los dos valores decimales que se deben indicar. En lugar de
describirlos, creemos un objeto de este tipo y experimentemos con él.
camera {
location <0, .1, -25>
look_at 0
angle 30
4. TUTORIAL PARA PRINCIPIANTES 68
Con una sintaxis tan simple, no hay mucho que hacer con un toro salvo cambiarle la textura...¿no?
Veamos...
Los toros son muy útiles en composición de formas. Hagamos un pequeño experimento. Veamos qué
forma tiene la diferencia entre un toro y una caja:
difference {
torus { 4, 1
rotate x*-90 // para verlo desde arriba
}
box { <-5, -5, -1>, <5, 0, 1> }
pigment { Green }
}
Interesante... medio toro. Ahora añadiremos otro al revés. Sólo hay que declararlo y hacer las
transformaciones necesarias para usarlo en dos posiciones distintas:
#declare Half_Torus = difference {
torus { 4, 1
rotate -90*x // para verlo desde arriba
}
box { <-5, -5, -1>, <5, 0, 1> }
pigment { Green }
}
general, no conviene que nuestra cámara coincida con un plano de alguna de las cajas utilizadas en la
imagen). Cambiaremos la coordenada y de la cámara de 0 a 0.1 para evitar este defecto.
union {
object { Half_Torus }
object { Half_Torus
rotate Flip_It_Over
translate x*Torus_Translate
}
object { Half_Torus
translate x*Torus_Translate*2
}
object { Half_Torus
rotate Flip_It_Over
translate x*Torus_Translate*3
}
object { Half_Torus
rotate Flip_It_Over
translate -x*Torus_Translate
}
object { Half_Torus
translate -x*Torus_Translate*2
}
object { Half_Torus
rotate Flip_It_Over
translate -x*Torus_Translate*3
}
object { Half_Torus
translate -x*Torus_Translate*4
}
rotate y*45
translate z*20
}
Al crear la imagen veremos una forma serpenteante muy curiosa. Pero queremos modelar algo más útil,
que podamos encontrar en la vida real ¿que tal una cadena?
Pensemos un momento. Hay que observar que un eslabón de la cadena puede ser modelado de forma
muy sencilla usando dos semitoros y dos cilindros. Creamos un nuevo archivo, en el que podemos usar
los mismos fondo, cámara, luz y declaraciones de objetos que usábamos en TORDEMO.POV:
#include "colors.inc"
camera {
location <0, .1, -25>
look_at 0
angle 30
}
#declare Torus_Translate = 8
Ahora, creamos un toro completo a partir de dos semitoros:
4. TUTORIAL PARA PRINCIPIANTES 70
union {
object { Half_Torus }
object { Half_Torus rotate Flip_It_Over }
}
Esto parece ser una forma algo artificiosa de crear un toro, pero realmente vamos a desplazar cada
mitad para dejar sitio a los cilindros. Primero, declararemos los cilindros que utilizaremos:
#declare Chain_Segment = cylinder { <0, 4, 0>, <0, -4, 0>, 1
pigment { Green }
}
Después, añadiremos dos de estos cilindros a la unión de los semitoros trasladándolos de forma que
queden alineados con el radio exterior de los toros a cada lado:
union {
object { Half_Torus }
object { Half_Torus rotate Flip_It_Over }
object { Chain_Segment translate x*Torus_Translate/2 }
object { Chain_Segment translate -x*Torus_Translate/2 }
}
Ahora, trasladamos los semitoros en la dirección vertical para que sus extremos coincidan con los de los
cilindros. La distancia coincide con la mitad de la definida como Torus_Tranlate:
union {
object { Half_Torus
translate y*Torus_Translate/2
}
object { Half_Torus
rotate Flip_It_Over
translate -y*Torus_Translate/2
}
object { Chain_Segment
translate x*Torus_Translate/2
}
object { Chain_Segment
translate -x*Torus_Translate/2
}
}
Trazamos el resultado y tenemos un eslabón de la cadena. ¡Pero aún no hemos acabado! ¿Alguien ha
visto una cadena de color verde? Usemos una apariencia metálica sobre ellos. En primer lugar,
borremos todos los pigmentos de las declaraciones de los toros y cilindros. Después, declaremos lo
siguiente antes de la unión:
#declare Chain_Gold = texture {
pigment { BrightGold }
finish {
ambient .1
diffuse .4
reflection .25
specular 1
metallic
}
}
Ahora, añadamos esta textura a la unión y nombrémosla apropiadamente:
#declare Link = union {
object { Half_Torus
translate y*Torus_Translate/2
}
object { Half_Torus
rotate Flip_It_Over
translate -y*Torus_Translate/2
}
object { Chain_Segment
PERSISTENCE OF VISION RAYTRACER 71
translate x*Torus_Translate/2
}
object { Chain_Segment
translate -x*Torus_Translate/2
}
texture { Chain_Gold }
}
Por fin, uniremos dos eslabones. El segundo debe ser trasladado en dirección vertical de forma que su
cara interior coincida con la cara interior del primer eslabón. La distancia adecuada resulta ser el doble
de la distancia Torus_Translate menos dos (dos veces el radio exterior). Esto puede describirse
mediante la expresión:
(Torus_Translate*2-2)*y
Declaramos la expresión como sigue:
#declare Link_Translate = (Torus_Translate*2-2)*y
En el bloque en el que situemos el objeto, usaremos este valor multiplicándolo para insertar nuevos
eslabones. Ahora, rotaremos el segundo eslabón noventa grados respecto al eje vertical para que sea
perpendicular al primero (como los verdaderos eslabones de una cadena). Finalmente, reduciremos el
tamaño de la unión a un cuarto de su tamaño para poder ver el resultado completamente:
union {
object { Link }
object { Link translate y*Link_Translate rotate y*90 }
scale .25
}
Al trazar esto, podremos ver un par de eslabones muy realistas. Si queremos hacer una cadena
completa, necesitamos declarar esta unión y crear otra unión usando como pieza este par de eslabones.
Quitamos el escalado de la primera declaración para poder escalar sólo el objeto definitivo:
#declare Link_Pair =
union {
object { Link }
object { Link translate y*Link_Translate rotate y*90 }
}
Ahora declaramos nuestra cadena:
#declare Chain = union {
object { Link_Pair}
object { Link_Pair translate y*Link_Translate*2 }
object { Link_Pair translate y*Link_Translate*4 }
object { Link_Pair translate y*Link_Translate*6 }
object { Link_Pair translate -y*Link_Translate*2 }
object { Link_Pair translate -y*Link_Translate*4 }
object { Link_Pair translate -y*Link_Translate*6 }
}
Y, finalmente, situamos nuestra cadena añadiendo unas transformaciones para hacerla visible en su
totalidad. Estas transformaciones incluyen escalarla en un factor 1/10, trasladarla y girarla para poder
ver bien todos los enlaces:
object { Chain scale .1 rotate <0, 45, -45> }
4. TUTORIAL PARA PRINCIPIANTES 72
En la imagen podemos ver una cadena dorada que cruza diagonalmente la pantalla.
Los objetos CSG pueden se extremadamente complejos. Pueden estar anidados profundamente (una
unión puede contener varias intersecciones, y éstas varias diferencias...).Los objetos CSG son (casi
siempre) objetos finitos y por tanto responden al método automático de simplificación que usa POV-
Ray (auto-bounding) y pueden también ser transformados como si fuesen cualquier otra forma
primitiva. A pesar de esto, en determinadas circunstancias, conviene utilizar (con moderación) la
instrucción bounded_by si creamos un CSG muy complejo.
4.5.2. Unión
Intentemos diseñar una unión sencilla. Crea un archivo llamado CSGDEMO.POV y escribe:
#include "colors.inc"
camera {
location <0, 1, -10>
PERSISTENCE OF VISION RAYTRACER 73
look_at 0
angle 36
}
plane { y, -1.5
pigment { checker Green White }
}
Añade dos esferas, trasladando cada una de ellas en un sentido distinto del eje x 0.5 unidades.
Colorearemos una roja y otra azul.
sphere { <0, 0, 0>, 1
pigment { Blue }
translate -0.5*x
}
sphere { <0, 0, 0>, 1
pigment { Red }
translate 0.5*x
}
Trazamos esta unión a 200x150. Coloquemos una unión agrupando ambas esferas. Esto creará un solo
objeto, unión de ambas esferas.
union{
sphere { <0, 0, 0>, 1
pigment { Blue }
translate -0.5*x
}
sphere { <0, 0, 0>, 1
pigment { Red }
translate 0.5*x
}
}
Si lo volvemos a trazar, no observaremos ningún cambio, pero ahora podemos dar a ambas esferas la
misma textura, moverlas como si de una sola pieza se tratase, o escalarlas. Hagámoslo:
union{
sphere { <0, 0, 0>, 1
translate -0.5*x*
}
sphere { <0, 0, 0>, 1
translate 0.5*x
}
pigment { Red }
scale <1, .25, 1>
rotate <30, 0, 45>
}
Al trazarlo ahora, observaremos que la imagen ha cambiado radicalmente. Podemos escalarla con
diferentes valores, o probar sobre este objeto varias texturas distintas.
Aplicar una textura a una unión en lugar de hacerlo sobre los objetos aislados tiene varias ventajas. En
primer lugar, cambiar de decisión sobre la apariencia del objeto es más si sólo hemos de escribirla una
vez que si debemos cambiarla en todos los objetos que compongan la figura. En segundo lugar, la
escena se interpreta más rápido, ya que sólo es necesario que el ordenador la interprete una vez. En
tercer lugar, ahorra memoria, ya que el programa construye un solo modelo de textura (y referencia cada
objeto a este modelo). Si la aplicamos sobre varios objetos, aunque la textura sea idéntica, almacena una
copia por cada uno de ellos.
4. TUTORIAL PARA PRINCIPIANTES 74
4.5.3. Intersección
Ahora usemos las mismas esferas de la sección anterior para ilustrar el siguiente tipo de objeto CSG, la
intersección. Cambiamos la palabra "union" por "intersection", y borramos las transformaciones:
intersection {
sphere { <0, 0, 0>, 1
translate -0.5*x
}
sphere { <0, 0, 0>, 1
translate 0.5*x
}
pigment { Red }
}
Al trazar la escena, veremos un objeto similar a una lente, en lugar de las dos esferas. Esto sucede
porque la intersección encierra el volumen compartido por todas las formas, en este caso la figura que
vemos, donde las esferas se solapan. Me gusta este objeto, de forma que lo usaremos para explicar las
diferencias.
4.5.4. Diferencia
Rotemos el objeto de forma que presente su frente a la cámara.
intersection{
sphere { <0, 0, 0>, 1
translate -0.5*x
}
sphere { <0, 0, 0>, 1
translate 0.5*x
}
pigment { Red }
rotate 90*y
}
En realidad, la diferencia no es un objeto diferente, es idéntica a la intersección, sólo que todos los
objetos excepto el primero llevan la clave inverse, que hace que cambien de nombre su interior y su
interior. Es decir, que lo anterior también podría haberse escrito como:
intersection{
sphere { <0, 0, 0>, 1
translate -0.5*x
}
sphere { <0, 0, 0>, 1
translate 0.5*x
}
pigment { Red }
rotate 90*y
cylinder { <0, 0, -1> <0, 0, 1>, .35
inverse
pigment { Blue }
}
}
Bueno, hagamos algo mejor: declaremos nuestra lente perforada de forma que podamos ponerle un
nombre. Antes, habremos eliminado todas las texturas de su interior, ya que las utilizaremos en su
ubicación definitiva.
#declare Lens_With_Hole = difference {
intersection {
sphere { <0, 0, 0>, 1
translate -0.5*x
}
sphere { <0, 0, 0>, 1
translate 0.5*x
}
rotate 90*y
}
cylinder { <0, 0, -1> <0, 0, 1>, .35 }
}
Ahora usaremos una unión para construir una figura compuesta de copias de este objeto:
union {
object { Lens_With_Hole translate <-.65, .65, 0> }
object { Lens_With_Hole translate <.65, .65, 0> }
object { Lens_With_Hole translate <-.65, -.65, 0> }
object { Lens_With_Hole translate <.65, -.65, 0> }
pigment { Red }
}
Trazamos la escena. Un objeto interesante ¿no? Pero intentemos algo más. Hagamos las lentes
parcialmente transparentes añadiéndoles algo de filtro al pigmento de la unión:
union {
object { Lens_With_Hole translate <-.65, .65, 0> }
object { Lens_With_Hole translate <.65, .65, 0> }
object { Lens_With_Hole translate <-.65, -.65, 0> }
object { Lens_With_Hole translate <.65, -.65, 0> }
pigment { Red filter .5 }
}
Trazamos de nuevo la imagen. Está bien, salvo que... podemos ver trozos de los objetos lente dentro de
otros. Esto no está tan bien.
4.5.5. Fusión
Esto nos lleva al cuarto tipo de construcción CSG. la fusión. Es muy similar a la unión, salvo que las
superficies de los objetos que deben estar dentro de otro de la unión no se trazan, es decir, desaparecen.
Esto eliminará el problema al que hemos hecho alusión antes. Probémoslo:
4. TUTORIAL PARA PRINCIPIANTES 76
merge {
object { Lens_With_Hole translate <-.65, .65, 0> }
object { Lens_With_Hole translate <.65, .65, 0> }
object { Lens_With_Hole translate <-.65, -.65, 0> }
object { Lens_With_Hole translate <.65, -.65, 0> }
pigment { Red filter .5 }
}
¡Desde luego que lo hace!
Veamos qué sucede cuando usamos un cilindro para abrir un agujero en una caja más grande:
difference {
box { -1, 1 pigment { Red } }
cylinder { -z, z, 0.5 pigment { Green } }
}
Al trazarlo, veremos una nube de puntos rojos donde el agujero debería estar, provocados por la
coincidencia de la base del cilindro y el frontal de la caja. A veces, un rayo de luz impacta primero en la
superficie del cilindro, decidiendo que debe pasar a través de ella. En otras ocasiones, es alcanzada antes
la superficie de la caja, rebotando en ella. Esto produce un mal resultado, y causa la aparición de la nube
de puntos.
Este problema se puede remediar aumentando un poco la longitud del cilindro, evitando así la
coincidencia de superficies:
difference {
box { -1, 1 pigment { Red } }
cylinder { -1.001*z, 1.001*z, 0.5 pigment { Green } }
}
En general, debemos hacer el objeto que restamos algo más grande en una diferencia para evitar
coincidencias.
Un problema similar ocurre con las intersecciones (que, como hemos comentado, son muy similares a
las diferencias, con las fusiones (especialmente, ya que su objetivo es eliminar las superficies interiores,
y, cuando coinciden, ambas pueden ser consideradas interiores a la otra) e incluso, aunque con menos
frecuencia, con uniones en las que ambas superficies usan distinta textura. Habitualmente todos los
casos tienen una sencilla solución, que consiste en agrandar algo alguno de los objetos implicados.
uso adecuado del tipo correcto puede dar lugar a resultados muy impresionantes. Tomémonos un
momento para explorar algunos de los diferentes tipos de fuentes de luz y sus diferentes parámetros.
Por defecto la fuente de luz, la cual emite su luz en todas partes y en todas direcciones, y es blanca pura
(rgb <1, 1, 1>). El cambio de color puede ser utilizado para crear efectos interesantes. Lo primero de
todo el nivel de luz global de la escena puede ser ajustado fácilmente. En lugar de cambiar todos los
valores ambient en cada finish, sólo la fuente de luz ambiente es modificada. Asignando diferentes
colores nosotros podemos crear bonitos efectos como una caprichosa luz de ambiente rojiza. Para más
detalles sobre la fuente de luz ambiente véase "Luz de Ambiente".
camera {
location <-4, 3, -9>
look_at <0, 0, 0>
angle 48
}
Añadimos los siguientes objetos simples:
plane { y, -1
texture {
pigment {
checker
color rgb<0.5, 0, 0>
color rgb<0, 0.5, 0.5>
}
finish {
diffuse 0.4
ambient 0.2
phong 1
phong_size 100
reflection 0.25
}
}
}
texture { Brown_Agate }
rotate <90, 160, 0>
translate <-1, 1, 3>
}
sphere { <0,0,0>,1
texture { Sapphire_Agate }
translate <1.5, 0, -2>
}
Ahora añadimos una fuente de luz puntual:
light_source {
<2, 10, -3>
color White
}
Trazamos esto a "200x150 -A" y vemos que los objetos son claramente visibles y con sombras
pronunciadas. Los lados de objetos curvados próximos a la fuente de luz son de color brillante y las
áreas que están en el lado opuesto a la fuente de luz son más oscuras. También apreciamos que el plano
ajedrezado está iluminado incluso en todo el horizonte. Esto nos permite ver el plano, pero no es muy
realista.
focal parece haberse hecho mucho más pequeña, pero lo que realmente ha sucedido es que el falloff
ha llegado a ser tan exagerado que el radio actual aparece mucho más pequeño.
Decidimos que un valor de tightness de 10 (el valor por defecto) y un valor de falloff de 18 son
los mejores para esta luz focal y ahora pondremos algunas luces más alrededor de la escena para
conseguir efectos. Coloquemos un foco azul ligeramente más estrecho y uno rojo además del blanco
que ya teníamos.
light_source {
<10, 10, -1>
color Red
spotlight
radius 12
falloff 14
tightness 10
point_at <2, 0, 0>
}
light_source {
<-12, 10, -1>
color Blue
spotlight
radius 12
falloff 14
tightness 10
point_at <-2, 0, 0>
}
Trazando esto veremos que la escena ahora tiene un aire maravillosamente misterioso. Las tres luces
focales convergen sobre los objetos haciéndolos azules en un lado y rojos en el otro, con suficiente
blanco en el medio para proporcionar un equilibrio.
intermedia donde no hay ni luz total ni oscuridad. Para simular esta suave sombra, un trazador de rayos
debe dar a sus fuentes de luz dimensión. POV-Ray lleva a cabo esto con una característica conocida
como luz extendida3.
Las luces extendidas tienen dimensiones en dos ejes. Estos están especificados por los dos primeros
vectores en la sintaxis de superficie. Debemos también especificar cuántas luces hay en el array. Cuantas
más coloquemos, las sombras serán más suaves, pero nos llevará más tiempo de trazado. Normalmente
un array de 3x3 ó 5x5 será suficiente. También tenemos la posibilidad de especificar un valor de
adaptación. La palabra reservada adaptive le dice al trazador de rayos que puede adaptarse a la
situación y enviar sólo los rayos necesarios para determinar el valor del pixel. Si no se usa adaptive se
enviará un rayo por cada luz en la luz de superficie. Esto puede realmente ralentizar el proceso. Cuanto
más alto sea el valor de adaptive, más suave será la penumbra, pero más tiempo empleará el trazado.
Normalmente un valor adaptive de 1 es suficiente. Finalmente, es probable que debamos usar la
palabra reservada jitter. Ésta le dice al trazador que mueva ligeramente la posición de cada luz en la
fuente extendida, de forma que las sombras aparezcan realmente suaves en lugar de darnos una
penumbra formada por franjas de sombras cada vez más claras.
Después de hacer esto, apreciamos dos cosas. El trazado se hace un poco más largo que con una fuente
de luz puntual o focal y las sombras no son tan marcadas. Todo tiene una bonita y suave penumbra a su
alrededor. Pero esto se puede mejorar.
¡Las luces puntuales y cilíndricas pueden también ser luces extendidas! ¿Recuerdas esas sombras
marcadas originadas por las luces puntuales de nuestra escena? No tendría mucho sentido usar un array
de 5x5 para una luz puntual, pero un array más pequeño podría hacer un buen trabajo y
proporcionarnos la cantidad óptima de penumbra para una luz puntual. Probémoslo. Comentamos la
fuente extendida y modificamos las luces cilíndricas para que sean como las siguientes:
light_source {
<2, 10, -3>
color White
spotlight
radius 15
falloff 18
tightness 10
area_light <1, 0, 0>, <0, 0, 1>, 2, 2
adaptive 1
jitter
point_at <0, 0, 0>
}
light_source {
light_source {
<-12, 10, -1>
color Blue
spotlight
radius 12
falloff 14
tightness 10
area_light <1, 0, 0>, <0, 0, 1>, 2, 2
adaptive 1
jitter
point_at <-2, 0, 0>
}
Ahora tenemos tres luces puntuales de superficie, de tamaño una unidad y con cuatro (2x2) luces, tres
colores diferentes, todas iluminando nuestra escena. Trazamos esto a 200x150 -A. Esto parece
funcionar perfectamente. Todas nuestras sombras tienen pequeñas bandas de penumbra, exactamente
como cabría esperar en un objeto iluminado con luz puntual real.
<0, 2, 0>
color White
looks_like { Lightbulb }
}
Trazando esto veremos que ahora una bonita bombilla con apariencia realista ilumina la escena. Sin
embargo, si no especificamos un valor alto de ambient la bombilla no estará iluminada por la fuente
de luz. Por otro lado, todas las sombras provienen de la bombilla como en una situación real. Las
sombras son marcadas, así que convirtamos nuestra bombilla en una luz extendida:
light_source {
<0, 2, 0>
color White
area_light <1, 0, 0>, <0, 1, 0>, 2, 2
adaptive 1
jitter
looks_like { Lightbulb }
}
Apreciamos que hemos colocado esta luz de superficie en el plano xy en lugar de en el plano xz.
También apreciamos que la apariencia real de la bombilla no se ve afectada en ningún modo por la
fuente de luz. La bombilla debe ser iluminada por alguna otra fuente de luz o, como en este caso,
proporcionar un valor alto de ambient. Se pueden obtener resultados más interesantes empleando
halos (véase sección "Halos").
¿Recuerdas las tres luces de color puntuales de superficie? Volvamos a ellas, quitémosles los
comentarios y comentemos el resto de las fuentes. Añadamos lo siguiente:
light_source {
<0, 20, 0>
color Gray50
shadowless
}
Ésta es una bonita luz de poca intensidad colocada 20 unidades sobre el centro de nuestra escena. Dará
una ligera iluminación a todos los objetos incluyendo el plano de la parte posterior. Tracemos y
veámosla.
Primero hagamos nuestra luz de relleno un poco más brillante cambiando Gray50 a Gray75. Ahora,
modifiquemos la luz de relleno como sigue:
light_source {
<0, 20, 0>
color Gray75
fade_distance 5
fade_power 1
shadowless
}
Esto significa que el valor completo de la luz de relleno alcanzará una distancia de 5 unidades desde la
fuente de luz. El valor 1 de fade_power quiere decir que la atenuación será lineal (la luz se desvanece
según un valor constante). Tracemos para ver el resultado.
Experimentemos con estas palabras reservadas. Primero añadimos una atmósfera a nuestra escena:
#include "atmos.inc"
atmosphere { Atmosphere2 }
Comentemos las tres líneas que convierten cada una de las luces puntuales en luces de superficie. De
otro modo el trazado se hará muy largo.
//area_light <1, 0, 0>, <0, 0, 1>, 2, 2
//adaptive 1
//jitter
Generando esta escena a 200x150 -A veremos que realmente las luces puntuales son visibles. Veremos
cómo el haz rojo y el azul se entrecruzan y cómo la luz superior blanca ilumina la parte inferior
atravesando el centro de la escena. También apreciamos que las luces puntuales parecen disminuir su
intensidad a medida que la luz desciende desde la fuente de luz hacia los objetos. La luz roja inunda
todo excepto en la parte baja de la izquierda de la escena y la luz azul inunda todo excepto en la parte
baja de la derecha. Esto es debido a la atenuación atmosférica y añade más realismo a la escena. La
interacción entre atmósfera y fuente de luz da a nuestra escena una apariencia ahumada y misteriosa,
pero el trazado empleará más tiempo. Convirtiendo estas fuentes puntuales en luces de superficie
todavía empleará más tiempo. Este es el precio a pagar para obtener una imagen de calidad.
Supongamos que queremos una superficie muy abollada sobre un objeto. Sería muy difícil modelar
matemáticamente esa cantidad de abolladura. Podemos, sin embargo, simular las abolladuras alterando
la forma en que la luz se refleja en la superficie. Los cálculos de reflexión dependen de un vector
denominado normal a la superficie. Este es un vector que apunta hacia afuera de la superficie y es
perpendicular a ella. Modificando artificialmente (o perturbando) este vector normal, podemos simular
abolladuras. Cambiamos la escena a lo siguiente y la trazamos:
sphere { <0, 1, 2>, 2
texture {
pigment { color Yellow }
normal { bumps 0.4 scale 0.2 }
finish { phong 1}
}
}
Esto informa a POV-Ray de que use un patrón de abolladura para modificar la normal a la superficie.
El valor 0.4 controla la profundidad aparente de las abolladuras. Normalmente las abolladuras son de
aproximadamente una unidad de ancho, lo cual no parece encajar muy bien con una esfera de radio 2.
El escalado hace que las abolladuras tengan 1/5 de anchura, pero no afecta a su profundidad.
}
finish { phong 1 }
}
}
La palabra clave wood especifica un patrón de pigmento de anillos concéntricos como los anillos de la
madera. La palabra clave color_map especifica que el color de la madera debe mezclarse desde
DarkTan a DarkBrown en el primer 90% del veteado y de DarkBrown a VeryDarkBrown sobre el restante
10%. La palabra clave turbulence agita ligeramente el patrón de forma que el veteado no sean
círculos perfectos y la palabra clave scale ajusta el tamaño del patrón.
Muchos patrones nos vienen dados por defecto para ofrecernos esa característica alrededor de una
esfera de radio 1.0. Una característica se puede definir burdamente como una transición de color. Por
ejemplo, una textura de madera debería tener una banda sobre una esfera de radio 1.0. En este ejemplo
escalamos el patrón usando la palabra clave scale seguida por un vector. En este caso escalamos 0.2
en la dirección x, 0.3 en la dirección y, y 1 en la dirección z, lo cual lo deja inalterado. Valores de
escalado mayores que 1 extenderán un elemento. Valores de escalado menores que 1 encogerán un
elemento. Un valor de escalado de 1 dejará el elemento inalterado.
Miremos el fichero TEXTURES.INC para ver qué pigmentos y acabados están definidos y probémoslos.
Insertemos el nombre del nuevo pigmento donde está ahora DMFWood4 o probemos un acabado
diferente en lugar de Shiny y volvamos a trazar nuestro fichero.
Aquí tenemos un ejemplo de un uso de identificador de textura completo en lugar de sólo las piezas.
sphere { <0, 1, 2>, 2
texture { PinkAlabaster }
}
Obviamente, no podemos probarlas todas. En ese caso, nuestro tutorial aún tendría más páginas. En
este tutorial sólo probaremos unas cuantas de las opciones, para proporcionar una muestra de lo que
puede crearse con POV-Ray. Con un poco de práctica, pronto podrá el lector crear sus propias texturas.
4.8.2. Pigmentos
Todas las superficies deben tener un color. En POV-Ray este color se denomina pigmento. No tiene
porqué ser un color uniforme. Puede ser un patrón de color, uno de los tres dibujos permitidos o una
imagen extendida. Pueden colocarse diferentes capas de pigmentos, de forma que las superiores tengan
partes transparentes a través de las que se muestren las inferiores. Probemos algunas de las posibilidades
de este concepto.
camera {
location <1, 1, -7>
look_at 0
angle 36
}
plane { y, -1.5
pigment { checker Green, White }
}
sphere { <0,0,0>, 1
pigment { Red }
}
Trazando esta imagen en una prueba a 200x150, vemos que se trata de una sencilla bola roja sobre un
suelo a cuadros blancos y verdes. Usaremos esta esfera para probar nuestras texturas.
Veremos que cada uno de ellos da lugar a una disposición de los colores ligeramente diferente (bozo y
spotted puede que resulten idénticos). Pero para obtener buenos resultados, cada tipo de patrón
requiere el uso de algunos modificadores.
Cambiemos el patrón a marble. Al observarlo, veremos que es muy similar al gradient y, que no se
parece en absoluto al mármol, como parece sugerir su nombre. Situemos una frecuencia de 3
(frequency 3) y una turbulencia de 1 (turbulence 1) y probemos otra vez. Mucho mejor ¿no?
Prueba a cambiar el orden en el que sitúas la turbulencia y la frecuencia ¿qué sucede?
La turbulencia tiene de por sí unos modificadores específicos que nos permiten tener más control sobre
lo que hace. En primer lugar, el valor que sigue a la palabra turbulence puede tener decimales, e
indica lo "revuelta" que quedará la textura. Valores más altos hacen más caótico el resultado. En
segundo lugar, podemos usar los modificadores omega, lambda y octaves para cambiar los
parámetros internos de la turbulencia. Probemos esto ahora:
pigment {
marble
turbulence 0.5
lambda 1.5
omega 0.8
octaves 5
frequency 3
color_map {
[0.00 color Red]
[0.33 color Blue]
[0.66 color Yellow]
[1.00 color Red]
}
rotate 45*z
}
Trazar esto nos permitirá ver que la turbulencia ha cambiado, dando lugar a un patrón ligeramente
distinto. Podemos jugar con los valores de turbulence, lambda, omega y octaves para observar
lo que hacen.
Hay otra clase de transparencia en POV-Ray. Se llama transmitancia o transparencia sin filtro. Su
palabra clave es transmit, y difiere de la anterior en que no filtra la luz de acuerdo con el color de la
superficie. Permite que la luz pase a través sin cambios. Puede especificarse como sigue: rgbt
<1,0,0,1>.
Usaremos ahora colores transparentes para crear otro tipo de texturas, las texturas superpuestas.
Volviendo a nuestro ejemplo anterior, declaramos la siguiente textura:
#declare LandArea = texture {
pigment {
agate
turbulence 1
lambda 1.5
omega .8
octaves 8
color_map {
[0.00 color rgb <.5, .25, .15>]
[0.33 color rgb <.1, .5, .4>]
[0.86 color rgb <.6, .3, .1>]
[1.00 color rgb <.5, .25, .15>]
PERSISTENCE OF VISION RAYTRACER 89
}
}
}
}
Esta será la textura del suelo. Ahora, crearemos lo océanos declarando lo siguiente:
#declare OceanArea = texture {
pigment {
bozo
turbulence .5
lambda 2
color_map {
[0.00, 0.33 color rgb <0, 0, 1>
color rgb <0, 0, 1>]
[0.33, 0.66 color rgbf <1, 1, 1, 1>
color rgbf <1, 1, 1, 1>]
[0.66, 1.00 color rgb <0, 0, 1>
color rgb <0, 0, 1>]
}
}
}
}
Observa que el área transparente permitirá ver la tierra, mientras que el azul opaco representará el
océano.
Ahora, declaremos otra textura que represente la atmósfera, con remolinos de nubes.
#declare CloudArea = texture {
pigment {
agate
turbulence 1
lambda 2
frequency 2
color_map {
[0.0 color rgbf <1, 1, 1, 1>]
[0.5 color rgbf <1, 1, 1, .35>]
[1.0 color rgbf <1, 1, 1, 1>]
}
}
}
Por fin, apliquemos estas texturas sobre nuestra esfera:
sphere { <0,0,0>, 1
texture { LandArea }
texture { OceanArea }
texture { CloudArea }
}
Trazando esto, veremos una reconstrucción bastante buena de un pequeño planeta. Pero la capa de
nubes no es muy realista. Hay formas de hacerlas mucho mejor.
4.8.3. Normales
Los objetos de POV-Ray tienen superficies muy lisas. Esto no es muy real, de forma que hay varios
sistemas de distorsionar la superficie, modificando su normal. La normal es el vector perpendicular a
una superficie en un punto dado. La luz se refleja, o traspasa este objeto en función de esa normal, de
forma que alterarla significa que la superficie puede aparecer abollada, ondulada, arrugada, o modificada
de cualquiera de las formas disponibles. Probemos un puñado de ellas.
PERSISTENCE OF VISION RAYTRACER 91
Como añadido interesante, cambiaremos la textura del suelo a un solo color con una normal como la
que sigue:
plane { y, -1.5
pigment { color rgb <.65, .45, .35> }
normal { dents .75 scale .25 }
}
Una de las formas es usar mapas de normales. Un mapa de normales funciona igual que los mapas de
pigmentos usados con anterioridad. Cambiemos la textura de nuestra esfera de la siguiente forma:
sphere { <0,0,0>, 1
pigment { Gray75 }
normal {
gradient y
frequency 3
turbulence .5
normal_map {
[0.00 granite]
[0.25 spotted turbulence .35]
[0.50 marble turbulence .5]
[0.75 bozo turbulence .25]
[1.00 granite]
}
}
}
Al ver la imagen, observaremos que la esfera tiene una superficie con bultos muy irregular. El patrón
gradiente separa las normales en bandas, pero la turbulencia las ha agitado, dándole un aspecto caótico.
Pero esto nos da una idea.
4. TUTORIAL PARA PRINCIPIANTES 92
Podemos usar el mismo patrón para un mapa de normales que el que usamos para crear los océanos, de
forma que las zonas de tierra se vean rugosas, mientras que los océanos parezcan más lisos. ¿Quiere
esto decir que si aplicamos el mismo patrón con los mismos modificadores en una esfera del mismo
tamaño obtendremos la misma forma? Probémoslo. Primero, tracemos las dos esferas, de forma que
podremos ver que el patrón es realmente el mismo. Quitamos las señales de comentario a la primera
esfera y realizamos los siguientes cambios.
sphere { <0,0,0>, 1
texture { LandArea }
texture { OceanArea }
//texture { CloudArea } // <-lo convertimos en comentario
translate -x // <- añadimos esta transformación
}
Modificamos la esfera gris de la siguiente forma:
sphere { <0,0,0>, 1
pigment { Gray75 }
normal {
bozo
turbulence .5
lambda 2
normal_map {
[0.4 dents .15 scale .01]
[0.6 agate turbulence 1]
[1.0 dents .15 scale .01]
}
}
translate x // <- añadimos esta transformación
}
Ahora estamos seguros de que el patrón es el mismo. Ahora, marquemos como comentario la esfera
gris y añadamos el bloque de normales a la textura del suelo del otro planeta. Quitaremos la traslación
para que vuelva a quedar centrado.
#declare LandArea = texture {
pigment {
agate
turbulence 1
lambda 1.5
omega .8
octaves 8
color_map {
[0.00 color rgb <.5, .25, .15>]
[0.33 color rgb <.1, .5, .4>]
[0.86 color rgb <.6, .3, .1>]
[1.00 color rgb <.5, .25, .15>]
}
}
normal {
bozo
turbulence .5
lambda 2
normal_map {
[0.4 dents .15 scale .01]
[0.6 agate turbulence 1]
[1.0 dents .15 scale .01]
}
}
}
Mirando el resultado, nos haremos una idea de como funciona la idea. Las zonas terrestres están llenas
de bultos mientras que los océanos son lisos. Añadiendo de nuevo la capa de nubes, el planeta estará
completo.
PERSISTENCE OF VISION RAYTRACER 93
Por razones de espacio, hay muchas cosas que no hemos tratado. Por ejemplo, deberías experimentar
los llamados mapas de cuestas (slope maps), las medias (average) y mapas de bultos (bump maps).
4.8.4. Acabados
La parte final de una textura de POV-Ray es el acabado. Controla las propiedades de la superficie de un
objeto. Puede hacer que sea brillante y reflexivo o monótono y apagado. También puede especificar lo
que ocurre con la luz que pasa a través de pigmentos transparentes, con la que es dispersada debido a
superficies imperfectas y con la que es reflejada por superficies con delgadas películas que producen
interferencias. Hay doce propiedades diferentes disponibles en POV-Ray para especificar el acabado de
un objeto dado. Estas están controladas por los siguientes identificadores: ambient, diffuse,
brilliance, phong, specular, metallic, reflection, refraction, caustics,
attenuation, crand e iridiscence. Diseñemos un par de texturas que usen estos parámetros.
sphere { <0,0,0>, 1
pigment {Gray75}
finish {
ambient .2
diffuse .6
}
}
En este ejemplo se usan los valores por defecto para ambient y diffuse. Trazamos para ver cuales
son los resultados y después hacemos el siguiente cambio al acabado.
ambient 0
diffuse 0
La esfera es negra debido a que hemos especificado que la luz no sea reflejada por ella. Cambiemos
ahora diffuse por su valor por defecto de 0.6.
Ahora vemos la superficie gris donde la luz de la fuente incide directamente sobre la esfera, pero el lado
sombreado sigue siendo absolutamente negro. Ahora cambiemos diffuse a 0.3 y ambient a 0.3.
La superficie de la esfera se ha vuelto ahora más monótona. Es debido a que hemos especificado un
alto grado de luz ambiental y solo una pequeña cantidad de la luz proveniente de la fuente de luz es
difusamente reflejada hacia la cámara. Los valores por defecto de ambient y diffuse son una media
bastante buena y un buen punto de partida. En la mayoría de los casos, un valor para ambient entre
0.1 y 0.2 es suficiente y un valor para diffuse entre 0.5 y 0.7 generalmente quedará bien. Hay un par
de excepciones. Si tenemos una superficie completamente transparente con unos altos valores de
refracción o reflexión, usar valores bajos para ambient y diffuse es lo mejor. He aquí un ejemplo.
sphere { <0,0,0>, 1
4. TUTORIAL PARA PRINCIPIANTES 94
Si alguna vez necesitamos que un objeto esté totalmente iluminado independientemente de las fuentes
de luz en una escena dada, podemos hacerlo artificialmente especificando un valor de 1 para ambient
y un valor de 0 para diffuse. Esto eliminará todo el sombreado y simplemente dará al objeto su color
en su forma más brillante en todos sus puntos. Esto es útil para simular objetos que emiten luz como
bombillas y para cielos en escenas donde el este no deba ser iluminado por ningún otro medio
Hay otro tipo de reflejo, que es calculado usando un método distinto, llamado reflejo especular. Se
especifica usando el identificador specular y opera en conjunción con otro identificador llamado
roughness. En muchos aspectos, estos dos identificadores trabajan juntos del mismo modo que
PERSISTENCE OF VISION RAYTRACER 95
phong y phong_size para crear reflejos que alteren el aparente brillo de la superficie. Intentémoslo
ahora usando specular en nuestra esfera.
sphere { <0,0,0>, 1
pigment { Gray50 }
finish {
ambient .2
diffuse .6
specular .75
roughness .1
}
}
}
Observando los resultados vemos un amplio y atenuado reflejo similar al que teníamos cuando
usábamos phong_size 25. Cambiemos roughness a 0.001 y tracemos de nuevo. Ahora vemos un
pequeño y ceñido reflejo similar al que teníamos cuando usábamos phong_size 150. Hablando en
general. specular es ligeramente más preciso y por lo tanto ligeramente más realista que phong, pero
de todos modos deberías probar ambos métodos al diseñar una textura. Incluso hay veces en las que
ambos métodos pueden ser usados en un mismo acabado.
diffuse .1
specular 1
roughness .001
reflection .75
metallic
}
}
}
Vemos que el reflejo a tomado su color de la superficie en lugar de la fuente de luz. Esto da a la
superficie una apariencia más metálica.
ambient .1
diffuse .1
reflection .15
refraction 1
ior 1.45
specular 1
roughness .001
fade_distance 5
fade_power 1
}
}
Esto da a la esfera un aspecto nublado, como si no toda la luz fuera capaz de pasar a través de ella. Para
variaciones interesantes de esta textura, bajemos el valor de ior a 1.15 y subamos el de reflection a
0.5.
Una vez sabemos lo que estamos buscando, seremos capaces de observar la cáustica en muchas
situaciones cotidianas: la sombra proyectada por una lupa, la luz que atraviesa una pecera, a través de un
trozo arrugado de celofán, etc. Podremos verla incluso en el fondo de una piscina en un día soleado. La
cáustica es un sutil efecto luminoso que puede dar realismo a las imágenes trazadas con objetos que lo
usen.
POV-Ray usa algoritmos que simulan la cáustica refractiva (la cáustica reflexiva no es posible). Existen
limitaciones inherentes al proceso estándar de trazado de rayos en general que la hacen inadecuada para
algunas aplicaciones de la simulación de la luz, tales como testeo óptico y muy pocos y particulares
casos de proyectos arquitectónicos de iluminación. Los métodos que llevan a cabo cálculos más
extensos necesarios para realizar simulaciones completas del comportamiento de la luz, incluyendo la
cáustica (como el path-tracing, el photon-tracing o el ray-tracing bidireccional) son muy lentos y poco prácticos
en plataformas normales.
Esto significa que nos tenemos que arreglar con la cáustica para obtener el mejor resultado posible,
pero con un poco de experimentación, veremos que podemos emular de forma muy cercana la realidad.
La mejor forma de hacerlo es, cuando sea posible, estudiando antes un ejemplo de lo que estamos
intentando trazar. Tenemos que conocer el diseño de su cáustica y ajustar entonces nuestra imagen final
hasta que estemos satisfechos.
#include "colors.inc"
#include "textures.inc"
camera {
location <0, 15, -40>
look_at <-2, 0, 1>
angle 10
}
plane { y, 0
pigment { Grey }
}
// he aquí algo para aplicar la cáustica sobre ello
Cuando tracemos esto veremos nuestra esfera en la esquina superior derecha de la imagen, flotando a
escasa distancia del plano y la sombra que proyecta se extiende sobre la parte central de la escena. Y allí,
en el centro hay una cáustica básica. Esa área brillante en el centro representa la luz que normalmente la
refracción concentraría en medio de la sombra.
La única cuestión que esto desprende es: ¿qué pasa con el valor decimal que sigue al identificador
caustics? Bien, aquí es donde aparece nuestra discusión sobre como ajustar la cáustica. ¿Recuerdas
los vasos de cristal? Si tuviéramos uno de paredes delgadas y una base gruesa veríamos lo que queremos
decir en la sombra que proyectaría. En la parte superior, con las paredes delgadas (con menor
refracción) la cáustica es menos pronunciada y más difundida entre la sombra, pero cuando llegamos a
la parte de la sombra proyectada por la base más gruesa y refractiva, de repente la cáustica se vuelve más
pronunciada y más enfocada cerca del centro.
Por supuesto, ya que la cáustica es simulada, no hay correspondencia entre el grado en que la cáustica es
enfocada o difuminada y la forma, tamaño o refractividad del objeto. Sin embargo, podemos controlarla
PERSISTENCE OF VISION RAYTRACER 99
manualmente con el valor decimal que sigue al identificador caustics. Cuanto más se acerca este
valor a cero, más difusa y tenue será la cáustica, mientras que cuanto más cerca este de 1, más enfocada
y pronunciada será esta. Con el valor 1 tenemos la cáustica de una gruesa y altamente refractiva pieza de
cristal, mientras que con el valor 0.1, parece más bien una esfera de cristal vacía. Trazamos de nuevo la
escena anterior con una rango de valores entre 0.1 y 1.0 y vamos viendo las diferentes cáusticas que
tenemos.
Los valores fuera de rango también funcionan. Los números mayores que 1 nos llevan a cáusticas cada
vez más enfocadas. Los números negativos producen efectos extraños pero interesantes. Esencialmente,
el objeto se ilumina de formas extravagantes y la sombra parece más bien un negativo fotográfico de si
misma. Parecido a los efectos de las pistolas de rayos de ciencia ficción de los años 50. Tiene una
apariencia extraña y no del todo foto-realísta, pero si nos gusta el surrealismo podemos querer probarlo
al menos una vez y anotar el efecto que produce sobre nuestra mente en caso de que alguna vez lo
necesitemos.
Las cáustica es también un truco artificial, como vimos antes y se puede tener por seguro, que ha sido
diseñada para reaccionar sobre los diseños de la normal de la superficie para hacer que estos parezcan
genuinos. ¿Recuerdas el experimento del vaso de agua? Si encontramos un vaso con diseños tallados
sobre su superficie probablemente veremos esos diseños resaltados en la cáustica proyectada por el
cristal. Cuando tenemos una superficie transparente con una normal aplicada, esta hace que la cáustica
proyectada por esa superficie imite el diseño de la normal, de forma que aparezca en la sombra.
A continuación hay un ejemplo de lo que queremos decir: está pensado para representar el agua en una
piscina. Lo conseguimos mediante un plano superior para el agua, otro inferior que representa el suelo
de la piscina, una cámara justo debajo de la superficie, mirando al suelo y una fuente de luz situada a
bastante altura. (ver CAUSTIC2.POV).
#include "colors.inc"
camera {
location <0, -5, 0>
look_at <0, -10, -5>
}
// el fondo de la piscina...
plane { y, -10
texture {
pigment { color rgb <0.6, 0.7, 0.7> }
finish { ambient 0.1 diffuse 0.7 }
scale 0.01
}
4. TUTORIAL PARA PRINCIPIANTES 100
plane { y, 0
texture {
pigment { rgbf <0.6, 0.67, 0.72, 0.9> }
normal {
bumps .6
scale <.75, .25, .25>
rotate <0, 45, 0>
}
finish { caustics .9 }
}
}
Las ondulaciones que le hemos dado al plano del agua están pensadas para representar las pequeñas y
aleatorias crestas que se forman sobre una piscina cuando una ligera brisa sopla sobre ella. Podríamos
haber usado ripples o waves también, como si algo se hubiera zambullido en ella en algún punto,
pero bumps será suficiente para un ejemplo.
Observamos que nuestra vista del suelo de la piscina muestra docenas de pequeñas cáusticas,
correspondientes a un diseño de ondulaciones aleatorias. Si queremos podemos usar ripples o
waves y ver como cambia el diseño de la cáustica. A pesar de que un plano liso no produciría cáustica
por si mismo (podemos intentarlo sin la normal), la generación simulada de cáustica de POV-Ray sabe
que si la superficie fuera realmente abultada como esta normal está indicando, la refracción de esta sería
suficiente para concentrar la luz en cáusticas por todo el suelo de la piscina.
Vemos que al igual que con una superficie curva, como la anterior esfera, el diseño de la normal
también afecta a las cáusticas proyectadas por un objeto. Lo curioso del caso es que esto sería la prueba
de que la cáustica es simulada: a nuestra agua no se le ha dado ninguna propiedad de refracción en su
acabado, pero la cáustica está allí.
4.8.5. Halos
Nota importante: el halo es una característica experimental de POV-Ray 3.0. Hay una alta probabilidad
de que el diseño e implementación de estas características cambie en futuras versiones. No podemos
garantizar que las escenas que las usen den los mismos resultados en futuras versiones o que se
mantenga la compatibilidad de la sintaxis del lenguaje.
Los halos son una poderosa característica que puede ser usada para crear gran cantidad de efectos
distintos como nubes, niebla, fuego, láseres, etc. El nombre se debe a la posibilidad de trazar halos,
como los que se ven alrededor de la luna o del sol.
Debido a la complejidad del halo y de la gran cantidad de parámetros proporcionados es muy difícil
conseguir resultados satisfactorios. Las siguientes secciones ayudarán a crear un halo paso a paso,
empezando por lo más básico hasta llegar a los conceptos más sutiles.
Es también aconsejable leer las secciones de referencia para un mejor entendimiento de las
características de los halos. En especial las secciones "Objetos Vacíos y Objetos Sólidos" y "Mapeado
del Halo" debido a que son esenciales para entender los halos.
de densidad. Las partículas pueden emitir luz, para crear efectos de fuego o láseres, o absorberla para
crear nubes o niebla.
Un halo esta vinculado a un objeto, llamado objeto contenedor, al igual que un pigmento, una normal o
un acabado. El objeto contenedor esta completamente rellenado con el halo, pero no podremos ver
nada si no nos aseguramos de que el objeto es vacío y su superficie translúcida. Como se consigue esto
lo veremos en la siguiente sección.
Cuando trabajemos con los halos siempre tendremos que tener en cuenta que el objeto contenedor
tiene que ser vacío y translúcido.
En el primer ejemplo (HALO01.POV) intentamos crear una salvaje explosión, en la cual la esfera es el
objeto más adecuado. Empezamos con una simple escena que consiste de una cámara, una fuente de
luz (no nos preocupan las sombras así que añadimos el identificador shadowless), un plano a cuadros y
una esfera unitaria que contiene el halo.
camera {
location <0, 0, -2.5>
look_at <0, 0, 0>
}
plane { z, 2
pigment { checker color rgb 0, color rgb 1 }
finish { ambient 1 diffuse 0 }
scale 0.5
hollow
}
sphere { 0, 1
pigment { color rgbt <1, 1, 1, 1> }
halo {
emitting
spherical_mapping
linear
color_map {
[ 0 color rgbt <1, 0, 0, 1> ]
[ 1 color rgbt <1, 1, 0, 0> ]
}
samples 10
}
hollow
}
Observamos que la esfera está declarada como vacía (mediante el identificador hollow) y tiene una
superficie translúcida (el canal de transmitancia en el color de pigmento es 1), tal como es requerido
para los halos. También notamos que el plano tiene el identificador hollow a pesar de que no tiene
halo. ¿Por qué es necesario esto?
PERSISTENCE OF VISION RAYTRACER 103
La razón es bastante simple. Tal como se describe en la sección "Objetos Vacíos y Objetos Sólidos" no
puede haber un halo en un objeto no vacío. Ya que la cámara está dentro del plano, es decir, está en la
región considerada como interior del plano, el halo nunca será visto a no ser que el plano sea declarado
como vacío (o el identificador negative sea añadido para situar la cámara en la parte exterior del
plano).
¿Que significan todos esos identificadores y valores en el halo? Al principio de la declaración se usa el
identificador emitting para especificar que tipo de halo queremos usar. El halo emisor emite luz. Eso
es lo más adecuado para nuestra salvaje explosión.
Los identificadores spherical_mapping y linear necesitan una explicación más detallada de cono
funciona un halo (esto también es llevado a cabo en el capítulo "Halo" en más detalle).
Como se ha dicho anteriormente el halo está formado de una gran cantidad de pequeñas partículas. La
distribución de estas partículas es descrita por una función de densidad. En general, una función de
densidad nos dirá que cantidad de partículas encontraremos en una posición dada.
En lugar de usar una función matemática explícita de densidad, los halos se basan en un determinado
número de mapeados y funciones de densidad para modelar una variedad de distribuciones de
partículas.
El primer paso en este modelado es determinar la función de mapeado que será usada para asignar a
cada punto tridimensional un valor perteneciente a un rango unidimensional. En nuestro ejemplo
hemos usado un mapeado esférico, es decir, tomamos la distancia de un punto desde el origen del
sistema de coordenadas. Esa es la razón por la que es recomendable empezar con un objeto contenedor
situado en el origen del sistema de coordenadas. Ya que todos los mapeados de densidad son relativos a
este origen, no veremos nada si empezamos con un objeto situado en cualquier otro lugar. La forma
correcta de situar un objeto contenedor es mover todo el objeto (incluyendo texturas y halos).
Ahora tenemos un solo valor comprendido en un rango que va de 0 a 1. Este valor será transformado
usando una función de densidad para obtener esta a partir de la distancia. Usar solo este valor no es
suficiente debido a que queremos tener una distribución de partículas en la densidad descienda según
nos movemos desde el centro del objeto contenedor al exterior.
Esto se consigue mediante la función de densidad. Existen varias alternativas disponibles tal como se
describe en la referencia del halo (ver sección "Función de densidad"). Usamos una simple función
lineal que transforma los valores de rango de 0 a 1 a un rango de 1 a 0. De esta forma tenemos un valor
de 1 en el centro de nuestra esfera y de 0 en la superficie.
Ahora que tenemos una función de densidad, ¿qué hacemos para que se vea algo? Aquí es donde el
identificador color_map entra en juego. Se usa para describir un mapa de color que indicará al
programa que color debe ser usado para cada densidad. La relación es bastante simple: los colores al
principio del mapa de color (valores bajos) serán usados para valores bajos de densidad y los colores al
final del mapa (valores altos) serán usados para densidades altas. En nuestro ejemplo el halo será
amarillo en el centro de la esfera, donde la densidad es mayor y se irá transformando en rojo hasta llegar
a la superficie de la esfera donde la densidad se aproxima a cero.
El canal de transmitancia de los colores en el mapa de color sirve para modelar la translucidez del
campo de densidad. Un valor de 0 representa translucidez nula, es decir, que las áreas con la
correspondiente densidad serán (casi completamente) opacas, mientras que un valor de 1 significa (casi
completamente) translúcido.
4. TUTORIAL PARA PRINCIPIANTES 104
Hay un parámetro que todavía necesita ser explicado: el identificador samples. Este identificador le
dice a POV-Ray cuantas muestras deben ser tomadas a lo largo de cualquier rayo que viaje a través del
halo para calcular su efecto. El uso de un valor bajo resultará en una alta velocidad de trazado y
viceversa. El valor de samples debe ser incrementado si el halo tiene una apariencia incorrecta debido a
la baja tasa de muestreo. Para más detalles ver "Muestreo del Halo".
Esto se consigue usando el identificador turbulence junto con la cantidad de turbulencia que queremos
añadir. Tal como se muestra en el siguiente ejemplo.
sphere { 0, 1
pigment { color rgbt <1, 1, 1, 1> }
halo {
emitting
spherical_mapping
linear
turbulence 1.5
color_map {
[ 0 color rgbt <1, 0, 0, 1> ]
[ 1 color rgbt <1, 1, 0, -1> ]
}
samples 10
}
hollow
}
Añadir turbulencia al halo provoca que todos los puntos en el interior del objeto contenedor se muevan
de forma pseudo-aleatoria. El resultado es un cambio en la distribución de partículas como si se hubiera
producido un flujo o corriente en el interior del halo (dependiendo de la cantidad indicada que sigue al
identificador turbulence tendremos un flujo más uniforme o más turbulento). En este ejemplo usamos
un valor alto, ya que una explosión es altamente turbulenta.
Observando la imagen de ejemplo (HALO03.POV) vemos que se parece más a una salvaje explosión que a
la bola brillante que teníamos hasta ahora.
4. TUTORIAL PARA PRINCIPIANTES 106
Nos damos cuenta que el tiempo que tarda en ser trazada la imagen se ha incrementado al añadir la
turbulencia. Esto es debido al hecho de que por cada una de las muestras tomadas del halo, la lenta
función de turbulencia tiene que ser evaluada.
Tal como se dijo antes, la turbulencia mueve las partículas en el interior del objeto contenedor del halo.
El problema es que algunas de estas partículas son desplazadas fuera del objeto contenedor. Esto lleva a
altas densidades en la superficie del objeto revelando su forma (todas las partículas fuera del objeto
contenedor se pierden y no serán visibles resultando en un abrupto cambio de densidad en la
superficie).
Una forma fácil de evitar esto es asegurarnos de que las partículas permanecen en el interior del objeto
contenedor incluso si añadimos turbulencia. Esto se consigue escalando el halo para reducir su tamaño.
No escalamos el objeto contenedor, solo el halo.
}
El comando scale 0.5 indica a POV-Ray que escale todos los puntos dentro del halo por esta
cantidad. Esto efectivamente escala el radio que tenemos después del mapeado de densidad a un rango
de 0 a 0.5 en lugar de 0 a 1 (sin turbulencia). Si añadimos la turbulencia los puntos pueden moverse
media unidad en cualquier dirección sin abandonar el objeto contenedor. Esto es exactamente lo que
queremos.
Para compensar el menor tamaño del halo escalamos la esfera (y el halo interior) por 1.5.
La cantidad por la cual debemos escalar el halo depende de la cantidad de turbulencia que usemos. A
más turbulencia, menor deberá ser el halo. He aquí algo con lo que experimentar.
Otra forma de evitar que los puntos abandonen la esfera es que esta sea más grande, es decir, una esfera
con un radio mayor que uno. Es importante reescalar la esfera antes de añadir el halo debido a que de
otra forma el halo sería también escalado.
Notemos que esto solo funciona para el mapeado esférico y de caja (y una función de densidad no
constante). Todos los demás tipos de mapeado son (parcialmente) infinitos, es decir, la distribución de
partículas resultante cubre un espacio infinito (ver también "Mapeado del Halo").
La explicación, más bien matemática, usada aquí no ayuda mucho en entender como se utiliza esta
característica. Aunque es bastante simple. El valor de frecuencia solo le indica al programa cuantas
veces se tiene que repetir el mapa de color en el rango de densidad de 0 a 1. Si se tiene una frecuencia
de uno (el valor por defecto) se especifica que el mapa de color solo será visible una vez en el campo de
4. TUTORIAL PARA PRINCIPIANTES 108
densidad, es decir, el color en 0 será usado para densidad 0, el color en 0.5 para densidad 0.5 y el color
en 1 para densidad 1. Simple, ¿verdad?.
Si elegimos una frecuencia de dos, el color en 0 será usado para densidad 0, el color en 0.5 será usado
para densidad 0.25 y el color en 1 será usado para densidad 0.5. ¿Qué pasa para densidades superiores a
0.5? Ya que no hay entradas en el mapa de color para valor superiores a 1 simplemente volvemos a
empezar de 0 otra vez. De esta forma el color en 0.1 será usado para densidad 0.55 ((2*0.55) mod 1 =
1.1 mod 1 = 0.1), el color en 0.5 será usado para densidad 0.75 y el color en 1 será usado para densidad
1.
Si se nos dan bien la matemáticas notaremos que este ejemplo no es del todo correcto debido a que (1 *
2) mod 1 = 0 y no 1. Simplemente imaginemos que hemos usado un valor ligeramente menor que uno y
todo irá bien.
Deberíamos darnos cuenta de que para evitar cambios repentinos en el color del halo para frecuencias
mayores que uno tendríamos que usar un mapa de color periódico, es decir, un mapa de color cuyas
entradas en 0 y en 1 sean las mismas.
Cambiamos nuestro ejemplo usando un mapa de color periódico y cambiando el valor de la frecuencia a
dos.
sphere { 0, 1
pigment { color rgbt <1, 1, 1, 1> }
halo {
emitting
spherical_mapping
linear
turbulence 1.5
color_map {
[ 0.0 color rgbt <1, 0, 0, 1> ]
[ 0.5 color rgbt <1, 1, 0, -1> ]
[ 1.0 color rgbt <1, 0, 0, 1> ]
}
frequency 2
samples 20
scale 0.5
}
hollow
scale 1.5
}
PERSISTENCE OF VISION RAYTRACER 109
Observando el resultado de (HALO05.POV) podemos estar bastante satisfechos con la explosión que
hemos creado.
Todavía hay algo más a tener en cuenta cuando se incrementa la frecuencia. A menudo es necesario
incrementar la tasa de muestreo (samples) casi del mismo modo que incrementamos la frecuencia. Si
no hacemos esto probablemente notaremos graves efectos de aliasing (como saltos o bandas extrañas
de color). Si esto ocurre simplemente se ha de cambiar el valor de samples de acuerdo con el nuevo
valor de frequency (dos veces la tasa de muestreo si doblamos la frecuencia).
Eso es exactamente lo que nos hacía falta. Observando los resultados de HALO06.POV podemos quedar
algo decepcionados. ¿Donde está el centro rojo de la explosión? Los bordes son verdes como
esperábamos pero hay gran cantidad de amarillo en el centro y solo un poco de rojo. ¿Qué esta
pasando?
Usamos un halo emisor para nuestro ejemplo. De acuerdo con la correspondiente sección en el capítulo
de referencia del halo (ver "Emisor") este tipo de halo utiliza partículas muy pequeñas que no atenúan la
luz que atraviesa el halo. Especialmente las partículas cerca del observador no atenúan la luz
proveniente de partículas más lejanas.
Durante el cálculo del color del halo cerca del centro de la esfera contenedora, el rayo pasa a través de
casi todas las posibles densidades de la distribución de partículas. De esta manera tenemos partículas
rojas y verdes según avanzamos, dependiendo de la posición actual en el halo. Se usa la suma de estos
colores, lo que da el color amarillo (la suma del rojo y el verde es el amarillo). Esto es lo que ocurre
aquí.
¿Como podemos conseguir lo que queremos? La respuesta es usar un halo brillante en lugar de un halo
emisor. El halo brillante es muy similar al emisor excepto que el primero atenúa la luz que pasa a través
de él. De esta forma la luz de las partículas situadas detrás de otras será atenuada por estas últimas.
El halo brillante es muy similar al emisor con la diferencia de que también absorbe la luz. Podemos
verlo como una combinación del halo emisor y del atenuante descrito en la sección "El Halo
Atenuante".
A pesar de que el color rojo de las áreas de alta densidad no es muy visible debido a la coloración verde,
las áreas de baja densidad situadas al frente absorben la mayor parte de la luz roja, no vemos el color
amarillo donde hubiéramos esperado un color rojo.
Debido a su similitud con el halo emisor tenemos que experimentar con este tipo de halo. Solo tenemos
que retener en mente todo lo aprendido en las secciones previas pare obtener resultados satisfactorios.
Una gran diferencia entre el halo atenuante y los otros tipos de halos es que el color del halo atenuante
es calculado a partir del mapa de color usando la densidad total de partículas a lo largo de un rayo dado.
Los otros tipos utilizan una media pesada de los colores calculados a partir de la densidad en cada
muestra.
plane { z, 2
pigment { checker color rgb 0, color rgb 1 }
finish { ambient 1 diffuse 0 }
scale 0.5
hollow
}
4. TUTORIAL PARA PRINCIPIANTES 112
sphere { 0, 1
pigment { color rgbt <1, 1, 1, 1> }
halo {
attenuating
spherical_mapping
linear
color_map {
[ 0 color rgbt <1, 0, 0, 1> ]
[ 1 color rgbt <1, 0, 0, 0> ]
}
samples 10
}
hollow
}
A pesar de que normalmente las nubes no son rojas, si no blancas o grises, usamos el color rojo para
hacerla más visible contra el fondo a cuadros blancos y negros.
El color de un halo atenuante se calcula a partir de la densidad total acumulada después de que el rayo
haya atravesado por completo el campo de partículas. Esto debe ser tenido en cuenta cuando se
especifica el mapa de color. Queremos que las áreas de la nube con baja densidad sean altamente
translúcidas, así que usamos un color rgbt <1,0,0,1> y queremos que las áreas de alta densidad
sean opacas, así que usamos un color rgbt <1,0,0,0>.
Figura 34: El halo atenuante básico usado para crear una nube
Otra idea es escalar el objeto contenedor para obtener una forma elipsoide que puede ser usada para
modelar una nube de forma bastante efectiva. Esto se consigue con el comando scale
<1.5,0.75,1> al final de la declaración de la esfera. Escala ambos, la esfera y el halo interior.
sphere { 0, 1
pigment { color rgbt <1, 1, 1, 1> }
halo {
PERSISTENCE OF VISION RAYTRACER 113
attenuating
spherical_mapping
linear
turbulence 1
color_map {
[ 0 color rgbt <1, 0, 0, 1> ]
[ 1 color rgbt <1, 0, 0, -1> ]
}
samples 10
scale 0.75
}
hollow
scale <1.5, 0.75, 1>
}
Observando los resultados de HALO22.POV vemos que se parece más a una nube real (aparte del color).
Queremos modelar esta apariencia añadiendo dos halos adicionales a nuestro objeto contenedor (ver
sección "Múltiples Halos" para más detalles). Esto se consigue de la siguiente forma.
sphere { 0, 1.5
pigment { color rgbt <1, 1, 1, 1> }
halo {
attenuating
spherical_mapping
linear
turbulence 1
color_map {
[ 0 color rgbt <1, 0, 0, 1> ]
[ 1 color rgbt <1, 0, 0, -1> ]
}
samples 10
scale <0.75, 0.5, 1>
translate <-0.4, 0, 0>
}
4. TUTORIAL PARA PRINCIPIANTES 114
halo {
attenuating
spherical_mapping
linear
turbulence 1
color_map {
[ 0 color rgbt <1, 0, 0, 1> ]
[ 1 color rgbt <1, 0, 0, -1> ]
}
samples 10
scale <0.75, 0.5, 1>
translate <0.4, 0, 0>
}
halo {
attenuating
spherical_mapping
linear
turbulence 1
color_map {
[ 0 color rgbt <1, 0, 0, 1> ]
[ 1 color rgbt <1, 0, 0, -1> ]
}
samples 10
scale 0.5
translate <0, 0.2, 0>
}
hollow
}
Los tres halos utilizados solo difieren en su localización, es decir, en el vector de traslación que hemos
usado. Los dos primeros halos sirven para formar la base de la nube, mientras el último se encuentra
situado sobre estos. La esfera tiene un radio distinto que la previa debido a que se necesita más espacio
para los tres halos.
El resultado de HALO23.POV de alguna forma parece una nube, a pesar de que puede necesitar algunos
retoques.
halo atenuante. Además también la dispersan. Esto hace que los rayos de luz y las sombras proyectadas
por objetos sobre el halo sean visibles.
light_source {
<2.5, 2.5, -2.5>
colour rgb <1, 1, 1>
spotlight
point_at <0, 0, 0>
radius 12
falloff 15
tightness 1
}
difference {
box { -1, 1 }
box { <-1.1, -0.8, -0.8>, <1.1, 0.8, 0.8> }
box { <-0.8, -1.1, -0.8>, <0.8, 1.1, 0.8> }
box { <-0.8, -0.8, -1.1>, <0.8, 0.8, 1.1> }
pigment { color rgb <1, 0.2, 0.2> }
scale 0.5
rotate 45*y
rotate 45*x
}
Como vemos el objeto entero es iluminado por la fuente de luz. Ahora podemos empezar a añadir algo
de polvo.
4. TUTORIAL PARA PRINCIPIANTES 116
El resultado de HALO32.POV es prometedor pero el polvo es demasiado espeso y solo podemos ver
algunas partes del objeto y nada del fondo.
colour_map {
[ 0 color rgbt <1, 1, 1, 1.0> ]
[ 1 color rgbt <1, 1, 1, 0.7> ]
}
samples 10
}
hollow
scale 5
}
A parte de los feos efectos de aliasing la imagen queda mejor. Podemos ver el objeto entero e incluso el
fondo es ligeramente visible (HALO33.POV).
Jittering se usa para añadir algo de aleatoriedad a los puntos de muestreo haciendo que la imagen
parezca más irregular. Esto es mejor que los efectos de aliasing. Un bajo valor para jittering es una
buena elección.
El super-muestreo intenta reducir las diferencias tomando muestras adicionales en áreas de grandes
cambios de intensidad. El umbral en el cual se usa el super-muestreo y el nivel máximo de recursión
pueden ser especificados mediante los identificadores aa_threshold y aa_level respectivamente.
La manera de enfocar el problema que siempre funciona es incrementar la tasa general de muestreo. Ya
que también es el método más lento deberíamos usar los demás métodos primero. Si no son suficientes
tenemos que incrementar la tasa de muestreo.
colour_map {
[ 0 color rgbt <1, 1, 1, 1.0> ]
[ 1 color rgbt <1, 1, 1, 0.7> ]
}
samples 50
aa_level 3
aa_threshold 0.2
jitter 0.1
}
hollow
scale 5
}
La imagen tiene mejor apariencia ahora. prácticamente no queda ningún efecto de aliasing.
Los mismos parámetros que hemos usado son discutidos en la sección acerca de la atmósfera (ver "La
Atmósfera" para más explicaciones).
Otra forma interesante de conseguir una distribución irregular es añadir algo de turbulencia al polvo.
Esto se consigue con el identificador turbulence seguido de la cantidad de turbulencia que será
usada, como muestra el siguiente ejemplo (HALO35.POV).
box { -1, 1
pigment { colour rgbt <1, 1, 1, 1> }
halo {
dust
dust_type 1
box_mapping
linear
turbulence 1
colour_map {
[ 0 color rgbt <1, 1, 1, 1.0> ]
[ 1 color rgbt <1, 1, 1, 0.5> ]
PERSISTENCE OF VISION RAYTRACER 119
}
samples 50
aa_level 3
aa_threshold 0.2
jitter 0.1
}
hollow
scale 5
}
Deberíamos notar que usamos una función de densidad lineal en lugar de la función constante anterior.
Esto es necesario debido a que con una función constante la densidad tiene el mismo valor en todos los
puntos. El añadir turbulencia no tendría ningún efecto debido a que a donde quiera que los puntos sean
movidos el valor de la densidad tendrá el mismo valor. Solo una distribución de densidad no constante
tiene sentido cuando se añade turbulencia.
El hecho de que el valor de turbulencia sea un vector puede ser usado para crear efectos como cascadas
usando un gran valor de turbulencia en una sola dirección (por ejemplo turbulence
<0.2,1,0.2>).
Usamos un mapa de color para obtener un filtrante polvo rojo por ejemplo:
colour_map {
[ 0 color rgbft <1, 0, 0, 0.5, 1.0> ]
[ 1 color rgbft <1, 0, 0, 0.5, 0.7> ]
}
4. TUTORIAL PARA PRINCIPIANTES 120
Algunos de los problemas y dificultades más comunes son descritas a continuación para ayudarnos a
evitarlos.
No podremos ver las propiedades del interior observando la superficie. Simplemente no es posible.
Esto siempre se debe tener en cuenta.
Si el ejemplo anterior fue pensado para crear una esfera rellenada con un halo y cubierta por una textura
a cuadros que ocultara en parte el halo tendríamos que haber empleado la siguiente sintaxis:
sphere { 0, 1
pigment {
checker
texture {
pigment { color Clear }
}
texture {
pigment { color Red }
}
}
halo { ... }
hollow
}
Un halo siempre se aplica a un objeto de la siguiente forma:
OBJECT {
texture {
pigment { ... }
normal { ... }
finish { ... }
halo { ... }
}
hollow
PERSISTENCE OF VISION RAYTRACER 121
}
No se permite un halo en la declaración de un pigmento, de un mapa de color, de un mapa de
pigmento, de un mapa de material o de cualquier otra cosa. No se nos impide hacerlo pero no
obtendremos los resultados que queremos.
Podemos usar halos con texturas superpuestas siempre que nos aseguremos de que los halos solo están
vinculados a la capa inferior (que por supuesto debe ser transparente para que se pueda ver el halo).
Si queremos añadir distintos halos tenemos que ponerlos todos en el interior de un solo objeto
contenedor para asegurarnos de que el halo se calcula de forma correcta (ver también "Múltiples
Halos").
También deberíamos observar que cuando tenemos varios objetos contenedores muy próximos unos a
otros pero sin superposición real, son tratados de forma correcta. Si ponemos un objeto contenedor en
frente de otro los halos son trazados correctamente.
Escalar el objeto antes de la declaración del halo solo escalara el objeto contenedor, no el halo. Esto es
útil cuando queremos evitar que la superficie del objeto contenedor sea visible debido al uso de la
turbulencia. Como hemos aprendido en las secciones anteriores, las partículas pueden moverse fuera del
objeto contenedor, donde son invisibles, si se añade turbulencia. Esto solo funciona para el mapeado
esférico y el mapeado de caja debido a que los campos de densidad descritos por los otros mapeados no
tienen dimensiones finitas.
Si se usa el identificador scale después de la declaración del halo, ambos, el halo y el objeto contenedor
son escalados. Esto es útil para escalar el halo según nuestras necesidades.
El halo mantiene su apariencia a pesar de las transformaciones aplicadas al objeto contenedor (después
del halo), es decir, la translucidez, el color y la turbulencia del halo no cambiarán.
4. TUTORIAL PARA PRINCIPIANTES 122
La apariencia del halo es independiente de la tasa de muestreo siempre que se tomen las suficientes
muestras para describir correctamente su forma. Esto significa que una o dos muestras difícilmente
serán suficientes para determinar la apariencia del halo. Según vamos incrementando el número de
muestras el halo se aproximará rápidamente a su apariencia real.
En pocas palabras, el halo no cambiará su apariencia con la tasa de muestreo siempre que tengamos el
suficiente número de muestras y no nos encontremos con los efectos del aliasing.
Siempre que añadamos turbulencia a un halo debemos evitar la función de densidad constante.
Para experimentar con algunas de las excitantes opciones de textura, preparemos una escena básica, a la
que aplicaremos las texturas que diseñemos más adelante. Empecemos llamando a los archivos de
inclusión de colores y texturas predefinidos, y poniendo una cámara y una fuente de luz.
#include "colors.inc"
#include "textures.inc"
camera {
orthographic
up <0, 5, 0>
right <5, 0, 0>
location <0, 0, -25>
look_at <0, 0, 0>
}
plane { -z, 0
pigment {
gradient x
pigment_map {
[ 0.0 Pigment1 ]
[ 0.5 Pigment2 ]
[ 1.0 Pigment1 ]
}
}
}
Vale, lo que hemos hecho es sencillo y probablemente fácil de entender si hemos trabajado
anteriormente con mapas de colores. Hemos colocado un mapa de pigmentos donde suele ir un mapa
de colores, y hemos situado nuestros pigmentos predeclarados como entradas del mapa. Cuando vemos
la imagen, observamos un patrón a bandas de cuadrados negros y de anillos concéntricos, de forma que
las transiciones entre un patrón y otro son suaves, mezclándose ambos patrones en el centro de los
cambios. También podemos hacer transiciones bruscas, retocando algo el mapa de pigmentos.
pigment_map {
[ 0.0 Pigment1 ]
[ 0.5 Pigment1 ]
[ 0.5 Pigment2 ]
[ 1.0 Pigment2 ]
}
La sintaxis de la instrucción es la que podíamos esperar. Hemos cambiado el tipo de mapa, poniéndolo
esta vez en el bloque de normal, y hemos colocado como parámetros tipos de normal. Recordemos que
en POV-Ray 3, todos los patrones que funcionan como colores funcionan como normales, y viceversa,
así que podemos cambiar de madera a granito, por ejemplo. Deberíamos investigar un poco esto, para
entender el aspecto que pueden tener estos patrones como normales.
Tras ver lo interesante que puede ser mezclar dos patrones en las transiciones, quizá queramos construir
una textura en la que dos patrones se mezclen completamente. Esto es posible usando la función
“average”. Volveremos a esto más adelante.
plane { -z, 0
rotate y * 30
texture {
gradient y
texture_map {
[ 0.0 Texture1 ]
[ 0.4 Texture1 ]
[ 0.6 Texture2 ]
[ 1.0 Texture2 ]
}
scale 2
}
}
¿Qué hemos hecho? El plano de fondo alterna verticalmente entre dos texturas, idénticas excepto en su
acabado. Cuando lo convertimos en una imagen, el cilindro se refleja en unas zonas del plano y en otras
no. Con pequeñas adaptaciones, podemos usar esta idea con cualquier patrón, mezclando cualquier tipo
de acabado que se nos ocurra. Podemos dar a diferentes partes de un objeto diferentes acabados o
diferentes texturas completas.
Una pregunta: si existe un mapa de texturas, ¿para qué necesitamos un mapa de pigmentos, o de
normales? Sencillo: velocidad de cálculo. Si usamos un mapa de texturas, para cada punto afectado,
POV-Ray hace los cálculos correspondientes a todas las texturas, después realiza un cálculo (media
ponderada) entre los resultados que promedia el valor que corresponde al punto. Usar un mapa de
pigmentos (o de normales) reduce el número de cálculos, ya que algunas partes de la textura se calculan
una sola vez. Como regla, usaremos preferentemente mapas de normales o pigmentos, dejando los de
texturas para cuando lo que queramos sea imposible hacerlo de otra forma.
PERSISTENCE OF VISION RAYTRACER 125
Por supuesto, esto también funciona con pigmentos completos, normales, e incluso texturas enteras,
igual que los otros patrones anteriormente citados. La única diferencia es que escribimos los datos tras
el patrón (como con los colores individuales), en lugar de preparar un mapa de la forma anterior.
Pongamos un ejemplo. Borramos el plano y los pigmentos declarados de nuestro último ejemplo, y
escribimos lo siguiente:
#declare Pigment1 = pigment {
hexagon
color Yellow color Green color Grey
scale .1
}
box { -5, 5
pigment {
hexagon
pigment {Pigment1}
pigment {Pigment2}
pigment {Pigment3}
rotate 90*x
}
}
Empezamos por declarar un ejemplo de cada uno de los patrones como pigmentos individuales.
Después, usamos el patrón hexagonal como una lista de pigmentos, usando los pigmentos predefinidos
en esta lista, en lugar de colores individuales. Hay dos instrucciones de girado en este ejemplo, ya que
los ladrillos se alinean en dirección z (para cubrir una pared, por defecto), mientras que los hexágonos lo
hacen en dirección y (cubriendo un suelo), mientras que nosotros queremos que todos queden frente a
la dirección z, que es hacia donde mira la cámara.
Por supuesto, en POV-Ray 3, todo lo que vale para pigmentos, vale para normales o texturas enteras. A
continuación vemos algunos ejemplos de su uso.
normal {
brick
normal {granite .1}
normal {bumps 1 scale .1}
}
o...
texture {
checker
texture {Gold_Metal}
4. TUTORIAL PARA PRINCIPIANTES 126
texture {Silver_Metal}
}
Podemos ver cómo ha cambiado la declaración del mapa de normales. El valor decimal que precedía
cada entrada del mapa ha desaparecido. Este número indicaba en qué punto se iniciaba la mezcla entre
uno y otro, y ahora la mezcla se realiza en todo el objeto. De hecho, el promedio no usa esos valores
como esperamos, si no como pesos para las mezclas, e incluirlos puede dar lugar a resultados
imprevistos.
¿Y bien? Es difícil crear una textura que reúna todas esas condiciones. Quizá el lector esté pensando en
pegar una imagen simulando este efecto, pero aún queda una solución: superponer varias texturas.
Sólo tenemos que especificar una serie de varias texturas, una tras otra, asociadas al mismo objeto. Se le
aplicarán como capas de pintura, una tras otra, en el orden en que aparezcan.
PERSISTENCE OF VISION RAYTRACER 127
Es importante que recordemos asignar un grado de transparencia (filtro o transmitancia) a parte de las
texturas que situemos en las capas superiores, ya que en caso contrario las inferiores no servirán para
nada. No recibiremos ningún mensaje de error, técnicamente es legal, sencillamente no tiene sentido. Es
como pasarse horas pintando una imagen elaborada en un muro, para después darle una capa de látex
blanco encima, ocultándola totalmente.
Diseñemos un objeto muy simple con texturas superpuestas y observemos cómo funciona. Creamos un
archivo llamado LAYTEX.POV y escribimos:
#include "colors.inc"
#include "textures.inc"
camera {
location <0, 5, -30>
look_at <0, 0, 0>
}
} // (fin de la caja)
Bueno. Esto se complica, así que para hacerlo más sencillo de entender, hemos incluido comentarios
explicando lo que hace cada parte, y dónde acaba. Para empezar, sólo creamos una caja sobre un suelo
ajedrezado típico, y dimos al cielo de fondo un tono de azul liso. Y después...
4. TUTORIAL PARA PRINCIPIANTES 128
Para empezar, dimos a la caja la textura Silver_Metal, declarada en TEXTURES.INC (si quieres nota,
mira en el archivo indicado y comprueba que esta textura figura ahí). Para dar impresión de desgaste,
hemos añadido un patrón de normal abollado (dents). Esto produce la sensación de que nuestra
misteriosa caja metálica ha sido golpeada.
Las pequeñas manchas de óxido no son mas que un patrón granito que varía de rojo oscuro a marrón y
después pasa de golpe a ser totalmente transparente, siendo así la mayor parte del mapa de color. Vale,
probablemente habríamos conseguido un patrón de manchas más realista usando mapas de pigmentos,
pero eso corresponde a otra sección del manual, así que no lo pensemos por ahora.
Por último, hemos añadido otra textura al bloque. La distribución llamada bozo varía desde centros
oscuros a gris semi-transparente y después se vuelve totalmente transparente durante la mitad del mapa
de colores. Da aspecto de manchas oscuras (quizá producidas por fuego) que están adheridas a la
superficie de la caja (por encima de las manchas de óxido). El resultado final es un misterioso bloque
metálico ciertamente maltratado, de una forma en la que una sola textura no habría podido nunca.
Una última aclaración sobre las texturas: si utilizamos texturas superpuestas, declaradas o no, debemos
olvidarnos de las abreviaturas para texturas (escribir sólo el pigmento, o sólo el acabado...), ya que este
método no se extiende a este tipo de texturas. Podemos apilar texturas completas, no trozos de textura.
Lo siguiente:
#declare Bad_Texture =
texture { /* insert your base texture here... */ }
pigment { Red filter .5 }
normal { bumps 1 }
no funcionará. El pigmento y la normal no son parte definida de una textura, Podemos escribirlos así si
no hubiese una textura base, pero así generará un error.
Creamos una escena que contiene cuatro cajas. La primera de ellas tendrá la textura base a cuadros rojos
y blancos, que usaremos de punto de partida, la segunda añade una capa que ensucia la tela de forma
realista, la tercera añade algo de vino a la tela, y la cuarta coloca unas pocas arrugas (no otra textura
superpuesta, aunque debemos fijarnos qué cambios en la textura provocan este efecto en el resultado).
PERSISTENCE OF VISION RAYTRACER 129
Empezamos situando una cámara, luces, y la primera caja. En este momento, la textura no es
superpuesta, claro. Observa el archivo LAYERED1.POV.
#include "colors.inc"
camera {
location <0, 0, -6>
look_at <0, 0, 0>
}
#declare PLAIN_TEXTURE =
// cuadros blancos y rojos
texture {
pigment {
checker
color rgb<1.000, 0.000, 0.000>
color rgb<1.000, 1.000, 1.000>
scale <0.2500, 0.2500, 0.2500>
}
}
Primero añadiremos una capa con dos grises distintos, parcialmente transparentes. Los distribuiremos
en cuadrícula, de la misma forma que antes, aunque usaremos algo de turbulencia para hacer más
realista el oscurecimiento. Añadimos la siguiente caja a la escena previa y reconstruimos la imagen.
#declare FADED_TEXTURE =
// cuadrados rojos y blancos
texture {
pigment {
checker
color rgb<0.920, 0.000, 0.000>
color rgb<1.000, 1.000, 1.000>
scale <0.2500, 0.2500, 0.2500>
}
}
// grises para oscurecer el rojo y blanco
texture {
pigment {
checker
color rgbf<0.632, 0.612, 0.688, 0.698>
color rgbf<0.420, 0.459, 0.520, 0.953>
turbulence 0.500
scale <0.2500, 0.2500, 0.2500>
}
}
Como hay una botella de vino en la escena, pensamos que sería un toque interesante añadir una o dos
manchas. Este efecto puede lograrse situando una burbuja muy plana en la tela, aunque lograríamos el
efecto del vino derramado, no de la mancha producida. Es el momento de añadir otra capa.
// caja sucia
Queremos añadir otro toque, en forma de algunas arrugas en el mantel. Aunque esto no significa añadir
una capa nueva, debemos tener en cuenta que hay que hacerlo sobre la última capa, ya que no tiene
ningún efecto modificar la normal de las capas inferiores (aunque las superiores sean totalmente
transparentes).
#declare WRINKLED_TEXTURE =
// cuadros rojos y blancos
texture {
pigment {
checker
color rgb<0.920, 0.000, 0.000>
color rgb<1.000, 1.000, 1.000>
scale <0.2500, 0.2500, 0.2500>
}
}
// grises para oscurecer
texture {
pigment {
checker
color rgbf<0.632, 0.612, 0.688, 0.698>
color rgbf<0.420, 0.459, 0.520, 0.953>
turbulence 0.500
scale <0.2500, 0.2500, 0.2500>
}
}
// manchas de vino
texture {
pigment {
spotted
color_map {
[ 0.000 color rgb<0.483, 0.165, 0.165> ]
[ 0.329 color rgbf<1.000, 1.000, 1.000, 1.000> ]
[ 0.734 color rgbf<1.000, 1.000, 1.000, 1.000> ]
[ 1.000 color rgb<0.483, 0.165, 0.165> ]
}
turbulence 0.500
frequency 1.500
}
normal {
wrinkles 5.0000
}
}
// caja arrugada
Una nota: los comentarios para la normal no son válidos para los acabados. Si una capa tiene reflexión
especular, y la superior no, donde la capa superior sea transparente veremos la reflexión especular.
Como en los otros casos, necesitamos un archivo que contenga la imagen original que será utilizada por
POV-Ray para decidir el tipo de textura que aplicará a cada punto, y especificar qué textura va asociada
a cada uno de los índices de la paleta de la imagen. Para construir dicha imagen, necesitamos que el
programa de dibujo nos deje elegir los colores por su índice (el color es irrelevante, sólo importa el
índice que va a ocupar en la paleta). Si tenemos el paquete completo que viene con POV-Ray,
tendremos entre los ficheros de inclusión una imagen llamada POVMAP.GIF, que sólo usa los cuatro
primeros colores de la paleta para dibujar un cuadro con las palabras “Persistence of Vision” dentro.
Esta imagen servirá de muestra en nuestro próximo ejemplo. Usando de nuevo nuestra cámara y luz de
siempre, y los ficheros de inclusión más típicos, completamos el fichero con el siguiente objeto:
plane { -z, 0
texture {
material_map {
gif "povmap.gif"
interpolate 2
once
texture { PinkAlabaster } // borde interno
texture { pigment { DMFDarkOak } } // borde externo
texture { Gold_Metal } // letras
texture { Chrome_Metal } // el panel
}
translate <-0.5, -0.5, 0>
scale 5
}
}
La posición de las luces y la ausencia de fondo puede que no dejen que la imagen tenga demasiada
brillantez, pero podremos ver cómo funciona este proceso. Las texturas son situadas sencillamente
según los colores de la imagen. Al usar la palabra clave “once” (para no repetir la imagen en la textura) y
trasladar y escalar la imagen, la vemos al completo delante de nuestra cámara.
Por supuesto, esto sólo funciona con imágenes con paleta, como las GIF y algunos tipos de PNG. Sin
embargo, sí pueden usarse imágenes sin paletas para construir algunos efectos. Veamos cómo usar
POV-Ray para producir imágenes de este tipo para él mismo.
Para empezar, si usamos una imagen sin paleta, POV-Ray sólo hace caso a los ocho bits del color rojo
para determinar qué textura usa. Necesitamos controlar perfectamente el color que van a tener los
píxeles de nuestra imagen, cosa que podemos lograr si
¿Confundido? Bien, pongamos un ejemplo. Generaremos un mapa de bits muy similar a POVMAP.GIF,
excepto que será en formato TGA. Le vamos a dar color verde y azul, pero esto es sólo para que
nosotros, las personas, podamos distinguir cómodamente los colores, ya que no podemos apreciar
variaciones de rojo de 1/255 unidades. Sin esas variaciones, la imagen aparecería negra a nuestros ojos,
de forma que podríamos usar POV-Ray para enviar mensajes secretos, aunque no es ese el uso que le
queremos dar. Queremos ver qué aspecto va a tener nuestra imagen.
plane { -z, 0
pigment { rgb <1/255, 0, 0.5> }
finish { ambient 1 }
}
La otra limitación es más grave, aunque también se puede esquivar. Al trabajar con texturas
superpuestas, hemos visto que podíamos apilar una sobre otra indefinidamente (siempre y cuando
hubiese transparencia en las superiores). Esta técnica tan útil tiene, sin embargo, problemas cuando se
usa como base las texturas especiales que mencionábamos. ¡Aunque hay una solución!
Por ejemplo, supongamos que tenemos una textura llamada “Speckled_Metal”, que produce una
superficie metálica plateada, y ponemos pequeñas manchas de óxido sobre ella. Supongamos que
entonces , para más realismo, decidimos poner manchas de óxido más realistas sobre la superficie. Uno
de los métodos es crear un mapa de texturas con transparencias para usar como capa superior. Sin
embargo, obtendremos un mensaje de error si lo intentamos. La solución que se propone es hacer
nuestra textura parte del mapa de texturas empleados, de la forma siguiente:
// Declaramos un pigmento que
// usaremos en las manchas de óxido
#declare Rusty = pigment {
granite
color_map {
4. TUTORIAL PARA PRINCIPIANTES 134
// Aquí se aplica
// Observa que nuestra textura original
// "Speckled_Metal" ahora es parte del mapa
#declare Rust_Patches = texture {
bozo
texture_map {
[ 0.0 pigment {Rusty} ]
[ 0.75 Speckled_Metal ]
[ 1.0 Speckled_Metal ]
}
}
Y el efecto es el mismo que si hubiésemos superpuesto las manchas de óxido en la superficie pulida.
Usando los patrones, pigmentos, normales, acabados, capas y texturas especiales no hay nada
prácticamente que no podamos crear como textura. ¡Una casi infinita variedad de posibilidades nos
esperan!
Es fácil asignar un color simple o un complicado diseño a una esfera celeste virtual (sky_sphere).
Puedes crear cualquier cosa, desde un azul y despejado cielo de verano hasta uno densamente nublado y
tormentoso. Incluso un cielo estrellado puede ser creado fácilmente.
Puedes usar distintos tipos de nieblas para crear escenas brumosas. Múltiples capas de niebla de
distintos colores pueden dar un toque siniestro a tu escena.
Un efecto mucho más realista se consigue usando una atmósfera, una niebla constante que interactúa
con la luz proveniente de las fuentes. Los rayos de luz se tornan visibles y los objetos proyectan
sombras sobre la niebla.
4.10.1. Background
La característica background se usa para asignar un color a todos los rayos que no incidan sobre
ningún objeto. Se usa de la siguiente forma.
camera {
location <0, 0, -10>
look_at <0, 0, 0>
}
sphere { 0, 1
pigment { color rgb <0.8, 0.5, 0.2> }
}
El color asignado al fondo será visible al usar una esfera celeste solo si queda algo de translucidez
después de que las capas de pigmento de esta sean procesadas.
PERSISTENCE OF VISION RAYTRACER 135
En los siguientes ejemplos empezaremos con una esfera celeste muy simple que se irá volviendo cada
vez más y más compleja según vayamos añadiendo nuevas características.
Podemos advertir que el color del cielo varía según el ángulo con la normal al plano de superficie. Si
miras directamente hacia arriba el cielo tendrá el color de un azul más profundo que en el horizonte.
Queremos modelar este efecto usando una esfera celeste como se muestra en la siguiente escena
(SKYSPH1.POV).
#include "colors.inc"
camera {
location <0, 1, -4>
look_at <0, 2, 0>
angle 80
}
sphere { 2*y, 1
pigment { color rgb <1, 1, 1> }
finish { ambient 0.2 diffuse 0 reflection 0.6 }
}
sky_sphere {
pigment {
gradient y
color_map {
[0 color Red]
[1 color Blue]
}
scale 2
translate -1
}
}
La parte interesante es la declaración de la esfera celeste. Contiene un pigmento que describe la
apariencia de la esfera. Queremos crear un gradiente de colores a lo largo del ángulo de visión medido
contra la normal al plano de superficie. Ya que el vector director será usado para calcular los colores del
pigmento tenemos que usar el gradiente y.
Las transformaciones de translación y escalado se usan para distribuir los puntos derivados del vector
director a un rango adecuado. Sin estas transformaciones el diseño sería repetido dos veces sobre la
esfera celeste. El escalado se usa para evitar la repetición y la sentencia translate -1 para mover el
color correspondiente al índice 0 al fondo de la esfera (al punto que verías si miraras directamente hacia
abajo).
4. TUTORIAL PARA PRINCIPIANTES 136
Después de estas transformaciones la entrada de color en la posición 0 del mapa de color estará en el
fondo de la esfera, es decir, por debajo de nosotros y el color en la posición 1 estará en lo más alto, es
decir, por encima de nosotros.
Los colores para el resto de las posiciones son interpolados entre estos dos colores tal como puedes ver
en la imagen resultante.
Si quieres que uno de los colores empiece a partir de un ángulo específico primero tienes que convertir
el ángulo a un índice del mapa de color. Esto se hace usando la fórmula
1 − Cos(angulo)
indice _ mapa _ color =
2
donde el ángulo se mide contra la normal (en el sentido negativo) al plano de superficie. Podríamos
decir que es la normal que apunta al centro de la tierra. Un ángulo de 0 grados describe el punto justo
debajo de nosotros, mientras que un ángulo de 180 representaría el cenit.
En POV-Ray debes primero convertir el valor en grados a radianes como se muestra en el siguiente
ejemplo.
sky_sphere {
pigment {
gradient y
color_map {
[(1-cos(radians( 30)))/2 color Red]
[(1-cos(radians(120)))/2 color Blue]
}
scale 2
translate -1
}
}
Esta escena usa un gradiente de colores que empieza con un rojo a los 30 grados y se transforma en
azul a los 120 grados. Por de bajo de 30 grados todo es de color rojo, mientras que por encima de los
120 todo es azul.
PERSISTENCE OF VISION RAYTRACER 137
La esfera celeste que usamos es mostrada a continuación. También se ha añadido un plano de suelo
para mayor realismo (SKYSPH2.POV).
sky_sphere {
pigment {
gradient y
color_map {
[0.000 0.002 color rgb <1.0, 0.2, 0.0>
color rgb <1.0, 0.2, 0.0>]
[0.002 0.200 color rgb <0.8, 0.1, 0.0>
color rgb <0.2, 0.2, 0.3>]
}
scale 2
translate -1
}
rotate -135*x
}
plane { y, 0
pigment { color Green }
finish { ambient .3 diffuse .7 }
}
El diseño del gradiente y las transformaciones dentro del pigmento son las mismas que en el ejemplo de
la sección anterior.
El mapa de color consiste de tres colores. Un rojo brillante y ligeramente amarillento es usado para el
sol, un rojo más oscuro para el halo y un azul oscuro para el cielo nocturno. El color del sol tan solo
cubre una pequeña parte de la esfera celeste debido a que no queremos que tenga un tamaño demasiado
grande. El color se usa en los valores 0.000 y 0.002 del mapa de color para obtener un acusado
contraste en el valor 0.002 (no queremos que el sol se funda con el cielo). El rojo más oscuro usado
para el halo se funde con el azul del cielo entre los valores 0.002 y 0.200 del mapa de color. Todos los
valores por encima de 0.200 mostrarán el color azul oscuro del cielo.
La sentencia rotate -135*x se usa para rotar tanto el sol como el cielo a su posición final. Si esta rotación
el sol estaría situado a 0 grados, es decir, por debajo de nosotros.
4. TUTORIAL PARA PRINCIPIANTES 138
Observando la imagen resultante podemos ver los impresionantes efectos que podemos conseguir con
la esfera celeste.
La esfera celeste tiene un inconveniente como podrás haber notado al observar la imagen final
(SKYSPH3.POV). El sol no emitirá ninguna luz y las nubes no proyectarán ninguna sombra. Si quieres
tener nubes que proyecten sombras tendrás que usar una esfera corriente de gran tamaño con la textura
adecuada y una fuente de luz situada en algún lugar en el exterior de la esfera.
4.10.3. La niebla
Puedes usar la característica fog para añadir niebla de dos tipos distintos a tu escena: niebla constante y
niebla de suelo. La primera tiene una densidad constante en todos los puntos mientras que en la
segunda la densidad decrece según nos movemos hacia arriba.
El valor de distance determina la distancia a la cual el 36.8% del fondo es todavía visible (para una
explicación más detallada sobre como se calcula la niebla leer la sección de referencia "Niebla").
El color de la niebla puede ser usado para crear cualquier cosa desde una niebla de un color blanco
inmaculado hasta un rojo sangre. También puedes usar una niebla negra para simular el efecto de un
limitado rango de visión.
El siguiente ejemplo muestra como añadir niebla a una escena simple (FOG1.POV).
#include "colors.inc"
camera {
location <0, 20, -100>
}
plane { y, -10
pigment {
4. TUTORIAL PARA PRINCIPIANTES 140
fog {
distance 150
colour rgb<0.3, 0.5, 0.2>
}
Las esferas en esta escena se desvanecen, en mayor o en menor medida dependiendo de su distancia, en
la niebla verdosa, al igual que el plano a cuadros.
la translucidez de la niebla nunca cae por debajo del 20% como puedes ver en la imagen resultante
(FOG2.POV).
Te habrás dado cuenta de que no solo disminuye la intensidad de los objetos en la niebla debido al color
de esta, si no que también los colores son influenciados. La esfera roja y especialmente la azul obtienen
un matiz de verde.
El identificador turbulence es usado para especificar la cantidad de turbulencia usada mientras que el
valor asociado a turb_depth es usado para mover el punto en el cual es calculado el valor de la
turbulencia a lo largo de la línea de visión. Valores cercanos a cero mueven el punto hacia el observador
mientras que los valores cerca de uno lo mueven hacia el punto de intersección (el valor por defecto es
0.5). Este parámetro puede ser usado para evitar los fallos que puedan aparecer en la niebla debido a la
turbulencia (esto ocurre normalmente en puntos de intersección muy alejados, especialmente si la
intersección no tiene lugar, es decir, ocurre directamente sobre el fondo). Si esto ocurre simplemente
hay que disminuir el valor de turb_depth hasta que el fallo desaparezca.
Deberías tener en cuenta que la densidad de la niebla no cambia. Solo el valor de la atenuación basado
en la distancia es modificado por el valor de la turbulencia en un punto a lo largo de la línea de visión.
El siguiente ejemplo (FOG5.POV) usa una niebla de suelo que tiene una densidad constante por debajo
de y=25 (el centro de la esfera roja) y disminuye rápidamente para altitudes superiores.
fog {
distance 150
colour rgbf<0.3, 0.5, 0.2, 1.0>
fog_type 2
fog_offset 25
fog_alt 1
}
4. TUTORIAL PARA PRINCIPIANTES 144
Figura 49: La niebla de superficie sólo cubre las partes más bajas
del mundo
fog {
distance 150
colour rgb<0.5, 0.1, 0.1>
fog_type 2
fog_offset 15
fog_alt 4
turbulence 0.2
turb_depth 0.2
}
fog {
distance 150
colour rgb<0.1, 0.1, 0.6>
fog_type 2
fog_offset 10
fog_alt 2
}
PERSISTENCE OF VISION RAYTRACER 145
Puedes combinar nieblas de densidad constante, de suelo, nieblas filtrantes y no filtrantes, nieblas
translúcidas, etc.
Para evitar este problema debes hacer que todos esos objetos sean vacíos asegurándote de que la cámara
se encuentra fuera de ellos (usando el identificador inverse) o añadiéndoles el identificador hollow
(que es mucho más fácil).
4.10.4. La atmósfera
Nota importante: la atmósfera es una característica experimental de POV-Ray 3.0. Hay una alta
probabilidad de que el diseño e implementación de estas características cambie en futuras versiones. No
podemos garantizar que las escenas que las usen den los mismos resultados en futuras versiones o que
se mantenga la compatibilidad de la sintaxis del lenguaje.
La atmósfera puede ser usada para modelar la interacción de la luz con las partículas suspendidas en el
aire. Los rayos de luz se volverán visibles y los objetos proyectarán sombras sobre la niebla o el polvo
del aire.
El modelo atmosférico usado en POV-Ray supone una densidad constante de partículas en todos los
puntos excepto en los objetos sólidos. Si quieres crear nieblas o humos con la apariencia de nubes
deberás usar la propiedad halo de las texturas descrita en la sección "Halos".
Imagina una sencilla habitación con una ventana. La luz entra a través de la ventana y es dispersada por
las partículas de polvo que flotan en el aire. Lo que verías serían unos rayos de luz provenientes de la
ventana reflejandose sobre el suelo.
Queremos modelar esta escena paso a paso. Los ejemplos siguientes empiezan con la habitación, la
ventana y un foco (spotlight) en algún lugar en el exterior de la habitación. De momento no hay
ninguna atmósfera para que podamos verificar si la iluminación es la correcta (ATMOS1.POV).
camera {
location <-10, 8, -19>
look_at <0, 5, 0>
angle 75
}
light_source {
<40, 25, 0> color rgb <1, 1, 1>
spotlight
point_at <0, 5, 0>
radius 20
falloff 20
atmospheric_attenuation on
}
union {
difference {
box { <-21, -1, -21>, <21, 21, 21> }
box { <-20, 0, -20>, <20, 20, 20> }
box { <19.9, 5, -3>, <21.1, 15, 3> }
}
box { <20, 5, -0.25>, <21, 15, 0.25> }
box { <20, 9.775, -3>, <21, 10.25, 3> }
pigment { color red 1 green 1 blue 1 }
finish { ambient 0.2 diffuse 0.5 }
}
La fuente de luz puntual se ha usado para iluminar la habitación desde el interior sin ninguna
interacción con la atmósfera. Esto se hace añadiendo atmosphere off. No nos tendremos que
preocupar de esta fuente de luz cuando añadamos la atmósfera más tarde.
PERSISTENCE OF VISION RAYTRACER 147
El objeto unión es usado para modelar la habitación y la ventana. Ya que usamos la diferencia entre dos
cajas para modelar la habitación (las primeras dos cajas en la declaración difference) no hay
necesidad de usar el identificador hollow. Si estamos dentro de esta habitación, estaremos fuera del
objeto (ver también "Usando Objetos Vacíos y la Atmósfera").
Siempre puedes empezar con un número arbitrario de muestras. Si los resultados no te satisfacen,
puedes incrementar la tasa de muestreo para obtener mejores resultados. El problema de elegir una
buena tasa de muestreo es mantener el equilibrio entre una imagen satisfactoria y una rápido trazado.
Una alta tasa de muestreo casi siempre funcionará bien, pero el trazado de la imagen también consumirá
mucho tiempo. He aquí algo con lo que experimentar.
El identificador distance especifica la densidad de la atmósfera. Funciona del mismo modo que el
parámetro distance del efecto niebla (fog).
Por último pero no menos importante, el valor del identificador scattering determinará la cantidad
de luz que es dispersada por las partículas (la luz restante es absorbida). Como verás más tarde este
parámetro es muy útil para ajustar el brillo medio de la atmósfera.
4. TUTORIAL PARA PRINCIPIANTES 148
Observando la imagen creada a partir de la escena anterior notarás algunos efectos de aliasing bastante
desagradables conocidos como mach-bands. Son el resultado de una baja tasa de muestreo.
Una posible solución es incrementar la tasa de muestreo hasta que los efectos desaparezcan y obtengas
una imagen satisfactoria. A pesar de que esto siempre funcionará, es una mala idea debido a que
consume demasiado tiempo. Una mejor aproximación al problema es usar primero las técnicas de
jittering y anti-aliasing. Si esto no funciona, tendrás que incrementar la tasa de muestreo.
La técnica de jittering mueve cada punto una pequeña y aleatoria cantidad sobre la dirección de
muestreo. Esto ayuda a reducir la regularidad resultante del aliasing. Difícilmente habrá algo más
molesto para el ojo humano que los efectos de una baja tasa de muestreo. Es mucho mejor añadir algo
de aleatoriedad a las posiciones de las muestras.
Usa el identificador jitter seguido de la cantidad de jittering que quieres usar. Son recomendables los
valores hasta 0.5.
Deberías tener en cuenta el hecho de que el jittering no puede ocultar totalmente los efectos resultantes
de una tasa de muestreo demasiado baja. En todo caso puede hacerlos menos visibles.
Adicionalmente, un mejor método para reducir los efectos del aliasing es usar el super-muestreo
adaptativo. Este método toma muestras adicionales donde es posible que sean necesarias. Si la
intensidad de dos muestras adyacentes difiere mucho, son tomadas muestras adicionales en un punto
intermedio. Este paso se ejecuta de forma recursiva hasta que es alcanzado un nivel de recursión
específico o la muestra tomada se acerca demasiado a otra adyacente.
aa_threshold especifica la diferencia máxima permitida entre dos muestras antes de que el
super-muestreo tenga lugar.
Después de esta parte teórica volvemos de nuevo a nuestra escena de muestra y añadimos los
identificadores apropiados para usar ambas técnicas, jittering y super-muestreo (ATMOS3.POV).
atmosphere {
type 1
samples 50
distance 40
scattering 0.2
aa_level 4
aa_threshold 0.1
jitter 0.2
}
Se eligió un valor muy bajo para threshold para que se efectúe el super-muestreo incluso entre puntos
adyacentes de intensidad muy similar. El nivel máximo de recursión de 4 resultará en un máximo de 15
super-muestreos.
Si observas los resultados que obtienes después de añadir jittering y super-muestreo seguramente no
estarás satisfecho. La única forma de reducir los defectos todavía visibles es incrementar la tasa de
muestreo eligiendo un número mayor de muestras.
Figura 53: Una alta tasa de muestreo nos lleva a una imagen
satisfactoria
Haciendo esto obtendrás un buen resultado sin (casi) ningún defecto. Por otro lado la cantidad de polvo
flotando en esta habitación puede ser un poco exagerada pero solo es un ejemplo y los ejemplos tienden
a ser exagerados.
Si, por ejemplo, quieres crear una atmósfera rojiza, puedes añadir la siguiente línea a la declaración de
atmósfera usada en el ejemplo anterior.
color rgbf <1, 0, 0, 0.25>
Usando solamente rgb <1,0,0> no funcionaría debido a que el valor de filtro del color sería cero y
no filtraría la luz, es decir, el color de esta no sería multiplicado por los valores de la componente RGB.
El valor de filtro de 0.25 significa que un 25% de la luz que pasa a través de la atmósfera será filtrada
por el color rojo y el 75% restante pasará sin ser filtrada.
El canal de transmitancia del color de la atmósfera se usa para especificar la translucidez mínima. Por
defecto el canal de transmitancia es cero y por lo tanto no existe tal translucidez mínima. Usando un
valor positivo te permite determinar la cantidad de luz que siempre pasará a través de la atmósfera sin
tener en cuenta su grosor determinado por el identificador distance.
Si usas un color rgbt <0,0,0,0.3> con nuestra habitación de ejemplo, puedes hacer que el fondo
azul sea visible. Hasta ahora estaba oculto debido a la atmósfera.
La mejor solución es elegir primero el valor de distance. Este valor determina la visibilidad de los
objetos en la escena sin tener en cuenta la dispersión de la luz. Funciona de igual forma que el valor
distance del efecto niebla (fog).
Ya que la niebla es muy similar a la atmósfera, excepto en lo que se refiere a la iluminación, podemos
usarla en lugar de la atmósfera para elegir un valor para la distancia. Si haces esto con la escena de la
habitación que usamos antes, podrías usar la siguiente declaración de niebla en lugar de la atmósfera
(ATMOS4.POV).
fog {
distance 40
color rgb <0, 0, 0>
}
PERSISTENCE OF VISION RAYTRACER 151
Figura 54: Una niebla de color negro puede ser usada para
obtener un valor de distancia para la atmósfera
Se usa el color negro para simular la atenuación que obtendrías en las partes situadas a la de sombra en
la escena con la atmósfera.
Si quieres usar una atmósfera coloreada tendrás que usar el mismo color para la niebla que el que
quieres usar para la atmósfera, incluyendo los valores del filtro y del canal de transmitancia (ver
"Usando una atmósfera coloreada" y "La Atmósfera" para una explicación del color de la atmósfera).
Si quieres simular la apariencia de esas partes iluminadas por una fuente de luz, puedes usar el color de
la atmósfera en la declaración de la niebla.
Una vez estés satisfecho con el valor de distancia tendrás que elegir una valor de dispersión
(scattering). Este valor te permite adecuar la intensidad de la atmósfera a tus necesidades.
Empezando con un valor de uno deberás aumentarlo si los efectos atmosféricos son difícilmente
visibles. Si no ves nada en las partes iluminadas de la atmósfera, tendrás que decrementar el valor.
Deberías tener en cuenta que quizás tengas que usar valores muy grandes o muy pequeños para obtener
los resultados deseados.
Si quieres añadir una fuente de luz que no interactúe con la atmósfera puedes usar el identificador
atmosphere dentro de la declaración de la fuente de luz (ver "Interacción con la atmósfera").
Simplemente añade atmosphere off.
Por defecto la luz proveniente de cualquier fuente no será disminuida por la atmósfera. De esta manera
los reflejos en tu escena serán normalmente demasiado brillantes. Esto puede ser cambiado con la
declaración
atmospheric_attenuation on.
4. TUTORIAL PARA PRINCIPIANTES 152
La dispersión Rayleigh se usa para partículas pequeñas como polvo o humo, mientras que la dispersión
Mie se usa para la niebla.
Si alguna vez has visto la escena del faro en la película Casper sabrás que efecto tiene el tipo de
dispersión. En esta escena el rayo de luz proveniente del faro se torna visible cuando apunta hacia el
observador y se va desvaneciendo según se aleja. Este comportamiento es típico de las minúsculas gotas
de agua que modela la dispersión Mie.
Esto también se mantiene para los objetos infinitos como quadric, quartic, triangle, polygon, etc. Donde
quiera que uses uno de estos objetos deberías añadir el identificador hollow, siempre que no estés
absolutamente seguro de que no lo necesitas. También debes asegurarte de que todos los objetos dentro
de los cuales se encuentra la cámara son declarados vacíos.
Donde quiera que obtengas resultados inesperados deberías revisar los objetos sólidos y declararlos
como vacíos.