Importare dati in Blender. Conversione in Python
Il controllo di Blender con il linguaggio Python permette di sviluppare idee con potenza e flessibilità. Utilizzando l’interfaccia di Blender si può osservare che ogni pulsante od oggetto presente nel software, è corredato da una tooltip che visualizza il comando in python equivalente. Per far comparire una tendina tooltip basta soffermarsi con il puntatore del mouse sopra un oggetto. In Blender un intero progetto 3d può quindi essere realizzato completamente da riga di comando.
Una volta definiti vertici e superfici rettangolari, è possibile assemblare qualsiasi solido con poche righe di comando. Assegnato un nome al solido, la fase successiva di modellazione consiste nell’assegnare automaticamente un determinato materiale ad ogni oggetto. Il codice scritto in Matlab genera un altro codice in Python che deve essere lanciato all’interno di Blender. Per utilizzare gli script in python è conveniente passare all’interfaccia “scripting” di Blender.
Definizione di un materiale in Blender – Cycles
Importare figure geometriche in Blender
In una matrice chiamata “elenco_quadrati” sono definiti qualche migliaio di quadrati tutti con determinate dimensioni e posizione sul piano cartesiano xy. I quadrati devono essere importati in Blender realizzando per ognuno di essi un parallelepipedo avente la base del quadrato ed un altezza prefissata. Ad ognuno di questi solidi deve successivamente essere assegnato un materiale unico all’interno dell’ambiente Cycles. Ogni parallelepipedo viene gestito in Blender definendo i vertici con coordinate (x,y,z) e le facce rettangolari che formano la mesh superficiale del solido.vertici = [(xmax, ymax, zmin),
(xmax, ymin, zmin),
(xmin, ymin, zmin),
(xmin, ymax, zmin),
(xmax, ymax, zmax),
(xmax, ymin, zmax),
(xmin, ymin, zmax),
(xmin, ymax, zmax)]
facce = [(0, 1, 2, 3),
(4, 7, 6, 5),
(0, 4, 5, 1),
(1, 5, 6, 2),
(2, 6, 7, 3),
(4, 0, 3, 7)]
function scrivi_py ()
% Autori
% Prof. Danilo Pasquini IPSIA Parodi Delfino, Colleferro (Roma)
% Prof. Paolo Sordi IPSIA A. Pacinotti, Pontedera (Pisa)
%
load ton39
scala = 10;
[riga,colonna] = size (matrice_contorno);
fattore = 0;
while (riga * colonna) * fattore * fattore < 24000000
%while (r * c) * fattore * fattore < 4800 * 6400
fattore = fattore + 1
end
elenco_quadrati (1:end,10) = 0
elenco_quadrati (1:end,11) = 10
nomefile = ['svg1' num2str(ceil(rand()*100)) '.py']
fid = fopen(nomefile, 'wt');
fprintf(fid, ['import bpy \n']);
[a,b] = size (elenco_quadrati);
minimo_x = min(elenco_quadrati (1:end,1));
massimo_x = max(elenco_quadrati (1:end,1));
minimo_y = min(elenco_quadrati (1:end,2));
massimo_y = max(elenco_quadrati (1:end,2));
medio_x = (massimo_x - minimo_x)/2;
medio_y = (massimo_y - minimo_y)/2;
elenco_quadrati (end+1,1) = minimo_x - medio_x * 2
elenco_quadrati (end,2) = minimo_y - medio_y * 2
elenco_quadrati (end,3) = max(medio_y*6,medio_x*6)
elenco_quadrati (end,5) = 255;
elenco_quadrati (end,6) = 255;
elenco_quadrati (end,7) = 255;
elenco_quadrati (end,10) = -5;
elenco_quadrati (end,11) = 0;
[a,b] = size (elenco_quadrati);
numero_inseriti = 0;
vettore = ones(a);
while numero_inseriti < a
prova = ceil(rand * a);
if vettore(prova) == 1
vettore(prova) = 0;
numero_inseriti = numero_inseriti + 1;
i = prova;
raggio = elenco_quadrati (i,3);
coord_x = elenco_quadrati (i,1) - medio_x;
coord_y = elenco_quadrati (i,2) - medio_y;
zmin = elenco_quadrati (i,10);
zmax = elenco_quadrati (i,11);
colore1 = elenco_quadrati (i,5)/255;
colore2 = elenco_quadrati (i,6)/255;
colore3 = elenco_quadrati (i,7)/255;
fprintf(fid, ['xmin =' num2str(coord_x/scala) ' \n']);
fprintf(fid, ['xmax =' num2str((coord_x+raggio)/scala) ' \n']);
fprintf(fid, ['ymin =' num2str(coord_y/scala) ' \n']);
fprintf(fid, ['ymax =' num2str((coord_y+raggio)/scala) ' \n']);
fprintf(fid, ['zmin =' num2str(zmin/scala) ' \n']);
fprintf(fid, ['zmax =' num2str(zmax/scala) ' \n']);
fprintf(fid, ['vertici = [(xmax, ymax, zmin), \n']);
fprintf(fid, [' (xmax, ymin, zmin), \n']);
fprintf(fid, [' (xmin, ymin, zmin), \n']);
fprintf(fid, [' (xmin, ymax, zmin), \n']);
fprintf(fid, [' (xmax, ymax, zmax), \n']);
fprintf(fid, [' (xmax, ymin, zmax), \n']);
fprintf(fid, [' (xmin, ymin, zmax), \n']);
fprintf(fid, [' (xmin, ymax, zmax)] \n']);
fprintf(fid, ['facce = [(0, 1, 2, 3), \n']);
fprintf(fid, [' (4, 7, 6, 5), \n']);
fprintf(fid, [' (0, 4, 5, 1), \n']);
fprintf(fid, [' (1, 5, 6, 2), \n']);
fprintf(fid, [' (2, 6, 7, 3), \n']);
fprintf(fid, [' (4, 0, 3, 7)] \n']);
fprintf(fid, ['mesh_data = bpy.data.meshes.new("cube_mesh_data") \n']);
fprintf(fid, ['mesh_data.from_pydata(verts, [], faces) \n']);
fprintf(fid, ['mesh_data.update() # (calc_edges=True) not needed here \n']);
fprintf(fid, ['cube_object = bpy.data.objects.new("Cube_Object' num2str(i) '", mesh_data) \n']);
fprintf(fid, [' \n']);
fprintf(fid, ['scene = bpy.context.scene \n']);
fprintf(fid, ['scene.objects.link(cube_object) \n']);
fprintf(fid, ['cube_object.select = True \n']);
fprintf(fid, [' \n']);
fprintf(fid, ['my_object = bpy.data.objects[''Cube_Object' num2str(i) '''].data \n']);
fprintf(fid, ['mat = bpy.data.materials.new(''vertex_material' num2str(i) ''') \n']);
fprintf(fid, ['mat.diffuse_color = (', num2str(colore1), ',', num2str(colore2), ',' , num2str(colore3) ') \n']);
fprintf(fid, ['mat.specular_color = (', num2str(colore1), ',', num2str(colore2), ',' , num2str(colore3) ') \n']);
fprintf(fid, ['my_object.materials.append(mat) \n']);
fprintf(fid, [' \n']);
end
end
fclose(fid)
pause(1)
load chirp;
y1 = y; Fs1 = Fs;
load gong;
wavplay(y1,Fs1,'sync') % The chirp signal finishes before the
Gestire la definizione di un materiale tramite Python
Cycles permette di progettare ogni materiale utilizzando uno schema a blocchi. La definizione di un materiale può essere impostata come se si lavorasse con dei blocchi matematici: l’ambiente di lavoro di cycles assomiglia molto ai programmi di simulazione elettronica o al classico Simulink di Matlab. Anche se il primo approccio può risultare un po’ complicato dopo un po’ di prove, la modellazione della maggior parte dei materiali diventa facilmente gestibile. Ogni blocco definito in Cycles viene chiamato nodo. La comunicazione tra i nodi avviene collegando delle linee tra i pin di input e output di ogni blocco. Anche questa fase di progettazione del materiale, può essere gestita interamente da uno script realizzato in Python. Ogni nodo creato da riga di comando deve essere posizionato fisicamente all’interno dell’area di lavoro attraverso il metodo “node.location”. I vari nodi possono essere collegati con la creazione di un link:out = nodes['diff'].outputs[0]
inp = nodes['mixer'].inputs[2]
mat.node_tree.links.new(out, inp)
# Autori
# Prof. Danilo Pasquini IPSIA Parodi Delfino, Colleferro (Roma)
# Prof. Paolo Sordi IPSIA A. Pacinotti, Pontedera (Pisa)
# Codice in Python per realizzare un materiale misto tra comportamento Diffuse e Gloss
#
import bpy
def creazione_materiale(matname, r=1, g=1, b=1, alpha=0):
scena = bpy.context.scene
if not scena.render.engine == 'CYCLES':
scena.render.engine = 'CYCLES'
mat = bpy.data.materials.new(matname)
mat.use_nodes = True
mat.diffuse_color = (r, g, b)
nodes = mat.node_tree.nodes
node=nodes['Diffuse BSDF']
nodes.remove(node)
node=nodes['Material Output']
node.location = 400, 160
node1 = nodes.new('ShaderNodeBsdfGlossy')
node1.name = 'gloss'
node1.location = 10, 260
node1.inputs[0].default_value = [r, g, 0.25, alpha]
node2 = nodes.new('ShaderNodeBsdfDiffuse')
node2.name = 'diff'
node2.location = 10, 80
node2.inputs[0].default_value = [r, g, 0.3, alpha]
node3 = nodes.new('ShaderNodeMixShader')
node3.name = 'mixer'
node3.location = 200, 160
node3.inputs[0].default_value = 0.457
print (' self=')
out = nodes['gloss'].outputs[0]
inp = nodes['mixer'].inputs[1]
mat.node_tree.links.new(out, inp)
out = nodes['diff'].outputs[0]
inp = nodes['mixer'].inputs[2]
mat.node_tree.links.new(out, inp)
out = nodes['mixer'].outputs[0]
inp = nodes['Material Output'].inputs[0]
mat.node_tree.links.new(out, inp)
return mat
creazione_materiale (materiale_name = "materiale1", r=0.6, g=0.6, b=0.4, alpha=0)