Acerca del Autor: Soy informático de profesión y llevo ya varios años ganándome la vida con esto. Lo que más tiempo llevo manejando es el lenguaje C. Tengo experiencia también como administrador de Unix aunque ahora estoy desarrollando con Visual C++ en WindowsNT (Puaffff lo que hay que hacer para ganarse el pan) Desde que tuve conocimiento de la existencia de Linux y del modelo de organización empleado en su desarrollo me di cuenta que el futuro tenía que ir por aquí. Tengo muchas esperanzas puestas en Linux y no me está defraudando. Justo lo contrario me pasa con Microsoft. Escribe al autorIndex:
|
Diseñando estructuras iterativas en PovrayResumen: En este artículo veremos la forma de usar Povray para el diseño de estructuras iterativas y como pueden lograrse con ellas bellas imagenes.
El arte y la técnica en la infografía.Estos artículos sobre Povray tratan tanto de los aspectos técnicos como de aquellos que no lo son. La técnica ya lo hemos dicho es importante pero también hay que aprender a sacar el máximo provecho de ella. La infografía es tan distinta a otras disciplinas que quizás para algunos sea un medio donde puedan descubrir sus capacidades artísticas. No abandonaremos la técnica porque también es necesaria, pero la técnica es solo un instrumento, para dominar la forma de expresión. Por ello continuaremos mezclando la fría exposición de los conocimientos técnicos con aspectos más creativos.Se trata de dar ideas. Puntos desde los cuales se pueden explorar muchos caminos. Ocurre que muchas veces empiezo a diseñar ejemplos y me divierto tanto que las cosas que quería tratar en ese momento pasan a un segundo plano. Una exposición demasiado sistemática resultaría demasiado aburrida y por ello tampoco resultaría muy didáctica. El manual de Povray sí que está desarrollado siguiendo una secuencia sistemática de los diferentes temas. Como instrumento de consulta está muy bien. Yo lo uso mucho. A diferencia del sistema metódico y secuencial que se utiliza en el manual yo utilizo un método que podría decirse que sigue un recorrido en espiral volviendo a temas tratados para tratarlos con más amplitud.Las escenas que utilizaré como ejemplo para ilustrar algunos aspectos técnicos no serán meros ejercicios técnicos sino que intentaré buscar la belleza estética y un acabado más completo de la escena aunque eso suponga introducir elementos extraños no explicados aun en el ejemplo. Poco a poco se irán revisando todos los conceptos para que lo que no se pudo comprender en una primera lectura se pueda asimilar en futuros artículos. Por otra parte muchos conceptos son tan visuales que apenas necesitan excesiva explicación porque el verlos en un ejemplo resulta suficiente para poder aplicarlo a la perfección. Quizas mejor incluso que si lo leemos en el manual sin una buena imagen como ejemplo. Tampoco hay que olvidar que para los que deseen avanzar más deprisa siempre pueden recurrir a este manual de Povray. Objetos geométricos simplesLa mayoría de estos objetos ya han sido utilizados en algún ejemplo. Los comentamos ahora a modo de repaso.El número de objetos que se pueden diseñar usando estas formas básicas es enorme, y además hay que tener en cuenta que el uso de formas sencillas representa un ahorro considerable en el tiempo de proceso de la escena.
sphere { < x, y, z>, radio ..... } / x, y, z son las coordenadas del centro de la esfera. En el lugar de los puntos suspensivos se pueden añadir sentencias para el escalado, rotación, traslación, pigmentación, textura, etc... Realmente la sintaxis permite definir un tronco de cono. cone { <x1, y1, z1>, rad1 <x2, y2, z2>, rad2 [open] ..... } x1, y1, z1 son las coordenadas del centro en el un extremo del tronco de cono, y rad1 el radio en este extremo. x2, y2, z2 son las coordenadas del centro en el otro extremo del tronco de cono, y rad2 el radio en este extremo. Para que el tronco de cono se convierta en un cono basta con que uno de los radios sea cero. Si deseamos que sea un cono abierto añadiremos la palabra 'open' en caso contrario la omitimos y obtendremos un cono macizo. cylinder { <x1, y1, z1>, <x2, y2, z2>, rad [open] ...... } x1, y1, z1 son las coordenadas del centro en el un extremo del cilindro x2, y2, z2 son las coordenadas del centro en el otro extremo del cilindro como, y rad el radio del cilindro. Para que el cilindro se sea un cilindro abierto añadiremos la palabra 'open' en caso contrario la omitimos y obtendremos un cilindro macizo. Recordemos que en caso de las esferas, conos y cilindros tenemos el recurso de deformar estas figuras usando unos factores de escala adecuados. También puede intentar deformar otros objetos pero en estos casos resulta especialmente interesante porque aparentemente se obtiene una figura distinta. plane { <x, y, z>, dist ..... } En esta ocasión x, y, z no representan una posición sino un vector cuya dirección es perpendicular a la superficie del plano. El valor dist será la distancia al centro de coordenadas. Recordemos que en Povray se puede abreviar la expresión de un vector. x = <0, 1 , 0> -z = <0, 0, -1> Se puede usar en lugar de un plano una esfera de gran tamaño. Esto no causa ningún problema. Nosotros ya lo hemos utilizado alguna vez. box { <x1, y1, z1>, <x2, y2, z2>...... } x1, y1, z1 son las coordenadas de una de las esquinas de la caja x2, y2, z2 son las coordenadas de la esquina opuesta. Objetos geométricos compuestos. (CSG)Las primitivas CSG permiten combinar varias formas simples en una sola más compleja. Después de esto tenemos un objeto que puede ser manejado cómodamente en escalado, translaciones, giros, texturas, etc.. sin necesidad de tener que aplicar estas transformaciones por separado a cada uno de los componentes.Las formas en que se pueden combinar los elementos sencillos entre si son cuatro y existe una quinta complemento que se puede aplicar a un elemento solo.
'union { object {A} object{B} }' Todos sus puntos dentro de A or B 'intersection { object {A} object {B} }' Todos sus puntos dentro de A y B object {A inverse} 'difference { object {A} object {B} }' Todos sus puntos dentro de A que no estén dentro B Equivale a 'union { object {A} object {B inverse }' 'merge { object {A} object {B} }' Como la union pero desaparecen las superficies internas de los componentes A y B. Si los objetos son todos opacos este detalle no ofrece ningún interés. Como sistema para diseñar sin equivocarse se puede utilizar lo siguiente. Junte todas las primitivas que añaden volumen en un único objeto. Luego haga la intersección de este objeto tal cual con el complemento las primitivas que eliminan volumen
Utilización de bucles y condiciones en Povray. Los elementos de una escena se describen generalmente en un orden arbitrario. A pesar de ello hay circunstancias en que puede ser necesario implementar bucles descriptivos para crear estructuras iterativas por ejemplo. En Povray existen varias formas de hacerlo. Una mediante las estructuras de control de flujo que proporciona el propio lenguaje de Povray. En su momento ya mencionamos las directivas de lenguaje #declare e #include y calificamos muchas otras como de menor importancia. Ahora las usaremos pero veremos que tampoco son imprescindibles. En el siguiente ejemplo usamos un programa escrito directamente en lenguaje Povray. Tengo que decir que personalmente es la primera vez que uso esto. El motivo es que no lo consideré muy necesario. Se puede conseguir lo mismo con programación externa que produzca el fuente necesario, y veremos más adelante un ejemplo de esta segunda posibilidad, que yo uso bastante a menudo. Se pueden hacer cosas mixtas también. Veremos que el estilo de programación con Povray no queda tan elegante como con un lenguaje de propósito general. La razón es que Povray se pensó como un lenguaje de descripción de escenas, y estas cosas son añadidos recientes. Vemos que con Povray se pueden programar toda clase de bucles y expresiones matemáticas complejas. En mi opinión está muy bien que Povray incorpore estas cosas pero no son imprescindibles. Todo ello se puede compensar utilizando programación externa, para generar un fuente más o menos complejo o iterativo. Creo que el hacerlo de una manera u otra nada tiene que ver con la parte artística que es la importante, por lo tanto no tiene especial merito hacerlo de una manera u otra. Lo más importante es la imagen final. En menor medida también puede ser importante el esfuerzo de desarrollo y la cantidad de proceso empleado. Si conoce un lenguaje de propósito general con el que se sienta más cómodo utilice a Povray como un paso final. Si quiere implementar algo sencillo puede usar Povray directamente para ello. Veremos ambas formas de hacerlo, pero antes comentaremos un par de cosas más.Prueba y error, frente al cálculo.Tenga en cuenta que muchas de las escenas pueden diseñarse partiendo de una idea. Luego se prueba con valores estimados por aproximación, y por último se va corrigiendo mediante prueba y error hasta obtener el resultado deseado. Para ello ya diseñamos una herramienta que nos permite usar Povray cómodamente (POV). Si piensa que todo puede hacerse con este sistema está equivocado. En ocasiones no queda más remedio que coger el lápiz, el papel y la calculadora. Además los problemas que tenemos que resolver son problemas geométricos en 3D. Es necesario un mínimo de conocimientos de geometría espacial y de trigonometría si quiere conseguir ciertos efectos. Generalmente basta con saber aplicar unas pocas fórmulas. Recordamos aquí unas pocas. sin(a)
= A / C = (Cateto opuesto / Hipotenusa)
Por tanto:
1 Radian = 180 / Pi = 57,29577951308232
Vamos a recordar los rangos de las principales funciones trigonométricas, en función del cuadrante:
a = atan(A/B) Esta última función es un poco ambigua. Realmente no podemos
conocer el valor de Alfa si no conocemos el cuadrante, por ello es preferible
usar:
Distancia entre P1(x1,y1,z1) y P2(x2,y2,z2) es D = sqrt( (x2-x1)^2 + (y2-y1)^2 + (z2-z1)^2 ) Hay muchas fórmulas útiles en trigonometría pero
creo que con estas es suficiente para la mayoría de los casos. En
Povray se asume que para las funciones trigonométricas trabajamos
con radianes por lo que usaremos la función de conversión
radians(). radians(Alfa) Por el contrario para los giros se asume que trabajamos
con grados. :-(
Erizos marinosEl ejemplo siguiente es un buen ejercicio para repasar la trigonometría básica. Se puede apreciar que en el erizo las púas tienen una colocación bastante buena. Esto no se puede improvisar, hay que analizarlo, elegir un algoritmo e implementarlo con la idea clara de lo que se quiere obtener. El fuente está ampliamente comentado para resultar lo más claro posible. Es un caso claro en el que se especifica una estructura altamente iterativa. En este caso elegimos Povray como lenguaje para implementar esta estructura iterativa pero no existe ninguna razón para no hacerlo en la otra forma que veremos más tarde mediante un programa externo.Empezmos mostrando el fuente de los peces. Se trata de una figura compuesta
en la que usamos las primitivas CGS que ya hemos comentado.
// (Copyright) (No modificar estas 11 primeras Lineas) // Autor: Antonio Castro Snurmacher // (E-mail acastro@ctv.es ) // // Este fuente puede ser utilizado, distribuido, y modificado // libremente pero siempre se deberá respetar la propiedad // intelectual de su autor. El autor renuncia a todo tipo de // beneficio económico y no se hace responsable de los // posibles perjuicios derivados del uso del mismo. Toda // modificación queda sujeta a las mismas condiciones de uso // que el original. En caso de traducción deberá conservarse // el texto original de esta cabecera y añadirse la traducción // a continuación de ella. ///////////////////////////////////////////////////// //------------------------------------------------------------ // balistap.inc (1-Mayo-1998) //------------------------------------------------------------ // Esta versión está dedicada a su inclusión en la revista // LinuxFocus //------------------------------------------------------------ #declare Color1 = color red 0.5 green 0.2 blue 0.4 #declare ColorEye = color red 0.5 green 0.5 blue 0.5 // Aleta inferior #declare AletDown = intersection { sphere { <-10,-7,0> 10 scale <2, 1, 0.1> } sphere { <-15,-17,0> 10 scale <2, 1, 1> inverse< } cone { <-10, 0, 0>, 0 <-45, 0, 0>, 20 inverse } pigment { color Color1 } } // Aleta superior #declare AletUp = intersection { sphere { <-10,7,0>, 10 scale <2, 1, 0.1> } sphere { <-15, 17,0>, 10 scale <2, 1, 1> inverse } cone { <-10, 0, 0>, 0 <-45, 0, 0>, 20 inverse } pigment { color Color1 } } // Aleta caudal (cola) #declare Tail = intersection { sphere { <-19,0,0>, 10 scale <2, 1, 0.1> } sphere { <-25,0,0>, 10 scale <2, 1.3, 1> inverse } pigment { color Color1 } } // Pez completo #declare Balistap = union{ sphere { <10, 4,0>,4 pigment { color ColorEye } scale <1,1, 0.6> } sphere { <10.2, 4.35,0>,3.43 pigment { color Gray20 } scale <1,1, 0.7> } sphere { <0,0,0> 10 scale <2, 1, 0.3> pigment { gradient y colour_map { [0.0 colour White] [0.1 colour Grey] [0.99 colour Black] } scale <1, 17, 1> translate <0, -7, 0> } } cone {<19, 0, 0>, 1.5 <-2, 0, 0> 8 scale <1,1, 0.5> pigment { color Color1 } } cone {<21, 0, 0>, 1 <0, 0, 0> 13 scale <1,1, 0.1> pigment { color Color1 } } object {AletUp} object {AletDown} object {Tail} } /////////(Copyright) (No modificar estas 11 primeras Lineas) // Autor: Antonio Castro Snurmacher (E-mail acastro@ctv.es ) // // Este fuente puede ser utilizado, distribuido, y modificado // libremente pero siempre se deberá respetar la propiedad // intelectual de su autor. El autor renuncia a todo tipo de // beneficio económico y no se hace responsable de los // posibles perjuicios derivados del uso del mismo. Toda // modificación queda sujeta a las mismas condiciones de uso // que el original. En caso de traducción deberá conservarse // el texto original de esta cabecera y añadirse la traducción // a continuación de ella. /////////////////////////////////////////////////// //----------------------------------------------------------- //erizo.pov (1-Mayo-1998) //----------------------------------------------------------- //Esta versión esta dedicada a su inclusión en la revista // //LinuxFocus //----------------------------------------------------------- #include "colors.inc" #include "textures.inc" #include "balistap.inc" #declare RadioCuerpo = 5 #declare NumEspinasMeridiano = 40 // Definimos el tamaño de las puas en función del tamaño del // cuerpo Los erizos de mar en la naturaleza presentan puas // largas en la parte superior y cortas en la parte inferior. #declare LongitudMaximaPua = RadioCuerpo * 2 #declare LongitudMinimaPua = RadioCuerpo / 4 // Color del erizo #declare TexturePua = texture { pigment {VeryDarkBrown} } #declare TextureCuerpo = texture { pigment {DarkBrown} } // Todas las definiciones que siguen a continuación están // calculadas a partir de las anteriores. Suponemos // inicialmente un erizo con cuerpo esférico. pi está // predefinido como #declare pi = 3.1415926535897932384626 #declare LongitudMeridiano = 2 * pi * RadioCuerpo // Suponemos que está totalmente recubierto de púas cónicas. // El radio de una púa en su base será 'RadioPua' #declare MeridianoPua = LongitudMeridiano / NumEspinasMeridiano #declare RadioPua = MeridianoPua / 2 // Usaremos la notación de eje, meridiano, y paralelo en el // erizo tal como lo haríamos con el eje, los meridianos, y // paralelos terrestres. Para recubrir el erizo totalmente de // púas trazaremos varios circulos 'paralelos del erizo', y // para ello tomaremos un 'meridiano del erizo' como punto de // partida de todos ellos. Llamaremos angulo vertical al // angulo formado con el 'eje del erizo' y el punto de // comienzo de un paralelo. En los polos este angulo vertical // valdrá 0 y 180, y en el ecuador valdrá 90. Necesitamos ir // incrementado este angulo para procesar en cada uno de ellos // las puas de un paralelo. Para calcular el incremento del // angulo vertical hacemos una regla de tres LongitudMeridiano // ---> 360 MeridianoPua ---> IncAngVert #declare IncAngVert = 360 * MeridianoPua / LongitudMeridiano // Para que el erizo no sen unda en la arena ni flote en el // agua calculamos la distancia del centro al extremo de las // puas pequeñas situadas en la parte inferior del erizo. #declare CorreccionY = RadioCuerpo + LongitudMinimaPua camera { location < -40, 40, -40> look_at < 25, CorreccionY , 25> } // En el fondo del mar la luz llega de varios puntos debido al // oleaje en la superficie. Para simular esto usaremos varias // fuentes de luz. light_source { <-200, 300, -200> color White} light_source { <-300, 300, -100> color White} light_source { <-100, 300, -300> color White} light_source { <0, 1200, 0> color White} // Para conseguir la coloracion del agua utilizamos un efecto // atmosférico. fog { distance 250 color SeaGreen } // La arena la definimos con un color Sienna, y con profundas // ondulaciones de gran tamaño. plane { y, 0 pigment { Sienna } normal { ripples 1.0 frequency 300.0 } finish { ambient 0.1 diffuse 0.9 } scale <3000, 3000, 3000> } // ******************* Declaracion del erizo **************** #declare erizo = object { union { // Calcularemos un paralelo de puas para cada valor de AngVert // El primer valor será 0. (0 puas en la misma dirección del // eje vertical. El segundo valor serán una pocas puas // situadas en el primero paralelo El máximo valor se // conseguirá para AngVert == a 90 porque es la zona del // ecuador donde cabe el máximo de puas. Las puas en un mismo // meridiano se calculan variando el ángulo horizontal // 'AngHoriz' #declare AngVert=0 #while (AngVert < 180 ) #declare RadParalelo = abs ( RadioCuerpo * sin(radians(AngVert))) #declare LongitudParalelo = 2 * pi * RadParalelo #declare NumEspinasParalelo = LongitudParalelo / MeridianoPua #declare LongitudPua = LongitudMinimaPua + ( \ (LongitudMaximaPua-LongitudMinimaPua) * ((180-AngVert)/180) ) // #declare LongitudPua = LongitudMaximaPua #declare IncAngHoriz = 360 / NumEspinasParalelo #declare Ybase = RadioCuerpo * cos (radians(AngVert)) #debug concat("\nAngVert=", str(AngVert,5,0), \ " LongitudPua=", str(LongitudPua,5,0), \ "Ybase=", str(Ybase,5,0), " "); #declare Ypunta = (RadioCuerpo + LongitudPua)* \ cos (radians(AngVert)) #declare AngHoriz=0 #while (AngHoriz < 360) #declare Xbase = RadParalelo * cos (radians(AngHoriz)) #declare Xpunta = (RadParalelo + LongitudPua) * \ cos (radians(AngHoriz)) #declare Zbase = RadParalelo * sin (radians(AngHoriz)) #declare Zpunta = (RadParalelo + LongitudPua) * \ sin (radians(AngHoriz)) //#debug concat( "Vert=", str(AngVert,5,0), \ // " Horiz=", str(AngHoriz,5,0), \ // "\n") cone { La luz de esta escena se consigue usando muchos puntos de luz para simular la iluminación subacuática caracterizada por el desorden introducido por el oleaje en superficie. Un solo foco de luz nos delataría en seguida porque la sombra del erizo en el fondo sería demasiado nítida. Generación mediante programas externos.Un trazador de rayos es solo la herramienta para generar toda una escena que ha sido especificada con ayuda de un lenguaje formal que es el trazador de rayos. Éste es capaz de entender las especificaciones de formas colores, luces , etc... pero muchas veces existe un trabajo previo para obtener lo que deseamos. Escaneres tridimensionales, programas de modelado, traductores de formatos, programación. etc... En este sentido un trazador de rayos puede utilizarse como un eslabón más en la cadena de herramientas, de todo tipo que nos permiten obtener un resultado final. En otras palabras no sólo es posible diseñar tecleando directamente el código fuente en el lenguaje del trazador de rayos para plasmar nuestra idea. Podemos ayudarnos de herramientas y también de la programación para generar toda clase de figuras complejas altamente repetitivas o recursivas.Vamos a poner un ejemplo de lo estamos diciendo. Este programa está escrito en C y trata de lo siguiente. Define un espacio con las proporciones de la resolución empleada (1000*750). Una vez definida esta área, el programa trata de situar esferas en dicha área de forma aleatoria. Habrá que detectar que la posición generada no tiene cerca ninguna otra de las esferas ya generadas para evitar que se ínter-penetren. Para controlar esto vamos guardando la posición de cada esfera y su tamaño. Si la posición obtenida cae encima de una esfera ya existente probaremos en otro lugar. En caso contrario comprobamos cual es la distancia mínima al borde más cercano del resto de las esferas. Si es necesario reducimos el tamaño de la esfera para que pueda entrar. En esta ocasión la nueva esfera será menor que el tamaño inicial establecido y quedará en contacto con otra. Después de un elevado número de iteraciones obtendremos una superficie llena de esferas de distintos tamaños sin apenas espacios libres entre ellas. Estamos usando mucha fuerza bruta de cálculo porque cada vez el programa necesita más intentos para colocar una nueva esfera. /////////(Copyright) (No modificar estas 11 primeras Lineas) // Autor: Antonio Castro Snurmacher (E-mail acastro@ctv.es ) // // Este fuente puede ser utilizado, distribuido, y modificado // libremente pero siempre se deberá respetar la propiedad // intelectual de su autor. El autor renuncia a todo tipo de // beneficio económico y no se hace responsable de los // posibles perjuicios derivados del uso del mismo. Toda // modificación queda sujeta a las mismas condiciones de uso // que el original. En caso de traducción deberá conservarse // el texto original de esta cabecera y añadirse la traducción // a continuación de ella. ///////////////////////////////////////////////////////////// //----------------------------------------------------------- //burbujas.c (1-Mayo-1998) */ //----------------------------------------------------------- //Esta versión esta dedicada a su inclusión en la revista //LinuxFocus //----------------------------------------------------------- /*************************************************************/ /** Compilar mediante cc balls.c -lm -o balls **/ /*************************************************************/ #include sphere{<-375, 0, 33> 55.0000000 texture{Gold_Metal}} //(0/1) sphere{< -86, 0, 62> 55.0000000 texture{Gold_Metal}} //(1/2) sphere{<-326, 0, 346> 55.0000000 texture{Gold_Metal}} //(2/3) sphere{< 190, 0, -156> 55.0000000 texture{Gold_Metal}} //(3/4) sphere{< 62, 0, -293> 55.0000000 texture{Gold_Metal}} //(4/5) sphere{< 323, 0, 161> 55.0000000 texture{Gold_Metal}} //(5/6) sphere{< 341, 0, -15> 55.0000000 texture{Gold_Metal}} //(6/7) ................... Tenemos que tener paciencia, pero si vemos que pasa el tiempo y no hay avances podemos interrumpir el proceso. Bastará editar el fichero y comprobar que la última linea está entera y sino quitarla. El fuente pov será el siguiente: /////////(Copyright) (No modificar estas 11 primeras Lineas) //Autor: Antonio Castro Snurmacher (E-mail acastro@ctv.es ) // // Este fuente puede ser utilizado, distribuido, y modificado // libremente pero siempre se deberá respetar la propiedad // intelectual de su autor. El autor renuncia a todo tipo de // beneficio económico y no se hace responsable de los // posibles perjuicios derivados del uso del mismo. Toda // modificación queda sujeta a las mismas condiciones de uso // que el original. En caso de traducción deberá conservarse // el texto original de esta cabecera y añadirse la traducción // a continuación de ella. ////////////////////////////////////////////////////////////// //------------------------------------------------------------ // burbujas.pov (1-Mayo-1998) //------------------------------------------------------------ // Esta versión esta dedicada a su inclusión en la revista Lin // uxFocus //------------------------------------------------------------ // Se recomienda usar el siguiente comando para la utilidad 'pov' // pov burbujas 6 9 1 4 // ^ ^ ^ ^ // | | | | // Resolucion __/ | | | // Calidad ____/ | | | // Desde Clock = 1 _/ | // Hasta Clock = 4 ___/ #include "colors.inc" #include "textures.inc" // Por defecto max_trace_level vale 5 . Aumentado a 15 // conseguimos mayor nivel detalle en las imágenes recursivas // generadas por reflejos global_settings { #max_trace_level 15 } // Declaramos distintos puntos de vista y solo elegiremos // finalmente una en función del valor de Clock #declare img1 = camera { location <0, 10000 ,0 > look_at <0, 0, 0> angle 7 } #declare img2 = camera { location <0, 250 ,0 > look_at <0, 0, 0> angle 130 } #declare img3 = camera { location <12, 3 ,12 > look_at <200, 3, 50> angle 30 } #declare img4 = camera { location <12, 3 ,12 > look_at <200, 3, 50> angle 120 } #switch (clock) #case (1) // This section is parsed if clock=1 camera {img1} #break #case (2) // This section is parsed if clock=2 camera {img2} #break #case (3) // This section is parsed if clock=4 camera {img3} #break #case (4) // This section is parsed if clock=5 camera {img4} #break #else #warning "Clock outside expected range\n" #end // End of conditional part // Fuente de luz blanca object { light_source { <100, 1000, 100> color White } } #declare textureBall = texture { Gold_Metal } // El fichero include 'burbujas.inc' es un fichero obtenido // mediante la salida de un programa escrito en lenguaje C. #include "burbujas.inc" Ya mencionamos en el artículo anterior que veríamos algunos ejemplos para comprobar las posibilidades de la cámara. Pues bien nos referíamos a este ejemplo. Podemos ver los distintos efectos de perspectiva conseguidos dependiendo de usar un ángulo muy pequeño desde muy lejos, o usar un ángulo muy abierto desde muy cerca. El máximo ángulo posible para la apertura del objetivo es 180. Es un caso extremo en el que no se distinguen las formas. Como puede verse un simple juego con la cámara puede producir efectos interesantes. Los renders se han realizado en un Pentium 200 MMX 48 MB Ram (398 bogomips). Lo ejecutamos según se sugiere usando nuestra herramienta 'pov' con el comando siguiente: pov burbujas 6 9 1 5 1 5 Tiempo total = Los parametros y sus significados son:
pov burbujas 9 9 1 5 1 5 Tiempo total = 4 horas y media.
Veamos ahora los resultados. En primer lugar en los cuatro primeros fotogramas solo varia la cámara. (posición, angulo, dirrección, etc) Falta un fotograma que lo mostraremos seguidamente pero antes vamos
a tratar algunos temas en relación con este último fotograma.
Optimización del uso de la CPUComo vemos, el último fotograma es el más complejo, y Povray no ha sabido optimizarlo. Cuando tenemos una figura compuesta, el trazador intenta determinar una figura más simple que lo envuelva. Esto en versiones anteriores de Povray había que hacerlo siempre a mano. Se especificaba con la primitiva 'bounded_by' una forma que envolviera a uno o más objetos y de esta forma el trazador asumía que los rayos que no incidían en este en voltorio tampoco incidían en los objetos internos ahorrandose esa comprobación. Actualmente son poco frecuentes los casos donde una optimización manual resulte util, pero estamos precisamente ante uno de esos casos. El último fotograma se corresponde con una figura compuesta excesivamente compleja. Por ello habría sido mejor o bien agrupar las burbujas por zonas bien delimitadas y combinarlas previamente en varias figuras compuestas para guiar así al optimizador o bien de combinarlas todas juntas en una como se hace en el ejemplo pero envolviendo grupos de esferas que esten en una zona bien delimitada usando 'bounded_by'. La sintaxisis sería: union { sphere { <x1, y1, z1>, r1 } sphere { <x2, y2, z2>, r1 } sphere { <x3, y3, z3>, r1 } .......................... bounded_by { sphere { <xb, yb, zb>, rb } } } Se puede aplicar no solo a uniones o intersecciones etc. sino a cualquier objeto, y se puede usar en 'bounded_by' una forma distinta para envolver aunque los mejores resultados los dan las esferas y las cajas. Si la forma elegida deja fuera una parte del objeto el resultado puede ser defectuoso. Repito que la necesidad de hacer esto es muy rara. Este último ejemplo tenía muy mala idea y el optimizador de Povray no pudo hacer más. Se trata de un objeto compuesto con 2154 esferas. Puede contarlas en la imagen si no me cree. :-) La última imagen es el resultado de seguir jugando con las posibilidades del trazador de rayos. Muchas veces a una misma idea se le pueden sacar muchas posibilidades y es aquí donde entra nuestra creatividad y nuestra imaginación. Es decir, que muchas veces no basta con partir de una buena idea sino que hay que seguir imaginando y jugando con distintas posibilidades hasta encontrar algo que nos guste. Se pueden imaginar cantidad de escenarios en los que la
programación puede servir de apoyo a la generación de imagenes
sintéticas, estáticas o en movimiento.
Lo que se hecha de menos.Povray proporciona muchas funciones matemáticas más o menos interesantes, pero hay una interesantísima que falta. Se trata de la una función spline. Nada hay más cómodo que trazar con lápiz y papel una serie de puntos y luego aplicar una función y obtener una curva que pase por esos puntos. La primitiva spline de Povray no puede usarse como función sino que genera una línea como base para construir formas, pero sería mucho mejor poder aplicar esa función a las variables que nosotros quisiéramos. De esta forma podríamos mover por ejemplo tanto objetos como la cámara siguiendo una trayectoria cualquiera. También sería bueno poder implementar funciones externamente. Bueno de alguna manera todo eso se puede compensar usando includes
y programación externa. Tenemos en Linux una utilidad llamada
'spline'. Se utiliza como un comando y genera la salida
correspondiente a la curva deseada, a partir de una entrada que pueden
ser parejas de puntos. Puede ser muy útil combinar este comando con el
uso de la programación externa. Por ejemplo para obtener animaciones,
o movimientos de cámara.
Ejercicios
Aportación de los lectores.Si algún lector implementa algún otro algoritmo para construcción de formas recursivas o iterativas. Puede enviarme sus experimentos, en forma de fuentes comprimidas con gzip. Las imágenes siempre comprimidas de alguna forma. Si hay material suficiente para ello se podría incluir en algún artículo. dedicado a Povray con una selección de las imágenes más curiosas, acompañadas de sus fuentes. Abstenerse de mandar nada que implique licencia de uso mediante pago en cualquiera de sus modalidades. Interesa sobre todo las fuentes.pov3.tar.gz, Fuentes de los programas de este artículo (42652 bytes) Texto original en Castellano |
Páginas web mantenidas por Miguel Ángel Sepúlveda © Antonio Castro 1998 LinuxFocus 1998 |