From BlenderWiki

Jump to: navigation, search

[edit] Un ejemplo funcional de Python

Ahora que ha visto que Blender es extendible mediante scripts Python y que conoce los fundamentos de como manipular y ejecutar un script, antes de romperse el cerebro con la referencia completa al API de Python, daremos un vistazo a un rápido ejemplo funcional.

Presentaremos un pequeño script para producir polígonos, éste de hecho duplica algo que la opción de la caja de herramientas Space → Add → Mesh → Circle ya hace, pero creará polígonos "rellenados", no sólo el borde externo.

Para hacer este simple script aún más completo mostraremos un interfaz gráfico de usuario (GUI), escrito enteramente con el API de Blender.

[edit] Cabeceras, importando módulos y variable globales

Las primeras 32 líneas de código se listan abajo: cabecera del script

001 002 003 004 005 006 007 008 009 010 011 012 013 014 015 016 017 018 019 020 021 022 023 024 025 026 027 028 029 030 031 032

######################################################
#
# Demo Script for Blender 2.3 Guide
#
######################################################
# Este script genera polígonos. Es bastante inútil desde
# que ud. puede hacer polígonos con ADD->Mesh->Circle
# pero es un buen ejemplo de un script completo, y los
# polígonos están "rellenos"
######################################################

######################################################
# Importando módulos
######################################################

import Blender
from Blender import NMesh
from Blender.BGL import *
from Blender.Draw import *

import math
from math import *

# Los parámetros del polígono
T_NumberOfSides = Create(3)
T_Radius = Create(1.0)

# Eventos
EVENT_NOEVENT = 1
EVENT_DRAW = 2
EVENT_EXIT = 3

Después de los necesarios comentarios acerca de lo que hace el script viene (líneas [016-022]) la importación de los módulos de Python. Blender es el módulo principal del API Python de Blender. NMesh es el módulo que provee acceso a las mallas (meshes) de Blender, mientras que BGL y Draw dan acceso respectivamente a las constantes y funciones OpenGL y al interfaz de ventanas de Blender.

El módulo math es el módulo matemático de Python, pero desde que tanto math como os son módulos preconstruídos en Blender no es necesaria una instalación completa de Python para esto.

Los polígonos están definidos por el número de lados que tienen y por sus radios. Estos parámetros deben ser definidos por el usuario mediante la GUI, para ello las líneas [025-026] crean dos objetos "generic button" con sus valores iniciales por defecto.

Por último, los objetos GUI funcionan con, y generan, eventos. Los identificadores de eventos (o ID de eventos, de manera abreviada) son enteros que definen los codificadores a su izquierda (deben ser únicos, a menos que existan necesidades especiales). Es considerado una buena práctica elegir nombres mnemónicos para los eventos, esto se haces aquí en las líneas [029-031].

[edit] Dibujando la GUI

El código responsable de dibujar la GUI debe residir en una función draw (Dibujando la GUI).

Dibujando la GUI

033 034 035 036 037 038 039 040 041 042 043 044 045 046 047 048 049 050 051 052 053 054 055 056 057

######################################################
# Dibujando la GUI
######################################################
def draw():
        global T_NumberOfSides
        global T_Radius
        global EVENT_NOEVENT,EVENT_DRAW,EVENT_EXIT

        ########## Títulos
        glClear(GL_COLOR_BUFFER_BIT)
        glRasterPos2d(8, 103)
        Text("Demo Polygon Script")

        ######### Botones de la GUI para los parámetros
        glRasterPos2d(8, 83)
        Text("Parameters:")
        T_NumberOfSides = Number("No. of sides: ", EVENT_NOEVENT, 10, 55, 210, 18,
                T_NumberOfSides.val, 3, 20, "Number of sides of out polygon");
        T_Radius = Slider("Radius: ", EVENT_NOEVENT, 10, 35, 210, 18,
                T_Radius.val, 0.001, 20.0, 1, "Radius of the polygon");

        ######### Botones Draw y Exit
        Button("Draw",EVENT_DRAW , 10, 10, 80, 18)
        Button("Exit",EVENT_EXIT , 140, 10, 80, 18)

Las líneas [037-039] simplemente garantizan el acceso a los datos globales. Lo realmente interesante empieza en las líneas [042-044]. Se inicializa la ventana OpenGL, y se establece su posición (x=8, y=103). El origen de esta referencia el la esquina inferior izquierda de la ventana del script. Luego se imprime el título “Demo Polygon Script”. Se escribe una cadena más (lines [047-048]).

Luego son creados los botones de ingreso de parámetros. El primero (líneas [049-050]) es un Num Button, exactamente como aquellos que hay en las diferentes ventanas de botones de Blender. Para el significado de todos los parámetros, por favor consulte la referencia del API. Hay, básicamente, la etiqueta del botón, el evento generado por el botón, su localización (x,y) y sus dimensiones (ancho, altura), su valor,el cual es un dato perteneciente al objeto Button en sí mismo, los valores mínimo y máximo permitidos y una cadena de texto que aparecerá como ayuda mientras el puntero del ratón se encuentre sobre el botón, a modo de tooltip. Las líneas [051-052] definen un Num Button con un dial, con una sintaxis muy similar. Finalmente, las líneas [055-056] crean un botón Draw que creará el polígono y un botón Exit.

[edit] Administrando Eventos.

La GUI no se ha dibujado, y no funcionará, hasta que haya sido escrito y registrado un adecuado manipulador de eventos(Manipulador de eventos).

Manipulador de eventos

058 059 060 061 062 063 064 065 066 067 068 069 070 071 072 073 074 075

def event(evt, val):
        if (evt == QKEY and not val):
                Exit()

def bevent(evt):
        global T_NumberOfSides
        global T_Radius
        global EVENT_NOEVENT,EVENT_DRAW,EVENT_EXIT

        ######### Administra los eventos de la GUI
        if (evt == EVENT_EXIT):
                Exit()
        elif (evt== EVENT_DRAW):
                Polygon(T_NumberOfSides.val, T_Radius.val)
                Blender.Redraw()

Register(draw, event, bevent)

Las líneas [058-060] definen el manipulador de eventos de teclado, aquí respondiendo a Q con una sencilla llamada Exit().

Más interesantes son las líneas [062-072], encargadas de administrar los eventos de la GUI. Esta función es llamada cada vez que se usa un botón de la GUI, con el número de evento definido dentro del botón como un parámetro. El corazón de esta función es, por lo tanto, la estructura 'select' (if/elif) que ejecuta códigos distintos de acuerdo al número de evento.

Como última llamada, es invocada la función Register(). Ésta dibuja efectivamente la GUI e inicia el ciclo de captura de eventos(“event loop”).

[edit] Manipulando la malla

Por último, Función Principal muestra la función principal, la que crea el polígono. Es, mas bien, una simple edición de la malla, pero muestras muchos puntos importantes de la estructura de datos interna de Blender.

Función principal

076 077 078 079 080 081 082 083 084 085 086 087 088 089 090 091 092 093 094 095 096 097 098 099 100 101 102 103 104 105 106 107 108 109

######################################################
# Cuerpo principal
######################################################
def Polygon(NumberOfSides,Radius):

        ######### Crea una malla nueva
        poly = NMesh.GetRaw()

        ######### Ubica los vértices
        for i in range(0,NumberOfSides):
                phi = 3.141592653589 * 2 * i / NumberOfSides
                x = Radius * cos(phi)
                y = Radius * sin(phi)
                z = 0

                v = NMesh.Vert(x,y,z)
                poly.verts.append(v)

        ######### Agrega un nuevo vértice al centro
        v = NMesh.Vert(0.,0.,0.)
        poly.verts.append(v)

        ######### Conecta los vértices para formar caras
        for i in range(0,NumberOfSides):
                f = NMesh.Face()
                f.v.append(poly.verts[i])
                f.v.append(poly.verts[(i+1)%NumberOfSides])
                f.v.append(poly.verts[NumberOfSides])
                poly.faces.append(f)

        ######### Crea un nuevo Objeto con la Malla nueva
        polyObj = NMesh.PutRaw(poly)

        Blender.Redraw()

La primera línea importante aquí es la número [082]. Aquí se crea un nuevo objeto malla, poly. El objeto malla está constituído por una lista de vértices y una lista de caras, además de alguna otra cosa interesante. Para nuestros propósitos las listas de vértices y caras son lo que necesitamos.

Por supuesto la malla recién creada está vacía. El primer ciclo (líneas [085-092]) calcula la localización x,y,z de los vértices necesarios para definir el polígono en base a NumberOfSides. Siendo el polígono una figura plana z=0 para todos sus vértices. La línea [091] llama al método Vert() de NMesh para crear un nuevo objeto vértice con las coordenadas (x,y,z). Tal objeto es agregado (line [092]) a la lista de vértices verts de la malla poly.

Finalmente (líneas [095-096]) se añade un último vértice al centro.

Las líneas [099-104] conectan estos vértices para formar caras. No es necesario crear todos los vértices y luego las caras. Puede crear de manera segura una nueva cara tan pronto existan los vértices que la conforman.

La línea [100] crea un nuevo objeto cara. Un objeto cara tiene su propia lista de vértices v (hasta 4) que lo definen.

Las líneas [101-103] agregan tres vértices a la lista f.v originalmente vacía. Los vértices son dos vétices adyacentes del polígono más el vértice central. Estos vértices deben ser tomados de la lista verts de la Malla.

Por último la línea [104] agrega la cara recién creada a la lista faces de nuestra malla poly.

[edit] Conclusiones

La GUI de nuestro ejemplo.
El resultado de nuestro script de ejemplo.

Si crea un archivo polygon.py con el código descrito arriba y lo carga en la ventana de texto de Blender, como aprendió en la página anterior, y presiona Alt P en dicha ventana para ejecutarlo, verá que el script desaparece y la ventana se vuelve gris. En la esquina inferior izquierda se dibujará la GUI (La GUI de nuestro ejemplo).

Seleccionando, por ejemplo, 5 vértices y un radio de 0.5, y presionando el botón Draw aparecerá un pentágono en el plano x, y de la ventana 3D (El resultado de nuestro script de ejemplo).