7.31.2006

Blender para programadores

Blender, como espero todos sepais, es un software para modelado, renderizado y un largo etcétera relacionado con el 3D. Lo interesante es que permite crear scripts en python para manipular los objetos, exportarlos, importarlos y todo lo se te pueda ocurrir.

Como el tiempo es oro, cuando programas algo con cierta entidad siempre surge la necesidad de crearte herramientas que faciliten y agilicen el trabajo. Para crearte las herramientas se puede optar por la vía de programarte todo un GUI en OpenGL (o en tu api favorita), usar algunas de las librerías como MFC, windows forms, wxWidgets, etc, usar un lenguaje no apropiado o usar el apropiado (por ejemplo python). Es posible que se pueda aprovechar mucho del código del motor, juego o lo que sea para hacer la tools, en ese caso es lógico usar el mismo sistema que usas en el motor, sin embargo si no es así, lo ideal es usar un lenguaje que permita trabajar rápido y te de cosas ya hechas. No quiero ser repetitivo, pero python encaja perfectamente ahí.

En algún rato libre estoy programando un juego de carreras de naves estilo wipeout además intentándolo meter todo en 96kb. Lógicamente no voy a guardar todos los datos de geometría en el ejecutable, pudiéndolo generar, para qué voy a gastar espacio a lo tonto? :P. Para generar la pista a cualquier se le ocurre que con unos cuantos puntos y una interpolación cúbica es más que suficiente. Qué es lo que permite hacerlo en 5 minutos? pues Blender da soporte para hacer pequeños GUI con pocas líneas, fácil acceso a los vértices, objetos, etc y además tienes toda la potencia de python.

Por ejemplo, para los puntos que generarán la línea y a su vez la malla se puede exportar de la siguiente forma:


def export_c():
O = Blender.Object.GetSelected()[0];
me = O.getData();
f = open("export.h","w");
f.write("vec3f track[%d]={\n"%len(me.verts));
for v in me.verts:
f.write("{%f,%f,%f},\n" %(v.co[0],v.co[1],v.co[2]));
f.write("};");
f.close();


Basta con seleccionar la malla y exportará los vértices. De esta forma puedo editar los vértices en blender a mi gusto y dar al botón de export, recompilo y ya lo tengo. De otra forma tendría que estar editando los vértices a mano hasta que consiguiera el resultado que quiero.




Las naves, por ejemplo, están basadas en quads con muy pocos polys. Para incluirlas en el código he creado un exportador:


def export(name):
p = Object.GetSelected()[0];
if(not p): return;
objname = p.getData(True);

me = NMesh.GetRaw(objname);
objname = objname.replace(".","_");
f = open(name,"w");
verts = [];
xmax = me.verts[0].co[0];
xmin = me.verts[0].co[0];
ymax = me.verts[0].co[1];
ymin = me.verts[0].co[1];
zmax = me.verts[0].co[2];
zmin = me.verts[0].co[2];

total = [0,0,0]
for x in me.verts:

if(xmax < x.co[0]): xmax = x.co[0];
if(xmin > x.co[0]): xmin = x.co[0];

if(ymax < x.co[1]): ymax = x.co[1];
if(ymin > x.co[1]): ymin = x.co[1];

if(zmax < x.co[2]): zmax = x.co[2];
if(zmin > x.co[2]): zmin = x.co[2];
total[0] = total[0] + x.co[0];
total[2] = total[1] + x.co[1];
total[1] = total[2] + x.co[2];

total[0] /= len(me.verts);
total[1] /= len(me.verts);
total[2] /= len(me.verts);
m = max(xmax-xmin,ymax-ymin,zmax-zmin);

f.write("float %s_verts[]={"%objname);

xpan = (xmax-xmin)/m;
ypan = (ymax-ymin)/m;
zpan = (zmax-zmin)/m;
for x in me.verts:
cx = (x.co[0]-xmin)/m;
cy = (x.co[1]-ymin)/m;
cz = (x.co[2]-zmin)/m;


f.write("%ff,%ff,%ff," % (cx-xpan/2.0,cy-ypan/2.0,cz-zpan/2.0));
f.write("};\n");

f.write("unsigned short %s_inds[]={"%objname);
for x in me.faces:
f.write("%d,%d,%d,%d," % (x.v[0].index,x.v[1].index,x.v[2].index,x.v[3].index));
f.write("};\n");

f.write("meshdata %s_mesh={"%objname);
f.write("%d,%s_verts,%d,%s_inds,0,0,0,0,0};\n"%( len(me.verts),objname,len(me.faces)*4,objname ));




Fácil, no?

De postre un wipeout en 32kb: el loco megabus