-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathpainterly-maya.py
1835 lines (1498 loc) · 75.1 KB
/
painterly-maya.py
1
import maya.cmds as cmdsimport maya.OpenMaya as OpenMayafrom maya import melimport sysimport osfrom math import *import random#sys.path.append( 'C:\Python25\Lib\site-packages' )sys.path.append( 'C:\Python26\Lib\site-packages' )from PIL import Imagefrom PIL import ImageFilterimport shutil as file_utilsimport time''' new import -- make sure you download numpy '''#from numpy import *############################################################ FIELDS ############################################################ image_filename = ""## dd mslab directory ###directory = "//win.cs.brown.edu/dfs/home/ddufresn/My Documents/PainterlyRender/"## mf laptop directory ###directory = "C:/Documents and Settings/matthew/Desktop/painterly/project/"## mf home directory ###directory = "C:/Documents and Settings/Matt/Desktop/painterly/project/"## mf lab directory ##directory = "//win.cs.brown.edu/dfs/home/mattf/WinData/Desktop/painterly/project/"#directory = ""thumbs_ext = "thumbs\\"renders_ext = 'renders'layers_ext = 'layers'composite_ext = 'composite'brush_size = 0.1stroke_density = 1num_strokes = 500num_colors = 10stroke_growth = 0orient_along_edges = Falsegx_filename = ""gy_filename = ""output_dir = ""base_billboards = []base_tufts = []active_cam = 'painterlyCam'build_cam = 'painterlyCam'prep_frame_btn = Falsecolor_palette=[]max_width = 400menu_txt_field = 'menu_disp_txt'window_name = 'painterly_render_ui'pad_length = 4render_path = ""render_lyr_base = "base_"render_lod0_str = "RenderLayerLOD0"render_lod1_str = "RenderLayerLOD1"render_lod2_str = "RenderLayerLOD2"lod0_file = "lod0"lod1_file = "lod1"lod2_file = "lod2"############################################################ __ __ ______ _______ _ _ ____ _____ _____ #### | \/ | ____|__ __| | | |/ __ \| __ \ / ____| #### | \ / | |__ | | | |__| | | | | | | | (___ #### | |\/| | __| | | | __ | | | | | | |\___ \ #### | | | | |____ | | | | | | |__| | |__| |____) | #### |_| |_|______| |_| |_| |_|\____/|_____/|_____/ #### ####################################################################### BRUSH PARAMETER METHODS #################def setBrushImage(filename): global image_filename image_filename = filenamedef setBrushSize(size): global brush_size brush_size = sizedef setNumStrokes(strokes): global num_strokes num_strokes = strokesdef setPaddingLength(length): global pad_length pad_length = length print pad_lengthdef setActiveCam(): global active_cam camera = cmds.optionMenuGrp('cam_select', v=True, q=True) active_cam = camera mel.eval("lookThroughModelPanel "+active_cam+" modelPanel4;") mel.eval("updateModelPanelBar modelPanel4;") print 'active camera set to ->> '+active_cam############ SET DIRECTORY #######################def setDirectory(dirName, dirType): print 'setting directory to '+dirName global directory directory = dirName+'/' cmds.textField('dir_display', tx=directory, e=True) cmds.button("prep_frame_button", en=True, e=True) cmds.button('brush_image_grp', en=True, e=True) global image_filename if (len(image_filename) > 0): cmds.button("prep_button", enable=True, e=True)def getDirectory(): global directory return directorydef setImgSeqPath(fn): global render_path base = os.path.basename(fn) file, ext = os.path.splitext(base) global pad_length #print pad_length pad_str = padFrame(0, pad_length) x_pad_str = pad_str.replace('0', 'x') #print 'padding_str '+pad_str+' -> '+x_pad_str #print 'setting img sequence path to '+fileName+' of type '+fileType cmds.textField('img_seq_filename', tx=file+'_['+x_pad_str+'].png', e=True) full_fn, ext = os.path.splitext(fn) render_path = file+'.png' print 'render path sent to '+render_pathdef setImgSequencePath(fileName, fileType): global render_path base = os.path.basename(fileName) fn, ext = os.path.splitext(base) global pad_length #print pad_length pad_str = padFrame(0, pad_length) x_pad_str = pad_str.replace('0', 'x') #print 'padding_str '+pad_str+' -> '+x_pad_str if ext == '' or ext == None: ext = '.iff' base += ext fileName += ext #print 'setting img sequence path to '+fileName+' of type '+fileType cmds.textField('img_seq_filename', tx=fn+'_['+x_pad_str+']'+ext, e=True) full_fn, ext = os.path.splitext(fileName) render_path = fn+ext #print 'render path set to ->> '+render_path def padFrame(frame, pad): frame_len = -1 i = 1 while frame_len < 1: divisor = 10**i if frame/divisor < 1: frame_len = i i = i+1 padding = '' for j in range(0, pad-frame_len): padding += '0' rtn_str = padding+str(frame) return rtn_str######################### GEOMETRY METHODS ################################## ############################################## Returns the magnitude of a vector ##############################################def magnitude(vec): return sqrt(vec[0]**2+vec[1]**2+vec[2]**2)#################################################### Returns the crossproduct of two vectors ####################################################def crossproduct(A, B): C = (A[1]*B[2] - A[2]*B[1], A[2]*B[0] - A[0]*B[2], A[0]*B[1] - A[1]*B[0]) return C#################################################### Returns the normalized vector of A ####################################################def getNormalized(A): return [A[0]/magnitude(A),A[1]/magnitude(A),A[2]/magnitude(A)]########################################################## Returns the area of a triange given 3d points ##########################################################def triarea(point1, point2, point3): AB = (point1[0]-point2[0],point1[1]-point2[1],point1[2]-point2[2]) AC = (point3[0]-point2[0],point3[1]-point2[1],point3[2]-point2[2]) cross = crossproduct(AB,AC) #print cross return 0.5*magnitude(cross)############################################## Return (v0,v1,v2) of a given face ############################################## def getVerticesOfFace(face): ## gather the translations of the vertices that make up the tri face_vertex_coords = cmds.xform( face, query=True, worldSpace=True, translation=True) #create 3d points v0 = (face_vertex_coords[0],face_vertex_coords[1],face_vertex_coords[2]) v1 = (face_vertex_coords[3],face_vertex_coords[4],face_vertex_coords[5]) v2 = (face_vertex_coords[6],face_vertex_coords[7],face_vertex_coords[8]) return (v0,v1,v2)################################### Calculate Surface Area ###################################def getMeshSurfaceArea(obj): cmds.polyTriangulate(obj) cmds.select(obj, r=True) numFaces = cmds.polyEvaluate(f=True) surface_area = 0 for i in range(0, numFaces): #get the area of the triangle defined by the 3 vertices vertices = getVerticesOfFace(obj+'.f['+str(i)+']') tri_area = triarea(vertices[0],vertices[1],vertices[2]) surface_area += tri_area return surface_area########################################################## Calculate How Far a 3-D Point is From Da Camera ##########################################################def getDistanceFromCamera(camera,point): cam_pos = cmds.xform(camera, q=True, t=True) #print cam_pos distance = sqrt((cam_pos[0]-point[0])**2+(cam_pos[1]-point[1])**2+(cam_pos[2]-point[2])**2) #print distance return distance########### Screen coord stuffs ################def getWorldToScreenMatrix(camera): v = cmds.getAttr(camera+'.worldInverseMatrix') m = [v[0], v[1], v[2], v[3], v[4], v[5], v[6], v[7], v[8], v[9], v[10], v[11], v[12], v[13], v[14], v[15]] return m#IMPORTANT! invmatrix should be a list of size 16def screenSpaceMultiply(vector, invmatrix): mayavector = OpenMaya.MVector(vector[0],vector[1],vector[2]) mayamatrix = OpenMaya.MMatrix() OpenMaya.MScriptUtil.createMatrixFromList(invmatrix,mayamatrix) #for j in range(0,4): # print (mayamatrix(j,0),mayamatrix(j,1),mayamatrix(j,2),mayamatrix(j,3)) #print (fixit1,fixit2,fixit3,fixit4) out = mayavector*mayamatrix #print (out[0], out[1], out[2]) return (out[0]+mayamatrix(3,0), out[1]+mayamatrix(3,1), out[2]+mayamatrix(3,2))#This will give the screen coordinates in "normalized" form. The output values for x and y will be between 0 and 1def getScreenCoords(worldpos, camera): global active_cam invmat = getWorldToScreenMatrix(camera) ptvecs = screenSpaceMultiply(worldpos,invmat) #hfv is in degrees hfv = cmds.camera(active_cam, q=True, hfv=True) #vfv is in degrees vfv = cmds.camera(active_cam, q=True, vfv=True) xrange = tan(0.017453293*hfv/2) yrange = tan(0.017453293*(hfv+vfv)/4) x = (ptvecs[0]/(-ptvecs[2]))/xrange/2.0+0.5 y = 1-((ptvecs[1]/(-ptvecs[2]))/yrange/2.0+0.5) return (x,y)########################## OBTAIN SCENE OBJECTS ######################################################################################## Returns a list of mesh objects in scene ####################################################def getMeshObjects(): #### Create a list of the mesh objects in the scene #### returnMeshObjs = cmds.ls(typ="mesh") ##And clear the active selection to keep things tipy cmds.select(clear=True) return returnMeshObjs#################################################### Returns a list of mesh objects in scene ####################################################def getLightObjects(): #### Create a list of the mesh objects in the scene #### returnLightObjs = cmds.ls(typ="light") ##And clear the active selection to keep things tipy cmds.select(clear=True) return returnLightObjsdef getActiveCam(): panel = cmds.getPanel(wf=True) models = cmds.getPanel( type='modelPanel' ) is_model = False for model in models: if panel == model: is_model = True if is_model: cam = cmds.modelPanel(panel, cam=True, q=True) print cam return cam else: print 'The active panel is not a modeling panel.'################### RENDER IMAGES ##################################### def renderScene(): global window_name cmds.RenderIntoNewWindow() #cmds.setFocus(window_name) #cmds.showWindow(window_name) ##Set render out type to PNG (that is what the 32 means) mel.eval("setAttr defaultRenderGlobals.outf 32") ##No idea what this does, but I need to add it mel.eval("setAttr defaultRenderGlobals.imfkey -type \"string\" \"\"") ##Render out the image based on the current render layer view ##WARNING!!! I am using a direct path, because I cannot get the local path as Maya imports it to its own special folders global directory mel.eval("renderWindowSaveImageCallback \"renderView\" \""+directory+"render.png\" \"PNG\"") ##Set the render out type back to iff mel.eval("setAttr defaultRenderGlobals.outf 7") return directory+"render.png"############################################### Create Flat Color Render #############################################def renderColorReference(): lights = getLightObjects() light_values = {} for light in lights: light_value = cmds.getAttr(light+".intensity") light_values[light]=light_value cmds.setAttr(light+".intensity",0) ##Create ambient light ambLight = cmds.ambientLight(rgb=[1, 1, 1], i=1) ##Set the ambient shade to zero, because the default makes it somewhat a point light cmds.setAttr(ambLight+".ambientShade", 0) cmds.RenderIntoNewWindow() ##Set render out type to PNG (that is what the 32 means) mel.eval("setAttr defaultRenderGlobals.outf 32") ##No idea what this does, but I need to add it mel.eval("setAttr defaultRenderGlobals.imfkey -type \"string\" \"\"") ##Render out the image based on the current render layer view ##WARNING!!! I am using a direct path, because I cannot get the local path as Maya imports it to its own special folders global directory mel.eval("renderWindowSaveImageCallback \"renderView\" \""+directory+"colorRef.png\" \"PNG\"") ##Set the render out type back to iff mel.eval("setAttr defaultRenderGlobals.outf 7") ##Replaces the current selection with the pointLight as a selected object cmds.select(ambLight,replace=True) cmds.delete() cmds.select(clear=True) for light in lights: light_value = light_values[light] cmds.setAttr(light+".intensity",light_value) return directory+"colorRef.png"################################################################ Create a file texture, given an image file and name ################################################################def createFileTexture(filename, name): texture = cmds.shadingNode('file', at=True, n=name) cmds.setAttr(texture+'.fileTextureName', filename, type='string') return texture########################### BILLBOARDS #################################################################### Create Billboards ##############################def createBillboards(selectedObjs,number_of_strokes,size_of_brush,layer_name): global render_lod0_str global render_lod1_str global render_lod2_str global active_cam ## Create billboards layers billboardRenderLayerLOD0 = cmds.createRenderLayer(name=layer_name+render_lod0_str,empty=True) billboardDisplayLayerLOD0 = cmds.createDisplayLayer(name=layer_name+"DisplayLayerLOD0",empty=True) billboardRenderLayerLOD1 = cmds.createRenderLayer(name=layer_name+render_lod1_str,empty=True) billboardDisplayLayerLOD1 = cmds.createDisplayLayer(name=layer_name+"DisplayLayerLOD1",empty=True) billboardRenderLayerLOD2 = cmds.createRenderLayer(name=layer_name+render_lod2_str,empty=True) billboardDisplayLayerLOD2 = cmds.createDisplayLayer(name=layer_name+"DisplayLayerLOD2",empty=True) ## iterate through the selected objects firstplane = cmds.polyPlane(w=10, h=10, sx=1, sy=1, ax=[0, 1, 0], cuv=2, ch=1) global brush_size uScale = brush_size cmds.scale(uScale, uScale, uScale, firstplane, r=True) billboardArea = (10*uScale)*(10*uScale) global image_filename brushtexture = createFileTexture(image_filename, 'brushTexture') tot_faces = 0 for obj in selectedObjs: cmds.select(obj, r=True) tot_faces += int(cmds.polyEvaluate(f=True)) tot_faces *= 2.0 print 'there are '+str(tot_faces)+' to be evaluated.' cmds.text(menu_txt_field, l='creating billboards for '+str(tot_faces)+' faces. please wait ...', w=max_width-25, e=True) cmds.progressBar('sobel_progress', max=tot_faces, e=True) start_time = time.time() #billboards = [] tufts = [] iterated_face = 0 update_amt = 20 for obj in selectedObjs: objSurfaceArea = getMeshSurfaceArea(obj) ## triangulate each of the selected objects cmds.polyTriangulate(obj) ## select each of the objects in turn and evaluate the number of faces cmds.select(obj, r=True) cmds.polyGeoSampler(abl = "overwrite", cbl = "overwrite", su=True, cdo=True, ids=True, sf=1) numFaces = cmds.polyEvaluate(f=True) #print numFaces ## iterate through the faces planeList = list() for i in range(0, numFaces): if iterated_face % update_amt == 0: curr_time = time.time() curr_elapsed = curr_time - start_time curr_secs = int(curr_elapsed % 60) curr_mins = int(curr_elapsed / 60) cmds.text(menu_txt_field, l='creating tuft [~'+padFrame(iterated_face, 2)+'\~'+padFrame(tot_faces, 2)+']. wait time thus far '+padFrame(curr_mins, 2)+':'+padFrame(curr_secs, 2)+' ...', w=max_width-25, e=True) cmds.progressBar('sobel_progress', s=update_amt, e=True) iterated_face += 1 ## gather the translations of the vertices that make up the tri trans_vals = cmds.xform( obj+'.f['+str(i)+']', q=True, ws=True, t=True) cmds.select(obj, r=True) #cmds.select('directionalLight1') cmds.select(obj+'.f['+str(i)+']', r=True) vtxString = cmds.polyInfo(fv=True) #print vtxString[0] vtx = vtxString[0].split() cmds.select(obj+'.vtx['+vtx[2]+']', r=True) normal_at_vert = cmds.polyNormalPerVertex( query=True, xyz=True ) #print color_vals_perVert #color_vals_perVert = cmds.polyColorPerVertex(a=True, g=True, b=True, q=True) #print color_vals_perVert ## TO DO ... evaluate the points to find the face center x_loc = (trans_vals[0]+trans_vals[3]+trans_vals[6])/3.0 y_loc = (trans_vals[1]+trans_vals[4]+trans_vals[7])/3.0 z_loc = (trans_vals[2]+trans_vals[5]+trans_vals[8])/3.0 #print 'centroid tri_['+str(i)+']('+str(x_loc)+', '+str(y_loc)+', '+str(z_loc)+')' ##uScale = sqrt(triarea((trans_vals[0],trans_vals[1],trans_vals[2]),(trans_vals[3],trans_vals[4],trans_vals[5]),(trans_vals[6],trans_vals[7],trans_vals[8])))/6 ## global num_strokes## density = 0.01## desired = density*objSurfaceArea## numBillboards = (triarea((trans_vals[0],trans_vals[1],trans_vals[2]),(trans_vals[3],trans_vals[4],trans_vals[5]),(trans_vals[6],trans_vals[7],trans_vals[8]))/objSurfaceArea)*desired faceArea = (triarea((trans_vals[0],trans_vals[1],trans_vals[2]),(trans_vals[3],trans_vals[4],trans_vals[5]),(trans_vals[6],trans_vals[7],trans_vals[8]))) global stroke_density numBillboardsRough = (faceArea/billboardArea)*stroke_density ##((triarea((trans_vals[0],trans_vals[1],trans_vals[2]),(trans_vals[3],trans_vals[4],trans_vals[5]),(trans_vals[6],trans_vals[7],trans_vals[8])))/objSurfaceArea)*stroke_density #print stroke_density numBillboards = int(numBillboardsRough) if random.uniform(0,1) <= numBillboardsRough-numBillboards: numBillboards = numBillboards+1 if(numBillboards>=1): for n in range(0,numBillboards): #plane = cmds.instance(firstplane) #planeList.append(plane[0]) #cmds.scale(uScale, uScale, uScale, plane, r=True) #cmds.select(plane, r=True) tuft = Tuft(firstplane, brushtexture, obj+'.f['+str(i)+']', (1, 1, 1), planeList, (billboardRenderLayerLOD0,billboardRenderLayerLOD1,billboardRenderLayerLOD2), (billboardDisplayLayerLOD0,billboardDisplayLayerLOD1,billboardDisplayLayerLOD2)) tuft.orient(active_cam,(0,1,0)) tufts.append(tuft) if(i==0): tuft = Tuft(firstplane, brushtexture, obj+'.f['+str(i)+']', (1, 1, 1), planeList, (billboardRenderLayerLOD0,billboardRenderLayerLOD1,billboardRenderLayerLOD2), (billboardDisplayLayerLOD0,billboardDisplayLayerLOD1,billboardDisplayLayerLOD2)) tuft.orient(active_cam,(0,1,0)) tufts.append(tuft) #print planeList plane_grp = cmds.group(planeList) cmds.rename(plane_grp, obj+'_rep_planes') cmds.pointConstraint(obj,obj+'_rep_planes',mo=True) faceNorms = cmds.polyInfo(fn=True) cmds.delete(firstplane) cmds.text(menu_txt_field, l='tufts created. preparing the scene for render.', w=max_width-25, e=True) ##Create ambient light ambLight = cmds.ambientLight(rgb=[1, 1, 1], i=1) ##Set the ambient shade to zero, because the default makes it somewhat a point light cmds.setAttr(ambLight+".ambientShade", 0) ## Select the light cmds.select(ambLight,r=True) cmds.editDisplayLayerMembers(billboardDisplayLayerLOD0,ambLight,noRecurse=True) cmds.editRenderLayerMembers(billboardRenderLayerLOD0,ambLight,noRecurse=True) cmds.setAttr(layer_name+"DisplayLayerLOD0"+".visibility", 0) cmds.setAttr(layer_name+render_lod0_str+".renderable", 0) cmds.editDisplayLayerMembers(billboardDisplayLayerLOD1,ambLight,noRecurse=True) cmds.editRenderLayerMembers(billboardRenderLayerLOD1,ambLight,noRecurse=True) cmds.setAttr(layer_name+"DisplayLayerLOD1"+".visibility", 0) cmds.setAttr(layer_name+render_lod1_str+".renderable", 0) cmds.editDisplayLayerMembers(billboardDisplayLayerLOD2,ambLight,noRecurse=True) cmds.editRenderLayerMembers(billboardRenderLayerLOD2,ambLight,noRecurse=True) cmds.setAttr(layer_name+"DisplayLayerLOD2"+".visibility", 0) cmds.setAttr(layer_name+render_lod2_str+".renderable", 0) ## Set the masterayer to be the active render layer (for whatever reason referred internally as defaultRenderLayer) cmds.editRenderLayerGlobals( currentRenderLayer='defaultRenderLayer') cmds.text(menu_txt_field, l='scene prepared. render at will ...', w=max_width-25, e=True) cmds.progressBar('sobel_progress', s=-tot_faces, e=True) return tuftsdef updateBillboardAttr(tuft_list,frame): ''' SO WHAT WE NEED TO DO HERE IS REPLACE THE GENERATION OF THE SOBEL IMAGES WITH A LOOKUP BASED ON FRAME ''' global directory (color_path, blurred_color, bw_path, grad_gx_pos_path, grad_gy_pos_path, grad_gx_neg_path, grad_gy_neg_path) = checkRefImages(active_cam, frame) imgGxPlus = Image.open(grad_gx_pos_path) imgGyPlus = Image.open(grad_gy_pos_path) imgGxMinus = Image.open(grad_gx_neg_path) imgGyMinus = Image.open(grad_gy_neg_path) (w, h) = imgGxPlus.size GxvaluesPlus = imgGxPlus.load() GyvaluesPlus = imgGyPlus.load() GxvaluesMinus = imgGxMinus.load() GyvaluesMinus = imgGyMinus.load() global directory frame_num = padFrame(int(frame), 4) colorimage = Image.open(color_path) colorValues = colorimage.load() blurimage = Image.open(blurred_color) blurredValues = blurimage.load() #realColorimage = Image.open(color_path) #realColorValues = realColorimage.load() #i = 1 for tuft in tuft_list: #print "Updating "+str(i)+" of "+str(len(tuft_list)) #i=i+1 positionworld = tuft.pos #print positionworld #get that position in normalized screen space normscreenpos = getScreenCoords(positionworld, active_cam) #print normscreenpos iIndex = int(max(0,min(round(normscreenpos[0]*w,0),w-1))) jIndex = int(max(0,min(round(normscreenpos[1]*h,0),h-1))) #color = (colorValues[iIndex,jIndex][0]/255.0,colorValues[iIndex,jIndex][1]/255.0,colorValues[iIndex,jIndex][2]/255.0) color = (colorValues[iIndex,jIndex][0]/255.0,colorValues[iIndex,jIndex][1]/255.0,colorValues[iIndex,jIndex][2]/255.0)## if (abs(magnitude(color)-magnitude(real_color)) > 40):## billboard.changeVisibility(0)## else:## billboard.changeVisibility(1) #tuft.changeColor(color) tuft.colorImgs(active_cam,(colorValues,blurredValues),h,w) Gx = float(GxvaluesPlus[iIndex,jIndex][0]-GxvaluesMinus[iIndex,jIndex][0]) Gy = float(GyvaluesPlus[iIndex,jIndex][0]-GyvaluesMinus[iIndex,jIndex][0]) #if (Gx==0 and Gy==0): # Gx = random.uniform(-1,1) # Gy = 1+random.uniform(-1,1) #angle = atan2(Gy,Gx) #billboard.orientAngle(active_cam,angle+1.5707963) tuft.orientImgs(active_cam,(GxvaluesPlus,GyvaluesPlus,GxvaluesMinus,GyvaluesMinus),h,w) # How far from Da Camera? distancefromcam = getDistanceFromCamera(active_cam,positionworld) global brush_size gradientvalue = sqrt((Gx/255)**2+(Gy/255)**2) desiredLOD = getDesiredLOD(distancefromcam,gradientvalue) #print distancefromcam #print "gradient: "+str(gradientvalue) #print desiredLOD #print round(desiredLOD,0) scale = brush_size*(distancefromcam)/100 #print scale #assert 1==0 tuft.changeScale((scale,scale,scale)) tuft.setLOD(desiredLOD) tuft.updatePos()def getDesiredLOD(distfromCamera,gradientvalue): w1 = 0.7 w2 = 0.3 number_of_levels = 2 return number_of_levels*sqrt(sqrt((w1*sqrt(sqrt(sqrt(gradientvalue)))+w2*sqrt(1/(distfromCamera+1)))/(w1+w2)))########################################################### ## Checks if Files Exist. If Not, Makes Them. #############################################################def checkRefImages(camera, frame): global directory frame_num = padFrame(int(frame), 4) color_path = directory+camera+'/'+str(frame_num)+'/color_render.png' blurred_color_path = directory+camera+'/'+str(frame_num)+'/color_render_blur.png' bw_path = directory+camera+'/'+str(frame_num)+'/color_render_bw.png' grad_gx_pos_path = directory+camera+'/'+str(frame_num)+'/gradients/sobel_gx_pos.png' grad_gy_pos_path = directory+camera+'/'+str(frame_num)+'/gradients/sobel_gy_pos.png' grad_gx_neg_path = directory+camera+'/'+str(frame_num)+'/gradients/sobel_gx_neg.png' grad_gy_neg_path = directory+camera+'/'+str(frame_num)+'/gradients/sobel_gy_neg.png' ## if the color image for frame DNE -> render the entire collection if not (os.path.isfile(color_path) and (os.path.isfile(blurred_color_path))): print 'color image does NOT exist for frame '+str(int(frame))+'. Building necessary reference images ...' renderRefImages(frame, frame+1, False) else: color_img = Image.open(color_path) (w,h) = color_img.size ## if the bw image for frame DNE -> run the sobel algorithm if not os.path.isfile(bw_path): print 'bw image does NOT exist for frame '+str(int(frame))+'. Building necessary reference images ...' cmds.progressBar('sobel_progress', max=((w-2)*(h-2)), e=True) SobelAlgorithm.run(color_path) cmds.progressBar('sobel_progress', s=-((w-2)*(h-2)), e=True) else: print 'BOTH the color and bw images exist. MUST CHECK FOR SOBEL' gx_pos_ex = os.path.isfile(grad_gx_pos_path) gy_pos_ex = os.path.isfile(grad_gy_pos_path) gx_neg_ex = os.path.isfile(grad_gx_neg_path) gy_neg_ex = os.path.isfile(grad_gy_neg_path) if not(gx_pos_ex and gy_pos_ex and gx_neg_ex and gy_neg_ex): SobelAlgorithm.run(color_path) return (color_path, blurred_color_path, bw_path, grad_gx_pos_path, grad_gy_pos_path, grad_gx_neg_path, grad_gy_neg_path)## this method generates the reference images needed for orientation (color, bw, sobel_x/y_pos/neg)## from start frame to end frame (if batch is set)def renderRefImages(start, end, batch): rtn = [] global active_cam frame = start ## set the current time to the given frame and renders it cmds.currentTime( frame, e=True ) cmds.RenderIntoNewWindow() mel.eval("setAttr defaultRenderGlobals.outf 32") ##No idea what this does, but I need to add it mel.eval("setAttr defaultRenderGlobals.imfkey -type \"string\" \"\"") global directory #print directory ''' do something with this frame_number too ''' frame_num = padFrame(int(frame), 4) save_str = directory+active_cam+'/'+str(frame_num)+'/' #print save_str #save_str = directory+str(frame_num)+'/' ## if the given directory does not exist, create all necessary folders if not os.path.exists(save_str): os.makedirs(save_str) print save_str mel.eval("renderWindowSaveImageCallback \"renderView\" \""+save_str+"color_render.png\" \"PNG\"") #mel.eval("renderWindowSaveImageCallback \"renderWindowPanel1\" \""+save_str+"color_render.png\" \"PNG\"") rtn.append(save_str+'color_render.png') img = Image.open(save_str+"color_render.png") ## determine the width and height of the resulting images (w, h) (w, h) = img.size if batch: cmds.progressBar('sobel_progress', max=(end-start)*((w-2)*(h-2)), e=True) else: cmds.progressBar('sobel_progress', max=((w-2)*(h-2)), e=True) for i in range(int(start), int(end)): frame = i ## since we render the first image to determine w and h, we dont need to re-render the start frame if i != start: cmds.currentTime( frame, e=True ) cmds.RenderIntoNewWindow() cmds.setFocus() ##Set render out type to PNG (that is what the 32 means) mel.eval("setAttr defaultRenderGlobals.outf 32") ##No idea what this does, but I need to add it mel.eval("setAttr defaultRenderGlobals.imfkey -type \"string\" \"\"") ##Render out the image based on the current render layer view ##WARNING!!! I am using a direct path, because I cannot get the local path as Maya imports it to its own special folders ''' do something with this frame_number too ''' frame_num = padFrame(int(frame), 4) save_str = directory+active_cam+'/'+str(frame_num)+'/' if not os.path.exists(save_str): os.makedirs(save_str) print save_str mel.eval("renderWindowSaveImageCallback \"renderView\" \""+save_str+"color_render.png\" \"PNG\"") #mel.eval("renderWindowSaveImageCallback \"renderWindowPanel\" \""+save_str+"color_render.png\" \"PNG\"") ##Set the render out type back to iff mel.eval("setAttr defaultRenderGlobals.outf 7") ## open the color render and begin generating the img = Image.open(save_str+"color_render.png") (w, h) = img.size blurred = img.filter(ImageFilter.BLUR) for blur in range(0,9): blurred = blurred.filter(ImageFilter.BLUR) blurred.save(save_str+"color_render_blur.png") sobel_imgs = SobelAlgorithm.run(save_str+"color_render.png") rtn.append(sobel_imgs) if batch: cmds.progressBar('sobel_progress', s=-(end-start)*((w-2)*(h-2)), e=True) else: cmds.progressBar('sobel_progress', s=-((w-2)*(h-2)), e=True) return rtn######################################## ##### render image sequence ##### ########################################def composite(im1_filename,im2_filename,im3_filename,result_filename): im1 = Image.open(im1_filename) if im1.mode != "RGBA": im1 = im1.convert("RGBA") im2 = Image.open(im2_filename) if im2.mode != "RGBA": im2 = im2.convert("RGBA") im3 = Image.open(im3_filename) if im3.mode != "RGBA": im3 = im3.convert("RGBA") im1.paste(im2,(0,0),im2) im1.paste(im3,(0,0),im3) print 'trying to save to ->> '+result_filename im1.save(result_filename,"PNG")def renderImgSeq(filename, camera, start_frame, end_frame): global render_lyr_base global render_lod0_str global render_lod1_str global render_lod2_str global active_cam global directory global renders_ext global render_path print 'render path is currently ->> '+render_path disp_txt = '' render = False if len(filename) > 4: if start_frame <= end_frame: disp_txt = 'rendering image sequence from frame '+str(start_frame)+' -> '+str(end_frame)+' using camera \''+str(camera)+'\'.' render = True else: disp_txt = 'the start frame must be smaller than or equal to the end frame.' else: disp_txt = 'please specify a valid filename before attempting to render.' print disp_txt cmds.text(menu_txt_field, l=disp_txt, e=True, w=max_width-25) if render: cmds.setAttr("defaultRenderGlobals.imageFormat", 32) mel.eval("setProject \""+directory+"\";") mel.eval("unifiedRenderGlobalsWindow;") mel.eval("createRenderOptions (\"rgOptionSoftwareFrame\");") mel.eval("mayaSoftwarePremultiplyCtrlChanged;") mel.eval("control -edit -enable true premultiplyThresholdCtrl;") mel.eval("updateMayaSoftwarePremultiplyCtrl;") mel.eval("control -edit -enable true premultiplyThresholdCtrl;") mel.eval('setAttr "defaultRenderGlobals.compositeThreshold" 0.001') mel.eval("window -e -vis 0 unifiedRenderGlobalsWindow;") global base_tufts tot_frames = ((end_frame+1)-start_frame) cmds.progressBar('sobel_progress', maxValue=tot_frames*3, e=True) frame_num = 1 render_dir = directory+renders_ext print render_dir layers_dir = render_dir+'/'+layers_ext composite_dir = render_dir+'/'+composite_ext if not os.path.exists(layers_dir): os.makedirs(layers_dir) if not os.path.exists(composite_dir): os.makedirs(composite_dir) for frame in range(start_frame, end_frame+1): cmds.currentTime( frame, e=True ) global base_tufts updateBillboardAttr(base_tufts,frame) cmds.setAttr(render_lyr_base+"DisplayLayerLOD0"+".visibility", 1) cmds.setAttr(render_lyr_base+"DisplayLayerLOD1"+".visibility", 1) cmds.setAttr(render_lyr_base+"DisplayLayerLOD2"+".visibility", 1) frame_str = padFrame(frame, 4) frame_dir = layers_dir+'/'+frame_str print 'frame dir ->> '+frame_dir if not os.path.exists(frame_dir): os.makedirs(frame_dir) #updateBillboardAttr(base_tufts,frame) cmds.text(menu_txt_field, l='render LOD [1/3] from frame ['+str(frame_num)+'/'+str(tot_frames)+']', e=True, w=max_width-25) #mel.eval('control -edit -enable false premultiplyThresholdCtrl') lod0_img = cmds.render(active_cam, l=render_lyr_base+render_lod0_str) base, ext = os.path.splitext(lod0_img) #print 'saving to ->> '+render_dir+'/'+lod0_file+ext file_utils.copy(lod0_img, frame_dir+'/'+lod0_file+ext) cmds.progressBar('sobel_progress', s=1, e=True) cmds.text(menu_txt_field, l='render LOD [2/3] from frame ['+str(frame_num)+'/'+str(tot_frames)+']', e=True, w=max_width-25) #mel.eval('control -edit -enable true premultiplyThresholdCtrl') lod1_img = cmds.render(active_cam, l=render_lyr_base+render_lod1_str) file_utils.copy(lod1_img, frame_dir+'/'+lod1_file+ext) cmds.progressBar('sobel_progress', s=1, e=True) cmds.text(menu_txt_field, l='render LOD [3/3] from frame ['+str(frame_num)+'/'+str(tot_frames)+']', e=True, w=max_width-25) #mel.eval('control -edit -enable true premultiplyThresholdCtrl') #mel.eval('setAttr "defaultRenderGlobals.compositeThreshold" 0.5') lod2_img = cmds.render(active_cam, l=render_lyr_base+render_lod2_str) file_utils.copy(lod2_img, frame_dir+'/'+lod2_file+ext) cmds.progressBar('sobel_progress', s=1, e=True) fn, ext = os.path.splitext(render_path) print 'saving composite to '+composite_dir+'/'+fn+'_'+frame_str+'.png' composite(lod0_img, lod1_img, lod2_img, composite_dir+'/'+fn+'_'+frame_str+'.png') cmds.setAttr(render_lyr_base+"DisplayLayerLOD0"+".visibility", 0) cmds.setAttr(render_lyr_base+"DisplayLayerLOD1"+".visibility", 0) cmds.setAttr(render_lyr_base+"DisplayLayerLOD2"+".visibility", 0) frame_num += 1 file_utils.rmtree(directory+'tmp') file_utils.rmtree(directory+render_lyr_base+render_lod0_str) file_utils.rmtree(directory+render_lyr_base+render_lod1_str) file_utils.rmtree(directory+render_lyr_base+render_lod2_str) cmds.editRenderLayerGlobals( currentRenderLayer='defaultRenderLayer') cmds.text(menu_txt_field, l='rendering completed. composites saved to '+composite_dir+'.', e=True, w=max_width-25) cmds.progressBar('sobel_progress', s=-tot_frames*3, e=True)########################################################### ## Creates a list of the objects in the scene meshObjs, #### and creates brush billboards for the scene. NO LONGER #### DOES ANY ORIENTATION OR COLOR SETTING, THAT IS FOR #### THE RENDER FRAMES #############################################################def prepScene(): meshObjs = getMeshObjects() global stroke_density global brush_size global base_tufts global render_lyr_base base_tufts = createBillboards(meshObjs,stroke_density,brush_size,render_lyr_base) cmds.button('render_btn', en=True, e=True) frame = cmds.currentTime(q=True) renderFrame(frame)def renderFrame(frame): #renderScene() #renderColorReference() global base_tufts updateBillboardAttr(base_tufts,frame) ############################## Color methods ########################################################################################### _____ _ _____ _____ ______ _____ #### / ____| | /\ / ____|/ ____| ____|/ ____| #### | | | | / \ | (___ | (___ | |__ | (___ #### | | | | / /\ \ \___ \ \___ \| __| \___ \ #### | |____| |____ / ____ \ ____) |____) | |____ ____) | #### \_____|______/_/ \_\_____/|_____/|______|_____/ #### ############################################################# class Tuft:## def __init__(self):## self.l0_billboards = []## self.l1_billboards = []## self.l2_billboards = []#### def __init__(self, lod0_billboards, lod1_billboards, lod2_billboards):## self.l0_billboards = lod0_billboards## self.l1_billboards = lod1_billboards## self.l2_billboards = lod2_billboards def __init__(self, plane, texture, face, color, planeList, billboardRenderLayerLIST, billboardDisplayLayerLIST): self.face = face self.l0_billboards = [] self.l1_billboards = [] self.l2_billboards = [] r0 = random.random() r1 = random.random() r2 = random.random() barycoords = [r0/(r0+r1+r2),r1/(r0+r1+r2),r2/(r0+r1+r2)] self.barycoords = barycoords #Add one LOD 0 board plane1 = cmds.instance(plane) planeList.append(plane1[0]) new_r0 = random.random() new_r1 = random.random() new_r2 = random.random() jitteredcoords = [new_r0/(new_r0+new_r1+new_r2),new_r1/(new_r0+new_r1+new_r2),new_r2/(new_r0+new_r1+new_r2)] cmds.editDisplayLayerMembers(billboardDisplayLayerLIST[0],plane1,noRecurse=True) cmds.editRenderLayerMembers(billboardRenderLayerLIST[0],plane1,noRecurse=True) self.l0_billboards.append(Billboard("lod0_0",plane1,texture,face,(1,1,1))) #Add two LOD 1 boards for i in range(0,2): plane2 = cmds.instance(plane) planeList.append(plane2[0]) new_r0 = random.random() new_r1 = random.random() new_r2 = random.random() jitteredcoords = [new_r0/(new_r0+new_r1+new_r2),new_r1/(new_r0+new_r1+new_r2),new_r2/(new_r0+new_r1+new_r2)] cmds.editDisplayLayerMembers(billboardDisplayLayerLIST[1],plane2,noRecurse=True) cmds.editRenderLayerMembers(billboardRenderLayerLIST[1],plane2,noRecurse=True) self.l1_billboards.append(Billboard("lod1_1",plane2,texture,face,(1,0,0))) #Add four LOD 2 boards for i in range(0,4): plane4 = cmds.instance(plane) planeList.append(plane4[0]) new_r0 = random.random() new_r1 = random.random() new_r2 = random.random() jitteredcoords = [new_r0/(new_r0+new_r1+new_r2),new_r1/(new_r0+new_r1+new_r2),new_r2/(new_r0+new_r1+new_r2)] cmds.editDisplayLayerMembers(billboardDisplayLayerLIST[2],plane4,noRecurse=True) cmds.editRenderLayerMembers(billboardRenderLayerLIST[2],plane4,noRecurse=True) self.l2_billboards.append(Billboard("lod2_1",plane4,texture,face,(0,0,1))) self.updatePos() def getLod0Bills(self): return self.l0_billboards def getLod1Bills(self): return self.l1_billboards def getLod2Bills(self): return self.l2_billboards def setLOD(self,level_of_detail): for billboard in self.l0_billboards: billboard.setAlpha(1.0) if (level_of_detail <= 1) and (level_of_detail > 0): for billboard in self.l1_billboards: billboard.setAlpha(level_of_detail) for billboard in self.l2_billboards: billboard.setAlpha(0.0) if (level_of_detail <= 2) and (level_of_detail > 1): for billboard in self.l1_billboards: billboard.setAlpha(1.0) for billboard in self.l2_billboards: billboard.setAlpha(level_of_detail - 1.0) def orient(self,camera,up): for billboard in self.l0_billboards: billboard.orient(camera,up) for billboard in self.l1_billboards: billboard.orient(camera,up) for billboard in self.l2_billboards: billboard.orient(camera,up) def changeScale(self, scale): for billboard in self.l0_billboards: billboard.changeScale((2.5*scale[0],2.5*scale[1],2.5*scale[2])) for billboard in self.l1_billboards: billboard.changeScale(scale) for billboard in self.l2_billboards: billboard.changeScale((scale[0]/2.0,scale[1]/2.0,scale[2]/2.0)) def orientImgs(self,camera,imageList,h,w): for billboard in self.l0_billboards: billboard.orientImgs(camera,imageList,h,w) for billboard in self.l1_billboards: billboard.orientImgs(camera,imageList,h,w) for billboard in self.l2_billboards: billboard.orientImgs(camera,imageList,h,w) def colorImgs(self,camera,colorPixelRefs,h,w): for billboard in self.l0_billboards: billboard.colorImgs(camera,colorPixelRefs[1],h,w) for billboard in self.l1_billboards: billboard.colorImgs(camera,colorPixelRefs[1],h,w) for billboard in self.l2_billboards: billboard.colorImgs(camera,colorPixelRefs[1],h,w) def changeColor(self,color): for billboard in self.l0_billboards: billboard.changeColor(color) for billboard in self.l1_billboards: billboard.changeColor(color) for billboard in self.l2_billboards: billboard.changeColor(color) def updatePos(self): verts = getVerticesOfFace(self.face) x = verts[0][0]*self.barycoords[0]+verts[1][0]*self.barycoords[1]+verts[2][0]*self.barycoords[2] y = verts[0][1]*self.barycoords[0]+verts[1][1]*self.barycoords[1]+verts[2][1]*self.barycoords[2] z = verts[0][2]*self.barycoords[0]+verts[1][2]*self.barycoords[1]+verts[2][2]*self.barycoords[2] self.pos = (x,y,z) for billboard in self.l0_billboards: billboard.updatePos() for billboard in self.l1_billboards: billboard.updatePos() for billboard in self.l2_billboards: billboard.updatePos() class Billboard: def __init__(self, name, plane, texture, face, color): self.name = name self.face = face ### Compute random barycentric coordinates ### r0 = random.random() r1 = random.random() r2 = random.random() barycoords = [r0/(r0+r1+r2),r1/(r0+r1+r2),r2/(r0+r1+r2)] self.barycoords = barycoords self.plane1 = plane self.updatePos() cmds.select(self.plane1, r=True) sg = cmds.sets(renderable=True, noSurfaceShader=True, empty=True) lambert = cmds.shadingNode("lambert", asShader=True) self.alphaNode = cmds.shadingNode("multiplyDivide", asUtility=True) reverse1 = cmds.shadingNode("reverse", asUtility=True) reverse2 = cmds.shadingNode("reverse", asUtility=True) self.material = lambert cmds.setAttr(lambert+".color", color[0], color[1], color[2]) cmds.connectAttr(lambert+".outColor", sg+".surfaceShader") cmds.connectAttr(texture+".outColor",reverse1+".input") cmds.connectAttr(reverse1+".output",self.alphaNode+".input1") cmds.setAttr(self.alphaNode+".input2",1,1,1) cmds.connectAttr(self.alphaNode+".output",reverse2+".input") cmds.connectAttr(reverse2+".output",lambert+".transparency") cmds.sets(plane[0], edit=True, forceElement=sg) cmds.move(self.pos[0], self.pos[1], self.pos[2], plane) ## def __init__(self, name, plane, texture, face, color, coords):## self.name = name## self.face = face#### r0 = coords[0]## r1 = coords[0]## r2 = coords[0]## barycoords = [r0/(r0+r1+r2),r1/(r0+r1+r2),r2/(r0+r1+r2)]## self.barycoords = barycoords#### self.updatePos()#### self.plane1 = plane## cmds.select(self.plane1, r=True)## sg = cmds.sets(renderable=True, noSurfaceShader=True, empty=True)## lambert = cmds.shadingNode("lambert", asShader=True)## self.material = lambert## cmds.setAttr(lambert+".color", color[0], color[1], color[2])## cmds.connectAttr(lambert+".outColor", sg+".surfaceShader")## cmds.connectAttr(texture+".outColor",lambert+".transparency")## cmds.sets(plane[0], edit=True, forceElement=sg)## cmds.move(self.pos[0], self.pos[1], self.pos[2], plane) def changeColor(self, color): cmds.setAttr(self.material+".color", color[0], color[1], color[2]) def colorImgs(self,camera,colorPixelRef,h,w): positionworld = self.pos normscreenpos = getScreenCoords(positionworld, camera) iIndex = int(max(0,min(round(normscreenpos[0]*w,0),w-1))) jIndex = int(max(0,min(round(normscreenpos[1]*h,0),h-1))) color = colorPixelRef[iIndex,jIndex] self.changeColor((color[0]/255.0,color[1]/255.0,color[2]/255.0)) def setAlpha(self, alpha): cmds.setAttr(self.alphaNode+".input2",alpha,alpha,alpha)## def changeVisibility(self,num):## mel.eval("setAttr "+self.plane1[0]+".visibility num;") def changeScale(self, scale): cmds.scale(scale[0], scale[1], scale[2], self.plane1, r=True, a=True) def orient(self,camera,up): cmds.aimConstraint(camera, self.plane1, o=[0,0,0], w=1, aim=[0,1,0], u=[0,0,-1], wut="vector", wu=(up[0],up[1],up[2])) def orient2D(self,camera,Gx,Gy): cmds.aimConstraint(camera, self.plane1, o=[0,0,0], w=1, aim=[0,1,0], u=[0,0,-1], wut="objectrotation", wu=(Gx,Gy,0), wuo=camera) def orientAngle(self,camera,angle): cmds.aimConstraint(camera, self.plane1, o=[0,0,0], w=1, aim=[0,1,0], u=[0,0,-1], wut="objectrotation", wu=(cos(angle),sin(angle),0), wuo=camera) def orientImgs(self,camera,imageList,h,w): #for image in imageList: # print image## gx_plus_img = Image.open(imageList[0])## gy_plus_img = Image.open(imageList[1])## gx_minus_img = Image.open(imageList[2])## gy_minus_img = Image.open(imageList[3])## (w, h) = gx_plus_img.size## gx_plus_pix = gx_plus_img.load()## gy_plus_pix = gy_plus_img.load()## gx_minus_pix = gx_minus_img.load()## gy_minus_pix = gy_minus_img.load() gx_plus_pix = imageList[0] gy_plus_pix = imageList[1] gx_minus_pix = imageList[2] gy_minus_pix = imageList[3] positionworld = self.pos normscreenpos = getScreenCoords(positionworld, camera) iIndex = int(max(0,min(round(normscreenpos[0]*w,0),w-1))) jIndex = int(max(0,min(round(normscreenpos[1]*h,0),h-1))) gx = float(gx_plus_pix[iIndex,jIndex][0]-gx_minus_pix[iIndex,jIndex][0]) gy = float(gy_plus_pix[iIndex,jIndex][0]-gy_minus_pix[iIndex,jIndex][0]) if (gx==0 and gy==0): gx = random.uniform(-1,1) gy = 1+random.uniform(-1,1) angle = atan2(gy,gx) self.orientAngle(camera,angle+1.5707963) def updatePos(self): verts = getVerticesOfFace(self.face) x = verts[0][0]*self.barycoords[0]+verts[1][0]*self.barycoords[1]+verts[2][0]*self.barycoords[2] y = verts[0][1]*self.barycoords[0]+verts[1][1]*self.barycoords[1]+verts[2][1]*self.barycoords[2] z = verts[0][2]*self.barycoords[0]+verts[1][2]*self.barycoords[1]+verts[2][2]*self.barycoords[2] self.pos = (x,y,z) cmds.move(self.pos[0], self.pos[1], self.pos[2], self.plane1)class PainterlyGui: def __init__(self): global max_width global window_name window_layout = 'ui_layout' if (cmds.window(window_name, ex=True)): cmds.deleteUI(window_name) main = cmds.window(window_name, t='Painterly Rendering', s=False, mb=True, vis=True, rtf=True) cmds.columnLayout(cal="center", h=200) cmds.columnLayout(cal="center") cmds.separator(w=max_width, h=10) cmds.text(' PAINTING PARAMETERS ') cmds.separator(w=max_width, h=10) cmds.setParent( '..' ) self.buildDirectoryPanel() ## build the brush image panel self.buildBrushImgPanel() ## build the strokes panel self.buildStrokesPanel() self.buildColorPanel() self.buildCameraPanel() cmds.separator(w=max_width, h=10) cmds.text(' PRE-RENDER ') cmds.separator(w=max_width, h=10) ## build the panel in charge of building reference images self.buildReferencePanel() cmds.separator(w=max_width, h=10) cmds.text(' RENDER ') cmds.separator(w=max_width, h=10) cmds.setParent( '..' ) self.buildImgSeqPanel() self.buildMenuDisplay() self.buildExitPanel(window_name) def updateImgSequencePanel(): print 'updating img seq panel' def updateBrushImgPanel(file_name): cmds.text(menu_txt_field, l='to proceed, please begin prepping frames for render or build the billboards.', e=True) img = Image.open(file_name) (w, h) = img.size if (w > 200 or h > 200): print 'resizing '+file_name+' ...' base = os.path.basename(file_name) fn, ext = os.path.splitext(base) img = Image.open(file_name) img.thumbnail((200, 200), Image.ANTIALIAS) global thumbs_ext thumb_str = directory+thumbs_ext+fn+"_thumbnail.png" thumb_dir = os.path.dirname(thumb_str) if not os.path.exists(thumb_dir): os.makedirs(thumb_dir) #print thumb_str img.save(thumb_str) cmds.textField('brush_img_disp', tx=thumb_str, e=True) cmds.image('brush_img', i=thumb_str, e=True) else: cmds.textField('brush_img_disp', tx=file_name, e=True) cmds.image('brush_img', i=file_name, e=True) setBrushImage(file_name) cmds.button("prep_button", enable=True,e=True) def prepCurrFrame(): curr_time = cmds.currentTime(q=True) renderRefImages(curr_time, curr_time+1, False) def prepFrames(start, end): if start >= end: print 'please make sure the start frame is strictly smaller than the end frame.' else: print 'preping frames '+str(start)+' -to-> '+str(end) renderRefImages(start, end+1, True) def prepCurrFrame(): curr_time = cmds.currentTime(q=True) renderRefImages(curr_time, curr_time+1, False) def prepFrames(start, end): if start >= end: print 'please make sure the start frame is strictly smaller than the end frame.' else: print 'preping frames '+str(start)+' -to-> '+str(end) renderRefImages(start, end+1, True) def buildDirectoryPanel(self): cmds.rowLayout(nc=3, cw3=[73, 200, 75]) cmds.text('directory.', w=73) if len(directory) > 0: cmds.textField('dir_display', w=200, ed=False, tx=directory) global prep_frame_btn prep_frame_btn = True else: cmds.textField('dir_display', w=200, ed=False) cmds.button('load_dir_btn', l='set...', w=75, c="cmds.fileBrowserDialog(m=4, ft='directory', fc=setDirectory, an='select dir')") cmds.setParent( '..' ) def buildBrushImgPanel(self): cmds.rowLayout(nc=3, cw3=[73, 200, 75]) cmds.text('brush image.', w=73) cmds.textField('brush_img_disp', w=200, ed=False) cmds.button('brush_image_grp', l='load...', en=False, c="PainterlyGui.updateBrushImgPanel(cmds.fileDialog(dm='*.png; *.jpg; *.jpeg; *.tiff; *.tif; *.psd; *.iff; *.gif'))", w=75) cmds.setParent( '..' ) cmds.columnLayout(cal="center") cmds.image('brush_img', w=200, h=200, en=False) cmds.setParent( '..' ) def buildImgSeqPanel(self): cmds.text('save as an image sequence ...') cmds.separator(w=max_width, h=10) cmds.setParent( '..' ) #cmds.rowLayout(nc=2, cw2=[73, 100]) #cmds.text('padding.') #cmds.intField('padding_num', w=100, v=4, cc="setPaddingLength(cmds.intField('padding_num', v=True, q=True))") #cmds.setParent( '..' ) cmds.rowLayout(nc=3, cw3=[73, 200, 100]) cmds.text('img sequence.', w=73) cmds.textField('img_seq_filename', w=200, en=False) #cmds.button('img_seq_btn', l='save as...', w=75, c="cmds.fileBrowserDialog(m=1, fl='png, *.png;', ft='image', fc=setImgSequencePath, an='save as..')") cmds.button('img_seq_btn', l='save as...', w=75, c="setImgSeqPath(cmds.fileDialog(m=1, dm='"+getDirectory()+" *.png;', t='save as..'))") cmds.setParent( '..' ) cmds.rowLayout(nc=6, cw6=[73, 50, 30, 70, 50, 30]) cmds.text('from frame', w=73) cmds.intField('img_seq_start_field', w=50) cmds.button(l='^', c="cmds.intField('img_seq_start_field', v=cmds.currentTime(q=True), e=True)") cmds.text(' to frame', w=70) cmds.intField('img_seq_end_field', w=50) cmds.button(l='^', c="cmds.intField('img_seq_end_field', v=cmds.currentTime(q=True), e=True)") cmds.setParent( '..' ) global active_cam cmds.button('render_btn', l='render.', w=100, c="renderImgSeq(cmds.textField('img_seq_filename', tx=True, q=True), '"+active_cam+"', cmds.intField('img_seq_start_field', v=True, q=True), cmds.intField('img_seq_end_field', v=True, q=True))") cmds.setParent( '..' ) def buildStrokesPanel(self): cmds.separator(w=max_width, h=10) cmds.rowLayout(nc=3, cw3=[120, 100, 100]) cmds.text('Brush Stroke Density', w=120) cmds.floatField('stroke_density_field', v=5, w=100, min=0, max=50, cc="cmds.floatScrollBar('stroke_density_scroll', v=cmds.floatField('stroke_density_field', v=True, q=True), e=True)") cmds.floatScrollBar('stroke_density_scroll', value=5, step=0.1, max=50, largeStep=1, w=100, cc="cmds.floatField('stroke_density_field', v=cmds.floatScrollBar('stroke_density_scroll', v=True, q=True), e=True)") cmds.setParent( '..' ) cmds.rowLayout(nc=3, cw3=[120, 100, 100]) cmds.text('Base Stroke Size.', w=120) cmds.floatField('stroke_size_field', v=0.1, w=100, min=0, max=10, cc="cmds.floatScrollBar('stroke_size_scroll', v=cmds.floatField('stroke_size_field', v=True, q=True), e=True)") cmds.floatScrollBar('stroke_size_scroll', value=0.1, step=0.05, max=10, largeStep=0.1, w=100, cc="cmds.floatField('stroke_size_field', v=cmds.floatScrollBar('stroke_size_scroll', v=True, q=True), e=True)") cmds.setParent( '..' ) def buildCameraPanel(self): cmds.rowLayout(nc=2, cw2=[75, 100]) cmds.optionMenuGrp('cam_select', l='select camera.', cc="setActiveCam()") for cam in cmds.ls(ca=True): shape_index = int(cam.find('Shape')) shape_len = len('Shape') cam_len = len(cam) print shape_index prefix = cam[0:shape_index] suffix = cam[shape_index+shape_len:cam_len] print prefix + " ... " + suffix cmds.menuItem( label=prefix+suffix ) global build_cam cmds.optionMenuGrp('cam_select', v=build_cam, e=True) cmds.setParent( '..' ) def buildMenuDisplay(self): global menu_txt_field cmds.columnLayout() cmds.progressBar('sobel_progress', maxValue=100, w=max_width-25) cmds.setParent( '..' ) cmds.frameLayout('menu_disp_frame', cl=False, cll=True, l='command display') if len(directory) > 0: cmds.text(menu_txt_field, w=max_width-25, al="right", l="select a brush image or begin prepping the frames for render.") else: cmds.text(menu_txt_field, w=max_width-25, al="right", l="please enter a directory to begin.") cmds.setParent( '..' ) def buildExitPanel(self, window_name): cmds.separator(w=max_width, h=10) cmds.button( label='exit', command=('cmds.deleteUI(\"' + window_name + '\", wnd=True)'), w=100 ) cmds.setParent( '..' ) def buildReferencePanel(self): cmds.rowLayout(nc=2, cw2=[125, 100]) cmds.button("prep_button",label='build billboards', c='PainterlyGui.prePrep()', w=100, enable=False) cmds.setParent( '..' ) cmds.rowLayout(nc=3, cw3=[100, 100, 100]) if prep_frame_btn: cmds.button("prep_frame_button", label='prep current frame', c="PainterlyGui.prepCurrFrame()", w=100, en=True) cmds.button("prep_frames_button", label='prep frames', en=True , c="PainterlyGui.prepFrames(cmds.intField('prep_start', v=True, q=True), cmds.intField('prep_end', v=True, q=True))", w=100) cmds.button('brush_image_grp', en=True, e=True) else: cmds.button("prep_frame_button", label='prep current frame', c="PainterlyGui.prepCurrFrame()", w=100, en=False) cmds.button("prep_frames_button", label='prep frames', en=False , c="PainterlyGui.prepFrames(cmds.intField('prep_start', v=True, q=True), cmds.intField('prep_end', v=True, q=True))", w=100) cmds.rowLayout(nc=5, cw5=[30, 30, 15, 30, 30]) cmds.intField('prep_start', w=30) cmds.button(l='^', c="cmds.intField('prep_start', v=cmds.currentTime(q=True), e=True)") cmds.text('to', w=15) cmds.intField('prep_end', w=30) cmds.button(l='^', c="cmds.intField('prep_end', v=cmds.currentTime(q=True), e=True)") cmds.setParent( '..' ) cmds.setParent( '..' ) cmds.setParent( '..' ) def prePrep(): global stroke_density stroke_density = cmds.floatField('stroke_density_field', v=True, q=True) global brush_size brush_size = cmds.floatField('stroke_size_field', v=True, q=True) prepScene() def buildColorPanel(self): cmds.separator(w=325, h=10) cmds.rowLayout(nc=2, cw2=[125, 100]) cmds.checkBox("color_palette_enable",label="Define Color Palette",align="left",cc="PainterlyGui.enableColorPalette()") cmds.setParent( '..' ) cmds.frameLayout('color_frame', w=max_width-25, cll=True, l="color palette.", cl=True) cmds.columnLayout('color_layout') cmds.rowLayout(nc=2, cw2=[125, 100]) cmds.checkBox("color_1_check",label="Enable Color 1",align="left",enable=False,onc="cmds.colorSliderGrp(\'color_1_slider\',edit=True,enable=True,visible=True)",ofc="cmds.colorSliderGrp(\'color_1_slider\',edit=True,enable=False,visible=False)") cmds.colorSliderGrp("color_1_slider",rgb=[0,0,1],enable=False,visible=False) cmds.setParent( '..' ) cmds.rowLayout(nc=2, cw2=[125, 100]) cmds.checkBox("color_2_check",label="Enable Color 2",align="left",enable=False,onc="cmds.colorSliderGrp(\'color_2_slider\',edit=True,enable=True,visible=True)",ofc="cmds.colorSliderGrp(\'color_2_slider\',edit=True,enable=False,visible=False)") cmds.colorSliderGrp("color_2_slider",rgb=[0,0,1],enable=False,visible=False) cmds.setParent( '..' ) cmds.rowLayout(nc=2, cw2=[125, 100]) cmds.checkBox("color_3_check",label="Enable Color 3",align="left",enable=False,onc="cmds.colorSliderGrp(\'color_3_slider\',edit=True,enable=True,visible=True)",ofc="cmds.colorSliderGrp(\'color_3_slider\',edit=True,enable=False,visible=False)") cmds.colorSliderGrp("color_3_slider",rgb=[0,0,1],enable=False,visible=False) cmds.setParent( '..' ) cmds.rowLayout(nc=2, cw2=[125, 100]) cmds.checkBox("color_4_check",label="Enable Color 4",align="left",enable=False,onc="cmds.colorSliderGrp(\'color_4_slider\',edit=True,enable=True,visible=True)",ofc="cmds.colorSliderGrp(\'color_4_slider\',edit=True,enable=False,visible=False)") cmds.colorSliderGrp("color_4_slider",rgb=[0,0,1],enable=False,visible=False) cmds.setParent( '..' ) cmds.rowLayout(nc=2, cw2=[125, 100]) cmds.checkBox("color_5_check",label="Enable Color 5",align="left",enable=False,onc="cmds.colorSliderGrp(\'color_5_slider\',edit=True,enable=True,visible=True)",ofc="cmds.colorSliderGrp(\'color_5_slider\',edit=True,enable=False,visible=False)") cmds.colorSliderGrp("color_5_slider",rgb=[0,0,1],enable=False,visible=False) cmds.setParent( '..' ) cmds.rowLayout(nc=2, cw2=[125, 100]) cmds.checkBox("color_6_check",label="Enable Color 6",align="left",enable=False,onc="cmds.colorSliderGrp(\'color_6_slider\',edit=True,enable=True,visible=True)",ofc="cmds.colorSliderGrp(\'color_6_slider\',edit=True,enable=False,visible=False)") cmds.colorSliderGrp("color_6_slider",rgb=[0,0,1],enable=False,visible=False) cmds.setParent( '..' ) cmds.rowLayout(nc=2, cw2=[125, 100]) cmds.checkBox("color_7_check",label="Enable Color 7",align="left",enable=False,onc="cmds.colorSliderGrp(\'color_7_slider\',edit=True,enable=True,visible=True)",ofc="cmds.colorSliderGrp(\'color_7_slider\',edit=True,enable=False,visible=False)") cmds.colorSliderGrp("color_7_slider",rgb=[0,0,1],enable=False,visible=False) cmds.setParent( '..' ) cmds.rowLayout(nc=2, cw2=[125, 100]) cmds.checkBox("color_8_check",label="Enable Color 8",align="left",enable=False,onc="cmds.colorSliderGrp(\'color_8_slider\',edit=True,enable=True,visible=True)",ofc="cmds.colorSliderGrp(\'color_8_slider\',edit=True,enable=False,visible=False)") cmds.colorSliderGrp("color_8_slider",rgb=[0,0,1],enable=False,visible=False) cmds.setParent( '..' ) cmds.rowLayout(nc=2, cw2=[125, 100]) cmds.checkBox("color_9_check",label="Enable Color 9",align="left",enable=False,onc="cmds.colorSliderGrp(\'color_9_slider\',edit=True,enable=True,visible=True)",ofc="cmds.colorSliderGrp(\'color_9_slider\',edit=True,enable=False,visible=False)") cmds.colorSliderGrp("color_9_slider",rgb=[0,0,1],enable=False,visible=False) cmds.setParent( '..' ) cmds.rowLayout(nc=2, cw2=[125, 100]) cmds.checkBox("color_10_check",label="Enable Color 10",align="left",enable=False,onc="cmds.colorSliderGrp(\'color_10_slider\',edit=True,enable=True,visible=True)",ofc="cmds.colorSliderGrp(\'color_10_slider\',edit=True,enable=False,visible=False)") cmds.colorSliderGrp("color_10_slider",rgb=[0,0,1],enable=False,visible=False) cmds.setParent( '..' ) cmds.rowLayout(nc=2, cw2=[125, 100]) cmds.button("set_palette",label='set palette', c='PainterlyGui.setColorPalette()', w=100,enable=False) cmds.setParent( '..' ) cmds.setParent( '..' ) cmds.setParent( '..' ) def enableColorPalette2(layout, window_name): #cmds.setParent( layout ) color_palette_enabled = cmds.checkBox("color_palette_enable",q=True,value=True) if color_palette_enabled: for i in range(1,num_colors+1): print 'building color check box '+str(i) cmds.rowLayout(nc=2, cw2=[125, 100]) cmds.checkBox("color_"+str(i)+"_check",label="Enable Color "+str(i),align="left",enable=False,onc="cmds.colorSliderGrp(\'color_1_slider\',edit=True,enable=True,visible=True)",ofc="cmds.colorSliderGrp(\'color_1_slider\',edit=True,enable=False,visible=False)") cmds.colorSliderGrp("color_"+str(i)+"_slider",rgb=[0,0,1],enable=False,visible=False) cmds.setParent( '..' ) cmds.rowLayout(nc=2, cw2=[125, 100]) cmds.button("set_palette",label='Set Color Palette', c='PainterlyGui.setColorPalette()', w=100,enable=False) cmds.setParent( '..' ) else: for i in range(1,num_colors+1): print 'destroying color check box '+str(i) cmds.deleteUI("color_"+str(i)+"_check") cmds.deleteUI("color_"+str(i)+"_slider") cmds.deleteUI("set_palette") cmds.window(window_name, rtf=True, e=True) def enableColorPalette(): color_palette_enabled = cmds.checkBox("color_palette_enable",q=True,value=True) cmds.frameLayout('color_frame', cl=not color_palette_enabled, e=True) for i in range(1,11): cmds.checkBox("color_"+str(i)+"_check",e=True,enable=color_palette_enabled) #cmds.checkBox("color_"+str(i)+"_check",e=True,vis=color_palette_enabled) cmds.button("set_palette",e=True,enable=color_palette_enabled) def setColorPalette(): print "FOR THE LOVE OF GAWD" updateBrushImgPanel = staticmethod(updateBrushImgPanel) updateImgSequencePanel = staticmethod(updateImgSequencePanel) enableColorPalette = staticmethod(enableColorPalette) enableColorPalette2 = staticmethod(enableColorPalette2) setColorPalette = staticmethod(setColorPalette) prePrep = staticmethod(prePrep) prepCurrFrame = staticmethod(prepCurrFrame) prepFrames = staticmethod(prepFrames)##class SobelImage:## def gaussianGrid(size = 5):## m = size/2## n = m+1 # remember python is 'upto' n in the range below## x, y = mgrid[-m:n,-m:n]## # multiply by a factor to get 1 in the corner of the grid## # ie for a 5x5 grid fac*exp(-0.5*(2**2 + 2**2)) = 1## fac = exp(m**2)## g = fac*exp(-0.5*(x**2 + y**2))## return g.round().astype(int)## ## def gaussianBlur(filename):## #print 'bluring '+filename## img_to_blur = Image.open(filename)## dir_name = os.path.dirname(filename)## dir_name = SobelAlgorithm.parseFilename(dir_name)## #print 'my dir name '+dir_name## filename = SobelAlgorithm.parseFilename(filename)## save_str = 'blurred\\'+dir_name+'\\'+filename+'_blurred.png'## if os.path.exists(save_str) == False:## if not os.path.exists('blurred\\'+dir_name+'\\'):## os.makedirs('blurred\\'+dir_name+'\\')## blur_img = img_to_blur.filter(GAUSSIAN)## blur_img.save(save_str)## #print 'blurred image '+filename+' saved it to '+save_str+'.'## else:## print 'reusing previous image '+save_str ## return save_str#### gaussianGrid = staticmethod(gaussianGrid)## gaussianBlur = staticmethod(gaussianBlur)##class GAUSSIAN(ImageFilter.BuiltinFilter):## name = "Gaussian"## gg = SobelImage.gaussianGrid().flatten().tolist()## filterargs = (5,5), sum(gg), 0, tuple(gg)class SobelAlgorithm: def parseFilename(filename): while filename.find('\\') > -1: filename = filename[filename.find('\\')+1:len(filename)] jpg_index = filename.find(".jpg") png_index = filename.find(".png") if jpg_index > -1: filename = filename[0:jpg_index] if png_index > -1: filename = filename[0:png_index] #print 'changing filename to '+filename return filename def buildBW(img, filename): (w, h) = img.size pix = img.load() filename = SobelAlgorithm.parseFilename(filename) save_str = filename+'_bw.png' if os.path.isfile(save_str)or(False) == False: bw_img = Image.new("RGB", (w, h), "black") bw_pix = bw_img.load() #IF this works I will shit a chicken for r in range(0, int(h)): #This isn't working anymore!! for c in range(0, int(w)): #print '['+str(r)+', '+str(c)+']' ## to change from color to grayscale [0.3r, .59g, .11b] ## and put to all r,g,b old_r = pix[c, r][0] old_b = pix[c, r][1] old_g = pix[c, r][2] new_val = float(0.3*old_r+0.59*old_g+0.11*old_b) bw_pix[int(c), int(r)] = (new_val, new_val, new_val) bw_img.save(save_str) print 'bw image '+save_str+' saved.' else: print 'reusing previous image ('+save_str+')' return save_str def sobelAlg(bw_fn, edge_img_gx_pos, edge_img_gy_pos, edge_img_gx_neg, edge_img_gy_neg, filename, make_four): gx = [[-1,0,1],[-2,0,2],[-1,0,1]] gy = [[1,2,1],[0,0,0],[-1,-2,-1]] g_x_center = g_y_center = 1 bw_img = Image.open(bw_fn) (w, h) = bw_img.size pix = bw_img.load() edge_pix_gx_pos = edge_img_gx_pos.load() edge_pix_gy_pos = edge_img_gy_pos.load() if make_four: edge_pix_gx_neg = edge_img_gx_neg.load() edge_pix_gy_neg = edge_img_gy_neg.load() w = int(w) h = int(h) dir = os.path.dirname(filename) filename = SobelAlgorithm.parseFilename(filename)## save_str1 = "gradients\\"+filename+"\\sobel_gx_pos.png"## save_str3 = "gradients\\"+filename+"\\sobel_gx_neg.png"## save_str2 = "gradients\\"+filename+"\\sobel_gy_pos.png"## save_str4 = "gradients\\"+filename+"\\sobel_gy_neg.png" save_str1 = dir+"/gradients/sobel_gx_pos.png" save_str3 = dir+"/gradients/sobel_gx_neg.png" save_str2 = dir+"/gradients/sobel_gy_pos.png" save_str4 = dir+"/gradients/sobel_gy_neg.png" file1 = os.path.isfile(save_str1) file2 = os.path.isfile(save_str2) file3 = os.path.isfile(save_str3) file4 = os.path.isfile(save_str4) dir_name = os.path.dirname(save_str1) if not os.path.exists(dir_name): os.makedirs(dir_name) if (file1 and file2 and file3 and file4)or(False) == False: ## for the sobel image algorithm, iter [1, size-1] for r in range(1, h-1): cmds.progressBar('sobel_progress', s=w, e=True) for c in range(1, w-1): gx_r = 0 gx_g = 0 gx_b = 0 gy_r = 0 gy_g = 0 gy_b = 0 for r_add in range(-1, 2): for c_add in range(-1, 2): curr_gx = gx[g_y_center+r_add][g_x_center+c_add] curr_gy = gy[g_y_center+r_add][g_x_center+c_add] gx_r += curr_gx*pix[c+c_add, r+r_add][0] gx_g += curr_gx*pix[c+c_add, r+r_add][1] gx_b += curr_gx*pix[c+c_add, r+r_add][2] gy_r += curr_gy*pix[c+c_add, r+r_add][0] gy_g += curr_gy*pix[c+c_add, r+r_add][1] gy_b += curr_gy*pix[c+c_add, r+r_add][2] g_r_gx = 0 g_g_gx = 0 g_b_gx = 0 g_r_gy = 0 g_g_gy = 0 g_b_gy = 0 if make_four: g_r_gx = gx_r g_g_gx = gx_g g_b_gx = gx_b g_r_gy = gy_r g_g_gy = gy_g g_b_gy = gy_b #print '('+str(gx_r)+','+str(gx_g)+','+str(gx_b)+')' if g_r_gx >= 0: edge_pix_gx_pos[c, r] = (g_r_gx, g_g_gx, g_b_gx) edge_pix_gy_pos[c, r] = (g_r_gy, g_g_gy, g_b_gy) else: edge_pix_gx_neg[c, r] = ((-g_r_gx), (-g_g_gx), (-g_b_gx)) edge_pix_gy_neg[c, r] = ((-g_r_gy), (-g_g_gy), (-g_b_gy)) else: g_r_gx = int(math.sqrt(gx_r**2)) g_g_gx = int(math.sqrt(gx_g**2)) g_b_gx = int(math.sqrt(gx_b**2)) g_r_gy = int(math.sqrt(gy_r**2)) g_g_gy = int(math.sqrt(gy_g**2)) g_b_gy = int(math.sqrt(gy_b**2)) global gx_pos_filename gx_pos_filename = save_str1 edge_img_gx_pos = edge_img_gx_pos.filter(ImageFilter.BLUR).filter(ImageFilter.BLUR) edge_img_gx_pos.save(save_str1) print 'sobel image '+save_str1+' saved.' if make_four: global gx_neg_filename gx_neg_filename = save_str3 edge_img_gx_neg = edge_img_gx_neg.filter(ImageFilter.BLUR).filter(ImageFilter.BLUR) edge_img_gx_neg.save(save_str3) print 'sobel image '+save_str3+' saved.' global gy_pos_filename gy_pos_filename = save_str2 edge_img_gy_pos = edge_img_gy_pos.filter(ImageFilter.BLUR).filter(ImageFilter.BLUR) edge_img_gy_pos.save(save_str2) print 'sobel image '+save_str2+' saved.' if make_four: global gy_neg_filename gy_neg_filename = save_str4 edge_img_gy_neg = edge_img_gy_neg.filter(ImageFilter.BLUR).filter(ImageFilter.BLUR) edge_img_gy_neg.save(save_str4) print 'sobel image '+save_str4+' saved.' return (save_str1,save_str2, save_str3, save_str4) return (save_str1,save_str2) else: if make_four: print 'reusing previous images ('+save_str1+', '+save_str2+', '+save_str3+', '+save_str4+')' return (save_str1,save_str2, save_str3, save_str4) else: print 'reusing previous images ('+save_str1+', '+save_str2+')' return (save_str1,save_str2) if make_four: return (save_str1,save_str2, save_str3, save_str4) else: return (save_str1,save_str2) def run(filename): rtn = [] img = Image.open(filename) (w, h) = img.size edge_img_gx_pos = Image.new("RGB", (w, h), "black") edge_img_gy_pos = Image.new("RGB", (w, h), "black") edge_img_gx_neg = Image.new("RGB", (w, h), "black") edge_img_gy_neg = Image.new("RGB", (w, h), "black") bw_img = SobelAlgorithm.buildBW(img, filename) rtn.append(bw_img) print 'building edge detection via sobel ...' imgs = SobelAlgorithm.sobelAlg(bw_img, edge_img_gx_pos, edge_img_gy_pos, edge_img_gx_neg, edge_img_gy_neg, filename, True) for img in imgs: rtn.append(img) #SobelImage.gaussianBlur(img) #print 'this is the SOBEL algorithms return'+str(rtn) return rtn run = staticmethod(run) buildBW = staticmethod(buildBW) sobelAlg = staticmethod(sobelAlg) parseFilename = staticmethod(parseFilename)############################################################################################### __ __ _____ _ _ _____ _____ ____ _____ _____ __ __ #### | \/ | /\ |_ _| \ | | | __ \| __ \ / __ \ / ____| __ \ /\ | \/ | #### | \ / | / \ | | | \| | | |__) | |__) | | | | | __| |__) | / \ | \ / | #### | |\/| | / /\ \ | | | . ` | | ___/| _ /| | | | | |_ | _ / / /\ \ | |\/| | #### | | | |/ ____ \ _| |_| |\ | | | | | \ \| |__| | |__| | | \ \ / ____ \| | | | #### |_| |_/_/ \_\_____|_| \_| |_| |_| \_\\____/ \_____|_| \_|_/ \_\_| |_| #### ###############################################################################################if not cmds.objExists(build_cam): new_cam = cmds.duplicate('persp', rr=True) cmds.rename(new_cam[0], build_cam)mel.eval("lookThroughModelPanel "+build_cam+" modelPanel4;")mel.eval("updateModelPanelBar modelPanel4;")PainterlyGui()