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.
Importare oggetti all’interno di Python. Automazione processi di modellazione e rendering

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.
  1. vertici = [(xmax, ymax, zmin),  
  2.            (xmax, ymin, zmin),  
  3.            (xmin, ymin, zmin),  
  4.            (xmin, ymax, zmin), 
  5.            (xmax, ymax, zmax),  
  6.            (xmax, ymin, zmax), 
  7.            (xmin, ymin, zmax),  
  8.            (xmin, ymax, zmax)]  
  9. facce = [(0, 1, 2, 3),         
  10.          (4, 7, 6, 5), 
  11.          (0, 4, 5, 1), 
  12.          (1, 5, 6, 2), 
  13.          (2, 6, 7, 3),  
  14.          (4, 0, 3, 7)]
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.
  1. function scrivi_py ()
  2. % Autori
  3. % Prof. Danilo Pasquini IPSIA Parodi Delfino, Colleferro (Roma)
  4. % Prof. Paolo Sordi IPSIA A. Pacinotti, Pontedera (Pisa) 
  5. %
  6. load ton39
  7. scala = 10;
  8. [riga,colonna] = size (matrice_contorno);
  9. fattore  = 0;
  10. while (riga * colonna) * fattore * fattore   < 24000000
  11.     %while (r * c) * fattore * fattore   < 4800 * 6400
  12.     fattore = fattore + 1
  13. end
  14. elenco_quadrati (1:end,10) = 0
  15. elenco_quadrati (1:end,11) = 10 
  16. nomefile = ['svg1' num2str(ceil(rand()*100))  '.py']
  17. fid = fopen(nomefile, 'wt');
  18. fprintf(fid, ['import bpy  \n']);
  19. [a,b] = size (elenco_quadrati);
  20.  
  21. minimo_x  = min(elenco_quadrati (1:end,1));
  22. massimo_x = max(elenco_quadrati (1:end,1));
  23. minimo_y  = min(elenco_quadrati (1:end,2));
  24. massimo_y = max(elenco_quadrati (1:end,2));
  25. medio_x = (massimo_x - minimo_x)/2;
  26. medio_y = (massimo_y - minimo_y)/2;
  27.  
  28. elenco_quadrati (end+1,1) = minimo_x - medio_x * 2
  29. elenco_quadrati (end,2)   = minimo_y - medio_y * 2
  30. elenco_quadrati (end,3) = max(medio_y*6,medio_x*6)
  31. elenco_quadrati (end,5) = 255;
  32. elenco_quadrati (end,6) = 255;
  33. elenco_quadrati (end,7) = 255;
  34. elenco_quadrati (end,10) = -5;
  35. elenco_quadrati (end,11) = 0;
  36. [a,b] = size (elenco_quadrati);
  37. numero_inseriti = 0;
  38. vettore = ones(a);
  39. while numero_inseriti < a
  40.     prova = ceil(rand * a); 
  41.     if vettore(prova) == 1
  42.         vettore(prova) = 0;
  43.         numero_inseriti = numero_inseriti + 1;
  44.         i = prova;
  45.         raggio = elenco_quadrati (i,3); 
  46.         coord_x = elenco_quadrati (i,1) - medio_x;
  47.         coord_y = elenco_quadrati (i,2) - medio_y;
  48.         zmin = elenco_quadrati (i,10);
  49.         zmax = elenco_quadrati (i,11);
  50.         colore1 = elenco_quadrati (i,5)/255;
  51.         colore2 = elenco_quadrati (i,6)/255;
  52.         colore3 = elenco_quadrati (i,7)/255;
  53.         fprintf(fid, ['xmin =' num2str(coord_x/scala)  ' \n']);
  54.         fprintf(fid, ['xmax =' num2str((coord_x+raggio)/scala)  ' \n']);
  55.         fprintf(fid, ['ymin =' num2str(coord_y/scala)  ' \n']);
  56.         fprintf(fid, ['ymax =' num2str((coord_y+raggio)/scala)  ' \n']);
  57.         fprintf(fid, ['zmin =' num2str(zmin/scala)  ' \n']);
  58.         fprintf(fid, ['zmax =' num2str(zmax/scala)  ' \n']);
  59.         fprintf(fid, ['vertici = [(xmax, ymax, zmin),  \n']);
  60.         fprintf(fid, ['         (xmax, ymin, zmin),  \n']);
  61.         fprintf(fid, ['         (xmin, ymin, zmin),  \n']);
  62.         fprintf(fid, ['         (xmin, ymax, zmin), \n']);
  63.         fprintf(fid, ['         (xmax, ymax, zmax),  \n']);
  64.         fprintf(fid, ['         (xmax, ymin, zmax), \n']);
  65.         fprintf(fid, ['         (xmin, ymin, zmax),  \n']);
  66.         fprintf(fid, ['         (xmin, ymax, zmax)]  \n']);
  67.         fprintf(fid, ['facce = [(0, 1, 2, 3), \n']);        
  68.         fprintf(fid, ['         (4, 7, 6, 5), \n']);
  69.         fprintf(fid, ['         (0, 4, 5, 1), \n']);
  70.         fprintf(fid, ['         (1, 5, 6, 2), \n']);
  71.         fprintf(fid, ['         (2, 6, 7, 3),  \n']);
  72.         fprintf(fid, ['         (4, 0, 3, 7)]  \n']);        
  73.         fprintf(fid, ['mesh_data = bpy.data.meshes.new("cube_mesh_data")  \n']);        
  74.         fprintf(fid, ['mesh_data.from_pydata(verts, [], faces) \n']);
  75.         fprintf(fid, ['mesh_data.update() # (calc_edges=True) not needed here  \n']);
  76.         fprintf(fid, ['cube_object = bpy.data.objects.new("Cube_Object' num2str(i)   '", mesh_data) \n']);
  77.         fprintf(fid, [' \n']); 
  78.         fprintf(fid, ['scene = bpy.context.scene   \n']);
  79.         fprintf(fid, ['scene.objects.link(cube_object)     \n']);
  80.         fprintf(fid, ['cube_object.select = True  \n']);
  81.         fprintf(fid, [' \n']); 
  82.         fprintf(fid, ['my_object = bpy.data.objects[''Cube_Object' num2str(i) '''].data  \n']);  
  83.         fprintf(fid, ['mat = bpy.data.materials.new(''vertex_material' num2str(i)  ''') \n']);
  84.         fprintf(fid, ['mat.diffuse_color  = (', num2str(colore1), ',', num2str(colore2), ',' , num2str(colore3) ') \n']);        
  85.         fprintf(fid, ['mat.specular_color = (', num2str(colore1), ',', num2str(colore2), ',' , num2str(colore3) ') \n']);        
  86.         fprintf(fid, ['my_object.materials.append(mat)   \n']);
  87.         fprintf(fid, [' \n']);
  88.     end
  89. end
  90.  
  91. fclose(fid)
  92. pause(1)
  93. load chirp;
  94. y1 = y; Fs1 = Fs;
  95. load gong;
  96. 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:
  1.     out = nodes['diff'].outputs[0]
  2.     inp = nodes['mixer'].inputs[2]
  3.     mat.node_tree.links.new(out, inp)
Definizione di un materiale in Blender – Cycles
  1. # Autori
  2. # Prof. Danilo Pasquini IPSIA Parodi Delfino, Colleferro (Roma)
  3. # Prof. Paolo Sordi IPSIA A. Pacinotti, Pontedera (Pisa) 
  4. # Codice in Python per realizzare un materiale misto tra comportamento Diffuse e Gloss
  5. #
  6. import bpy  
  7. def creazione_materiale(matname, r=1, g=1, b=1, alpha=0):
  8.  
  9.     scena = bpy.context.scene
  10.     if not scena.render.engine == 'CYCLES':
  11.         scena.render.engine = 'CYCLES'
  12.  
  13.     mat = bpy.data.materials.new(matname)
  14.     mat.use_nodes = True
  15.     mat.diffuse_color = (r, g, b)
  16.     nodes = mat.node_tree.nodes
  17.  
  18.     node=nodes['Diffuse BSDF']
  19.     nodes.remove(node)
  20.  
  21.     node=nodes['Material Output']
  22.     node.location = 400, 160
  23.  
  24.     node1 = nodes.new('ShaderNodeBsdfGlossy')
  25.     node1.name = 'gloss'
  26.     node1.location = 10, 260
  27.     node1.inputs[0].default_value = [r, g, 0.25, alpha]
  28.  
  29.     node2 = nodes.new('ShaderNodeBsdfDiffuse')
  30.     node2.name = 'diff'
  31.     node2.location = 10, 80
  32.     node2.inputs[0].default_value = [r, g, 0.3, alpha]
  33.  
  34.     node3 = nodes.new('ShaderNodeMixShader')
  35.     node3.name = 'mixer'
  36.     node3.location = 200, 160
  37.     node3.inputs[0].default_value = 0.457
  38.     print (' self=')
  39.  
  40.     out = nodes['gloss'].outputs[0]
  41.     inp = nodes['mixer'].inputs[1]
  42.     mat.node_tree.links.new(out, inp)
  43.  
  44.     out = nodes['diff'].outputs[0]
  45.     inp = nodes['mixer'].inputs[2]
  46.     mat.node_tree.links.new(out, inp)
  47.  
  48.     out = nodes['mixer'].outputs[0]
  49.     inp = nodes['Material Output'].inputs[0]
  50.     mat.node_tree.links.new(out, inp)
  51.  
  52.     return mat
  53.  
  54. creazione_materiale (materiale_name = "materiale1",  r=0.6, g=0.6, b=0.4, alpha=0)