I'm trying to get a Blender python script that uses tkinter to function. It is supposed to open a 3d face object to allow a user to alter the nose for rhinoplasty surgery. However, it relies heavily on tkinter's ability to provide the GUI in order to allow the user to choose the necessary files; and the code won't run past the import statement for it.
Here's the code:
import bpy
import openpyxl
from pathlib import Path
import os
import tkinter as tk
from tkinter import filedialog
from tkinter import *
activate = 0
#select original data points xlsx file
def selectDataPointsFile():
global dataPointsFile_path
global activate
dataPointsFile_path = filedialog.askopenfilename(filetypes=[("Excel files", "*.xlsx")])
activate += 1
if (activate == 3):
addPointsAndFaceButton['state'] = tk.NORMAL
newDataPointsButton['state'] = tk.NORMAL
#select new data points xlsx file
def selectNewDataPointsFile():
global newDataPointsFile_path
global activate
newDataPointsFile_path = filedialog.askopenfilename(filetypes=[("Excel files", "*.xlsx")])
activate += 1
if (activate == 3):
addPointsAndFaceButton['state'] = tk.NORMAL
faceObjectButton['state'] = tk.NORMAL
#select patient face obj file
def selectFaceObjectFile():
global faceObjectFile_path
global activate
faceObjectFile_path = filedialog.askopenfilename(filetypes=[("Object files", "*.obj")])
activate += 1
print("Data POint Button")
if (activate == 3):
meshFileExportButton['state'] = tk.NORMAL
#select patient face obj file
def meshFile():
global meshFile_path
global activate
meshFile_path = filedialog.askdirectory()
addPointsAndFaceButton['state'] = tk.NORMAL
#add the face with new and old points
def facePointsAdd():
r = 1
wb_obj = openpyxl.load_workbook(dataPointsFile_path)
wsheet = wb_obj.active
wb_objNew = openpyxl.load_workbook(newDataPointsFile_path)
wsheetNew = wb_objNew.active
#swap y and z invert old z
#old nose points
noseLoop = []
namez = []
for i in range(1, 49):
nosePoint = (wsheet["B"+str(i)].value, -wsheet["D"+str(i)].value, wsheet["C"+str(i)].value)
noseLoop.append(nosePoint)
namez.append(wsheet["A"+str(i)].value)
#new nose points
noseLoopNew = []
namezNew = []
for i in range(1, 49):
nosePointNew = (wsheetNew["B"+str(i)].value, -wsheetNew["D"+str(i)].value, wsheetNew["C"+str(i)].value)
noseLoopNew.append(nosePointNew)
namezNew.append(wsheetNew["A"+str(i)].value)
#list of colored points so old and new points matchup
colorList = []
colorList.append((0., 0., 0.,0.))
colorList.append((0., 0., 0.,0.))
colorList.append((1., 0., 0.,0.))
colorList.append((20., 30., 60.,0.))
colorList.append((1., 1., 0.,0.))
colorList.append((0., 0., 1.,0.))
colorList.append((1., 0., 1.,0.))
colorList.append((0., 1., 1.,0.))
colorList.append((1., 1., 1.,0.))
colorList.append((50., 1., 30.,0.))
colorList.append((0., 1., 0.,0.))
colorList.append((40., 100., 0.,0.))
colorList.append((0., 50., 2.,0.))
colorList.append((.67,.907,9,1.)) #12
colorList.append((.1,.85,69.,0.))
colorList.append((.3,30.,0.,0.))
colorList.append((40.,1.,0.,0.))
colorList.append((3.,0.,40.,0.))
colorList.append((40.,.1,.3,0.))
colorList.append((0., 250., 40.,0.))
colorList.append((1.3,40.5,0.,0.))
colorList.append((40.5,0.,35.5,0.))
colorList.append((0.,2., 40.,0.))
colorList.append((.3,40.,.1,0.))
colorList.append((0.,40.5,.3,0.))
colorList.append((35.5,40.,0.,0.))
colorList.append((0., 0., 50.,0.))
colorList.append((255.,105.,180.,0.))
colorList.append((.67,.907,9,1.)) #12
colorList.append((.1,.85,69.,0.))
colorList.append((.3,30.,0.,0.))
colorList.append((40.,1.,0.,0.))
colorList.append((3.,0.,40.,0.))
colorList.append((40.,.1,.3,0.))
colorList.append((0., 250., 40.,0.))
colorList.append((1.3,40.5,0.,0.))
colorList.append((40.5,0.,35.5,0.))
colorList.append((0.,2., 40.,0.))
colorList.append((.3,40.,.1,0.))
colorList.append((0.,40.5,.3,0.))
colorList.append((35.5,40.,0.,0.))
colorList.append((0., 0., 50.,0.))
colorList.append((255.,105.,180.,0.))
colorList.append((.67,.907,9,1.)) #12
colorList.append((.1,.85,69.,0.))
colorList.append((.3,30.,0.,0.))
colorList.append((40.,1.,0.,0.))
colorList.append((3.,0.,40.,0.))
colorList.append((40.,.1,.3,0.))
colorList.append((0., 250., 40.,0.))
colorList.append((1.3,40.5,0.,0.))
colorList.append((40.5,0.,35.5,0.))
colorList.append((0.,2., 40.,0.))
colorList.append((.3,40.,.1,0.))
colorList.append((0.,40.5,.3,0.))
colorList.append((35.5,40.,0.,0.))
colorList.append((0., 0., 50.,0.))
colorList.append((255.,105.,180.,0.))
def makeMat(num):
mat = bpy.data.materials.new(name = namez[i])
mat.diffuse_color = colorList[i]
mat.specular_color = (1., 1., 1.)
return mat
imported_object = bpy.ops.import_scene.obj(filepath=faceObjectFile_path)
for i in range(0, 47):
bpy.ops.mesh.primitive_uv_sphere_add(radius= r, location=noseLoop[i])
sphere = bpy.context.object
sphere.name = namez[i]
mesh = sphere.data
mat = makeMat(i)
mesh.materials.append(mat)
bpy.ops.mesh.primitive_cube_add(size= r, location=noseLoopNew[i])
cube = bpy.context.object
cube.name = (namezNew[i] + ' New')
mesh = cube.data
mat = makeMat(i)
mesh.materials.append(mat)
bpy.ops.object.select_all(action='DESELECT')
activeObj = bpy.context.window.scene.objects[0]
for i in range(0, 47):
bpy.data.objects[namez[i]].select_set(True) # Blender 2.8x
bpy.context.view_layer.objects.active = activeObj
bpy.ops.object.parent_set(type='VERTEX')
bpy.ops.object.select_all(action='DESELECT')
bpy.ops.object.mode_set(mode='SCULPT')
#insert mesh 1 (old nose mesh)
# make mesh
vertices = noseLoopNew
edges = []
faces = [[14,24,23],[14,24,22],[24,18,23],[24,17,22],[24,18,29],[24,29,17],[18,23,41],[17,22,40],[18,41,29],[29,17,40],[29,41,39],[29,40,39],[1,5,23],[5,41,23],[41,39,28],[39,40,28],[5,41,3],[3,41,7],[7,41,28],[28,40,6],[6,40,2],[22,2,4],[40,22,2],[22,4,0],[3,7,35],[7,35,28],[35,34,28],[28,34,6],[6,34,2],[34,2,26],[2,4,26],[4,31,26],[4,0,31],[32,1,5],[32,5,27],[5,27,3],[32,36,27],[3,27,35],[35,36,27],[34,35,36],[36,34,26],[36,26,31]]
newNoseMesh = bpy.data.meshes.new('newNoseMesh')
newNoseMesh.from_pydata(vertices, edges, faces)
newNoseMesh.update()
# make object from mesh
newNoseMesh_object = bpy.data.objects.new('newNoseMesh_object', newNoseMesh)
# create a collection
mesh_collection = bpy.data.collections.new('mesh_collection')
bpy.context.scene.collection.children.link(mesh_collection)
# add object to scene collection
mesh_collection.objects.link(newNoseMesh_object)
bpy.object = newNoseMesh
newMeshMat = bpy.data.materials.new('New Mesh Mat')
newMeshMat.use_nodes=True
nodes = newMeshMat.node_tree.nodes
newMeshMat.node_tree.nodes["Principled BSDF"].inputs[0].default_value = (0.8, 0, 0.704733,1)
newMeshMat.node_tree.nodes["Principled BSDF"].inputs[18].default_value = 1
newNoseMesh_object.active_material = newMeshMat
newNoseMesh_object.active_material.blend_method = 'BLEND'
#insert mesh 2
vertices = noseLoop
edges = []
faces = [[14,24,23],[14,24,22],[24,18,23],[24,17,22],[24,18,29],[24,29,17],[18,23,41],[17,22,40],[18,41,29],[29,17,40],[29,41,39],[29,40,39],[1,5,23],[5,41,23],[41,39,28],[39,40,28],[5,41,3],[3,41,7],[7,41,28],[28,40,6],[6,40,2],[22,2,4],[40,22,2],[22,4,0],[3,7,35],[7,35,28],[35,34,28],[28,34,6],[6,34,2],[34,2,26],[2,4,26],[4,31,26],[4,0,31],[32,1,5],[32,5,27],[5,27,3],[32,36,27],[3,27,35],[35,36,27],[34,35,36],[36,34,26],[36,26,31]]
oldNoseMesh = bpy.data.meshes.new('oldNoseMesh')
oldNoseMesh.from_pydata(vertices, edges, faces)
oldNoseMesh.update()
# make object from mesh
oldNoseMesh_object = bpy.data.objects.new('oldNoseMesh_object', oldNoseMesh)
# add object to scene collection
mesh_collection.objects.link(oldNoseMesh_object)
bpy.object = oldNoseMesh
meshMat = bpy.data.materials.new('Mesh Mat')
meshMat.use_nodes=True
nodes = meshMat.node_tree.nodes
meshMat.node_tree.nodes["Principled BSDF"].inputs[0].default_value = (0.00205669, 0.8, 0.0157096, 1)
meshMat.node_tree.nodes["Principled BSDF"].inputs[18].default_value = 1 #.4
oldNoseMesh_object.active_material = meshMat
oldNoseMesh_object.active_material.blend_method = 'BLEND'
#change opcacity of face
activeObj = bpy.context.window.scene.objects[0]
bpy.context.object.active_material.node_tree.nodes["Principled BSDF"].inputs[18].default_value = 0
bpy.context.object.active_material.blend_method = 'BLEND'
bpy.context.object.active_material.use_backface_culling = False
#export face
exportFileName = activeObj.name
if "." in activeObj.name:
print("Yes")
exportFileName = exportFileName[:-4]
#print(exportFileName)
#export obj to face to (patientName)MeshNose.obj
target_file = os.path.join(meshFile_path, exportFileName + ('MeshNose.obj'))
bpy.ops.export_scene.obj(filepath=target_file)
#delete meshes
bpy.data.objects['newNoseMesh_object'].select_set(True)
bpy.ops.object.delete()
bpy.data.objects['oldNoseMesh_object'].select_set(True)
bpy.ops.object.delete()
# solidify face
activeObj = bpy.context.window.scene.objects[0]
bpy.context.object.active_material.blend_method = 'OPAQUE'
bpy.context.object.active_material.node_tree.nodes["Principled BSDF"].inputs[18].default_value = 1
bpy.context.object.active_material.use_backface_culling = False
bpy.ops.object.mode_set(mode='SCULPT')
#closes little window
root.destroy()
root = Tk()
dataPointsButton = Button(root, text="Select Old Nose Data Point File For Patient(.xlsx)", command=selectDataPointsFile)
newDataPointsButton = Button(root, text="Select New Nose Data Point File For Patient(.xlsx)", command=selectNewDataPointsFile, state=tk.DISABLED)
faceObjectButton = Button(root, text="Select 3d Model Patient Face (.obj)", command=selectFaceObjectFile, state=tk.DISABLED)
meshFileExportButton = Button(root, text="Select the Folder You Want to Export meshFile in", command=meshFile, state=tk.DISABLED)
addPointsAndFaceButton = Button(root, text="Add The Patient's Face with Points", command=facePointsAdd, state=tk.DISABLED)
dataPointsButton.grid(row = 0, column = 0)
newDataPointsButton.grid(row = 1, column = 0)
faceObjectButton.grid(row = 2, column = 0)
meshFileExportButton.grid(row = 3, column = 0)
addPointsAndFaceButton.grid(row = 4, column = 0)
root.mainloop()
print(dataPointsFile_path)
print(faceObjectFile_path)
r = 1
wb_objTest = openpyxl.load_workbook(dataPointsFile_path)
wsheetTest = wb_objTest.active
wb_objNew = openpyxl.load_workbook(newDataPointsFile_path)
wsheetNew = wb_objNew.active
And here's the error it outputs:
I'm wondering if the issue may be that I have improperly installed tkinter into the Blender ./Scripts/modules folder...
I appreciate any help and thanks in advance.