ANI Python y Blender
ANI Python y Blender
Primeros pasos 1
Variables y operaciones básicas 3
Listas, bucles y sentencias condicionales 3
Funciones 6
Módulos 7
Operaciones básicas con Blender 7
Modificación de las propiedades de un objeto 8
Inserción de fotogramas clave 9
Un poco de limpieza 9
Manipulación de una malla 10
Creación de una pequeña ciudad 11
Control de la densidad de edificios 13
Automatización completa del proceso 15
Creación de una interfaz de usuario 16
Especificación de requisitos de la interfaz 16
Programación de interfaces en Blender 17
Declaración de propiedades 18
Creación de un panel 19
Creación de un operador 21
Creación de un complemento instalable 24
Paquetes Python 25
Creación de un add-on instalable para Blender 26
Importación de módulos durante el desarrollo 26
Primeros pasos
Las listas son objetos4 sobre los que es posible iterar. Común- 4
En Python, todos los tipos son, en
mente, se les denomina iterables. Cualquier objeto iterable se puede realidad, objetos de alguna clase,
incluidos los tipos básicos como
recorrer por medio de un bucle for. La estructura de un bucle for los enteros o los números de coma
en Python es: flotante.
1 1
2 2
3 hola
4 adios
5 [1, 2, ’hola’, ’adios’]
1 a = [1,2,’hola’]
2 a.append("adios")
3 b = []
4 for v in a:
5 b.append(v)
6 print(v)
7 print(b)
1 1
2 [1]
3 2
4 [1, 2]
5 hola
6 [1, 2, ’hola’]
7 adios
8 [1, 2, ’hola’, ’adios’]
1 a = [1,3,5,2,7,9]
2 b = [1,4,1,9,8]
3 intersec_ab
4 for x in a:
5 if x in b: # True si x es un elemento de b
6 intersec_ab.append(x)
7 print(intersec_ab)
manual.
Funciones
Módulos
2
3 for n in range(10):
4 print(math.sqrt(n))
1 import bpy
2
3 for ob in bpy.context.scene.objects:
4 print(ob.name)
1 bpy.ops.mesh.primitive_cube_add(size=2,
2 enter_editmode=False, align=’WORLD’,
3 location=(0, 0, 0), scale=(1, 1, 1))
1 import bpy
2
3 bpy.ops.mesh.primitive_cube_add(size=2,
4 enter_editmode=False, align=’WORLD’,
5 location=(0, 0, 0), scale=(1, 1, 1))
6
7 nuevo_cubo = bpy.context.active_object
programación con python sobre blender 9
8 nuevo_cubo.location = (1,1,1)
9
10 cubo_original = bpy.context.scene.objects[’Cube’]
11 cubo_original.location = (-1,-1,-1)
obj = bpy.context.active_object
obj.keyframe_insert(data_path=’location’)
obj.keyframe_insert(data_path=’location’,frame=20)
Un poco de limpieza
obj.select_set(True)
bpy.ops.object.select_all(action=’DESELECT’)
nuevo_cubo.name = ’Proc_Object’
1 import bpy
2 import bmesh
3
4 obj = bpy.context.object
5
6 # Creamos un objeto de tipo BMesh y cargamos los datos
7 bm = bmesh.new()
8 bm.from_mesh(obj.data)
9
10 # Imprimimos
11 # Las coordenadas estan en el sistema de referencia
12 # local del objeto
13 for v in bm.verts:
14 print(v.co)
3. Los cubos deben estar cerca, pero no tocarse, para que se formen
calles.
Para conseguir este efecto podemos usar una función que tenga
un valor próximo a 1 en la región central y cuyo valor decrezca se-
gún nos alejamos. Podemos llamar a esta función p, porque será la
probabilidad de que haya un edificio a una determinada distancia
del centro.
f ( x ) = tanh ( x − 5)
Figura 7: La función tangente hiperbó-
tendrá la transición desde −1 a 1 alrededor de x = 5. También lica, en el intervalo [−20, 20].
Declaración de propiedades
1 def register():
2 bpy.types.Scene.tam_x_suelo = bpy.props.FloatProperty(min = 1,default = 10)
3 # continua...
4
5 bpy.types.Object.alt_edificios = bpy.props.FloatProperty(min = 1,default = 2)
6 # continua...
1 def unregister():
2 del bpy.types.Scene.tam_x_suelo
3 del bpy.types.Scene.tam_y_suelo
4 # continua...
Creación de un panel
42
43 bpy.types.Object.alt_edificios = bpy.props.FloatProperty(name = "Altura",
44 description="Altura media edificios",
45 min = 1,default = 2)
46 bpy.types.Object.var_edificios = bpy.props.FloatProperty(name = "Variacion",
47 description="Variabilidad edificios",
48 min = 0,default = 1)
49 # continua...
50
51 bpy.utils.register_class(ProceduralCityPanel)
52
53 def unregister():
54 bpy.utils.unregister_class(ProceduralCityPanel)
55
56 del bpy.types.Scene.tam_x_suelo
57 del bpy.types.Scene.tam_y_suelo
58 # continua...
59
60
61 if __name__ == "__main__":
62 register()
Creación de un operador
bpy.utils.register_class(GenerateGroundOperator)
bpy.utils.unregister_class(GenerateGroundOperator)
row = layout.row()
row.operator("object.gen_ground")
6
7 # Creacion del suelo de la ciudad
8 bpy.ops.mesh.primitive_grid_add(x_subdivisions=n_x,
9 y_subdivisions=n_y,
10 size=1,
11 enter_editmode=False,
12 align=’WORLD’,
13 location=(0, 0, 0),
14 scale=(tam_x, tam_y, 1))
15
16 # Las dimensiones las hemos aplicado usando la escala. Ahora hacemos que
17 # esas sean las dimensiones reales del objeto, para que no haya problemas
18 # con las transformaciones
19 bpy.ops.object.transform_apply(location=False, rotation=False, scale=True)
20
21 suelo = bpy.context.object
22
23 # Creamos un objeto de tipo BMesh y cargamos los datos
24 bm = bmesh.new()
25 bm.from_mesh(suelo.data)
26
27 # Modificamos la coordenada z de los vertices
28 for v in bm.verts:
29 # Llamamos a una funcion que genera las alturas
30 v.co.z = altura_suelo(v.co.x,v.co.y,... #completar
31
32 bm.to_mesh(suelo.data)
33 bm.free()
34
35 return suelo
Paquetes Python
Python cuenta con una lista de directorios en los que buscar los
módulos cuando ejecutamos import. Un paquete es un módulo que
se instala en uno de estos directorios. Esto consiste en organizar
todos los ficheros en un directorio con el nombre del módulo y
copiarlo a una de estas rutas en las que Python busca al invocar
import. Crear e instalar un módulo con nuestro código permite
usarlo sin necesidad de tener los ficheros en el mismo directorio en
el que estamos trabajando.
city/
city/__init__.py
city/ground.py
citiy/buildings.py
donde path es una ruta relativa al directorio del paquete. Esto nos
permite organizar el paquete en varias carpetas que actuarán como
submódulos. En nuestro caso no vamos a crear subdirectorios, por
lo que la ruta será siempre el directorio actual. De esta forma, en el
fichero __init__.py cambiaremos las lineas
import ground
import buildings
if __name__ == "city":
from . import ground
from . import buildings
else:
print("Loading procedural city as a script")
import ground
import buildings
Referencias