|
Pythonlópes - El Python que yo sé Parte III: Toqueteando un poco para hacernos los amos del corral
El alcohol disminuye el campo visual.
|
|
Escribo estas líneas recién salida la versión 2.30 de Blender, con el nuevo API de Python ya muy depurado, funcional y documentado, y bastantes novedades implementadas. En este capítulo veremos cómo podemos tontear con el interface de usuario (GUI) de Blender y creernos que somos Blender en persona.
Para ello echamos un vistazo a lo que nos ofrece el módulo llamado Window:
Esto es, cositas que tienen relación con el GUI y que forman un cajoncito de sestrecito muy mono. Estas funciones se dividen en 3 grupos: *Acceso a ficheros *Barra de progreso *Orientación de la vista 3D y Cursor3D ¡Veámoslos! ¡YAA! |
Como en cualquier lenguaje con acceso a rutinas gráficas, el API de Python dispone de órdenes ('FileSelector' e 'ImageSelector') que nos abren una ventana estándar que permite al usuario navegar por los directorios y buscar archivos. Sin embargo, este acceso no se hace de la forma habitual: estas órdenes no devuelven una 'trayectoria a fichero' como cadena, ni tan siquiera como objeto. Lo que hacen es llamar a otra función donde se deberían realizar las operaciones deseadas sobre este fichero. Así, los formatos respectivos son:
Blender.Window.FileSelector (func , titulo) Blender.Window.ImageSelector (func , titulo)Donde titulo es una cadena que aparecerá en la ventana de selección de archivos, como "Elige fichero", "LOAD FILE" y esas cosas; y func es el nombre de una función de un parámetro a la que se llama, que debe ser de esta guisa: def func(nombre_archivo): print "El archivo se llama" , nombre_archivo f=open(nombre_archivo) ...Es decir, FileSelector ejecuta la función func y le pasa directamente la ruta al archivo como parámetro. Se ve enseguida que esto es muy incómodo y dificulta el hilo "lineal" del pensamiento del programador, pues aunque nos ahorra trabajo en ciertas situaciones, no siempre es deseable esta estructura para acceder a un fichero. Tampoco podemos hacer que esta func nos devuelva el nombre con un return ya que no la llamamos nosotros, sino FileSelector. ¿Qué devuelven pues estas funciones? Fácil: devuelven 'None'. Lo ideal, digamos, sería disponer de una orden directa: nombre_archivo=FileSelector("Busca Archivo"). Así que, a poco que nos estrujemos el celebro, encontramos la solución a través de una variable global: global nom_arch def func(ARCH): nom_arch=ARCHY nada más. Ya está. |
Esto sí que es sencillo, tan fácil como introducir un número entre 0 y 1 como primer parámetro de la función DrawProgressBar, y se dibuja una barrita de color en la ventana de información, sobre el logo de Blender. Así, en un bucle de 100 pasos:
|
|
Cuando creamos un objeto nuevo, este aparece en el lugar donde está el "Cursor3D" (el punto de mira) y orientado de tal manera que sus ejes XY son paralelos a los lados de la ventana, y el Z "sale para afuera" de la pantalla.
Podemos darnos cuenta, pues, de que el punto de vista de cada ventana3D, funciona en ese sentido como un objeto: tiene su posición (el Cursor3D) y su orientación (la que tendría el objeto que creamos sobre ella). También podemos decir que tiene asociado un vector escala que está dado por la longitud focal (Parámetro Lens, tanto en las Viewport Properties, como si es una cámara). Recordamos ahora que, cada vez que creamos un objeto desde Python, por ejemplo con NMesh.PutRaw('mesh'), aparecía en el origen y orientado sobre los ejes globales, o sea, su matriz de transformación era la identidad. Vamos a ver cómo simular exactamente el comportamiento del menú "Add" de Blender, con un script en Python. Así conseguiremos que, al crear un Objeto3D, nos aparezca según la vista de la ventana y centrado en el cursor.
Vale, pero ¿qué son esas líneas comentadas en (1)? Resulta que, aunque sabemos que un objeto3D está dado por: (a) un vector posición (x,y,z), (b) una orientación (los 3 ángulos de Euler, [A,B,C]) y (c) un vector escala (X,Y,Z), resulta que todo ello se almacena internamente en la matriz de transformación, de dimensiones 4x4, y legible con el método 'objeto.getMatrix()'. Sin embargo, de momento no hay método 'objeto.setMatrix()' para aplicar una transformación alobjeto, sino que hay que hacerlo según los pasos (a), (b), (c) de arriba. Aplicar la posición y la escala no es problema con 'o.setLocation', o escribiendo directamente en 'o.loc' y 'o.size', pero en cuanto a su orientación, sólo podemos asignar los ángulos de rotación, y en este ejemplo sólo disponemos de la matriz. ¿Hay alguna forma entonces de extraer estos ángulos de Euler de tal matriz? Sí, pero no es obvio. Así que mientras no hay una solución mejor, os remitimos al archivo funciones.py, donde se encuentra la función de Alfredo de Greef, mcc eeshlo, quien después de muchas aventuras matemáticas hizo las funciones mat2euler y euler2mat. |
|
V.18,11,3 - © 2003 Carlos López Escríbeme y dime algo... ¡tú puedes hacerlo! Gracias a todos los reporteros de fallos que hacen que esto se vaya corrigiendo ;-) |