def checkUnits(self): CustomSysUnits = cfgl.configLoader()[9] CurrentWorkUnits = str(rt.units.Systemtype) if CustomSysUnits != CurrentWorkUnits: rt.execute("units.Systemtype = #" + CustomSysUnits) if CustomSysUnits == 'meters': self.cboxSysUnits.setCurrentIndex(0) if CustomSysUnits == 'centimeters': self.cboxSysUnits.setCurrentIndex(1) if CustomSysUnits == 'millimeters': self.cboxSysUnits.setCurrentIndex(2) print("PolygonTools: Units changed to", CustomSysUnits) self.lblInfo_01.setText("Units changed to " + CustomSysUnits) else: if CustomSysUnits == 'meters': self.cboxSysUnits.setCurrentIndex(0) if CustomSysUnits == 'centimeters': self.cboxSysUnits.setCurrentIndex(1) if CustomSysUnits == 'millimeters': self.cboxSysUnits.setCurrentIndex(2) print("PolygonTools: Units is", CustomSysUnits) self.lblInfo_01.setText("Units is " + CustomSysUnits)
def main(): original = rt.selection[0] rt.execute("maxOps.cloneNodes $ cloneType:#copy newNodes:&nnl select nnl")# have to use Maxscript temp = rt.selection[0] temp.name = "High_" + original.name rt.addmodifier(temp,rt.Turbosmooth(iterations = 2,sepBySmGroups = True)) rt.addmodifier(temp,rt.Turbosmooth(iterations = 1))
def new_scene(force=True, do_save=True): """ Creates a new Max scene :param force: bool, True if we want to save the scene without any prompt dialog :param do_save: bool, True if you want to save the current scene before creating new scene """ if do_save and not force: save() ACTION_TABLE_ID = 0 NEW_ACTION_ID = "16" rt.EvalMAXScript('actionMan.executeAction ' + str(ACTION_TABLE_ID) + ' "' + str(NEW_ACTION_ID) + '"') return mxs_function = """fn mf = ( local windowHandle = DialogMonitorOPS.GetWindowHandle() if (windowHandle != 0) then ( UIAccessor.PressButtonByName windowHandle "Do&n't Save" ) return true ) """ rt.execute('mf={}'.format(mxs_function)) rt.DialogMonitorOPS.unRegisterNotification(id=rt.Name('forceNewFile')) rt.DialogMonitorOPS.registerNotification(rt.mf, id=rt.Name('forceNewFile')) rt.DialogMonitorOPS.enabled = True rt.actionMan.executeAction(0, '16') # new file macro action rt.DialogMonitorOPS.unRegisterNotification(id=rt.Name('forceNewFile')) rt.DialogMonitorOPS.enabled = False return True
def convert_python_list_to_maxscript_bit_array(python_list): """ Converts given Python list to a MaxScript Byte array :param python_list: list :return: rt.ByteArray """ rt.execute('fn b2a b = (return b as BitArray)') return rt.b2a(python_list)
def initializeBabylonExport(): rt.execute('Assembly = dotNetClass "System.Reflection.Assembly"') dllPath = os.path.join(rt.symbolicPaths.getPathValue(1), "bin\\assemblies\\Max2Babylon.dll") rt.execute('Assembly.loadfrom "{0}"'.format(dllPath)) rt.execute( 'maxScriptManager = dotNetObject "Max2Babylon.MaxScriptManager"') rt.execute('param = maxScriptManager.InitParameters "c:\\default.gltf"') rt.execute('param.logLevel = (dotNetClass "Max2Babylon.LogLevel").WARNING') rt.maxScriptManager.InitializeGuidTable()
def castIntToDotNetEnum(dotnetenum, index): ''' Cast python int to dotnetobject enum \nin : dotnetenum= str("dotnetenum") index= int \nout : rt.dotNetObject ''' animExpType = rt.getPropNames( rt.execute('(dotnetclass "{0}")'.format(dotnetenum))) prop = rt.name(animExpType[index]) command = '(dotnetclass "{0}").{1}'.format(dotnetenum, prop) return rt.execute(command)
def setSelectedObjVertexColor(): rt.execute('max modify mode') s = list(rt.selection) if s != None and len(s) > 0: for nod in s: if HasEditPolyn(nod): rt.Select(nod) rt.subobjectLevel = 1 rt.actionMan.executeAction( 0 ,"40021") nod.SetVertexColor(rt.color( 255, 255, 255), rt.name('VertexColor')) nod.SetVertexColor(rt.color( 255, 255, 255), rt.name('Illumination')) nod.SetVertexColor(rt.color(255,0,0), rt.name('Alpha')) rt.subobjectLevel = 0 print("Obj {0} Finished".format(nod)) else: print("OBJ {0} is not an Editable Poly, tool cannot perform vertex modifications".format(nod))
def _uvSnaps(self, assetName): originalSelection = rt.execute("selection as array") validShapes = rt.execute( "for o in selection where superClassOf o == geometryClass collect o" ) if len(validShapes) > 10: msg = "There are %s objects for UV snapshots.\nAre you sure you want to include snapshots to the Asset?" % ( len(validShapes)) state = rt.queryBox(msg, title='Too many objects for UV Snapshot') if state: pass else: return assetDirectory = os.path.join(self.directory, assetName) UVdir = os.path.join(assetDirectory, "UV_snaps") if not os.path.isdir(os.path.normpath(UVdir)): os.makedirs(os.path.normpath(UVdir)) rt.execute("max modify mode") for i in validShapes: objName = i.name UVpath = os.path.join(UVdir, '%s_uv.jpg' % objName) rt.select(i) defUnwrapMod = rt.Unwrap_UVW() rt.addModifier(i, defUnwrapMod) defUnwrapMod.setMapChannel = 1 defUnwrapMod.renderuv_fillmode = 0 defUnwrapMod.renderuv_seamColor = rt.Name("green") defUnwrapMod.renderuv_showframebuffer = False defUnwrapMod.renderuv_force2sided = False defUnwrapMod.renderuv_fillColor = rt.Name("black") defUnwrapMod.renderuv_showoverlap = False defUnwrapMod.renderuv_overlapColor = rt.Name("red") defUnwrapMod.renderuv_edgeColor = rt.Name("white") defUnwrapMod.renderuv_visibleedges = True defUnwrapMod.renderuv_invisibleedges = False defUnwrapMod.renderuv_seamedges = False defUnwrapMod.renderUV(UVpath) rt.deleteModifier(i, defUnwrapMod) rt.select(originalSelection)
def castStrToDotNetEnum(dotnetenum, string): ''' Find enum value of key string and returns it \nin : dotnetenum= str("dotnetenum") string= str \nout : rt.dotNetObject ''' arg = string.replace(" ", "") command = '(dotnetclass "{0}").{1}'.format(dotnetenum, arg) return rt.execute(command)
def startTransfer(self): mxs.execute("max create mode") with pymxs.undo(True): for i in self.skinMeshes: skinSource = mxs.skinUtils.ExtractSkinData(i[0]) skinSource = mxs.getNodeByName("SkinData_{}".format(i[0].name)) count = mxs.skinOps.GetNumberBones(i[1]) newBones = [] for item in range(count): # print(item +1, i[0].name, mxs.skinOps.GetBoneNode(i[1], item + 1)) try: newBones.append(self.dict[mxs.skinOps.GetBoneNode( i[1], item + 1)]) except: pass oldSkin = i[1] oldSkin.enabled = False skinMod = mxs.Skin() skinMod.name = "Transfered Skin" mxs.addModifier(i[0], skinMod, before=i[2] - 1) for bone in newBones: mxs.skinOps.addbone(skinMod, bone, 0) mxs.select(i[0]) mxs.selectmore(skinSource) mxs.skinUtils.ImportSkinDataNoDialog(True, False, False, False, False, 1.0, 0) mxs.delete(skinSource) mxs.clearSelection() mxs.execute("max modify mode")
def setWorkUnits(self): #load path and config PathConfig = cfgl.configLoader()[99:101] if self.cboxSysUnits.currentIndex() == 0: rt.execute("units.Systemtype = #meters") self.lblInfo_01.setText("Units changed to meters") print(self.lblInfo_01.text()) cfgl.ConfigWriter('Units', 'Custom_System_type_units', 'meters', PathConfig[0], PathConfig[1]) if self.cboxSysUnits.currentIndex() == 1: rt.execute("units.Systemtype = #centimeters") self.lblInfo_01.setText("Units changed to centimeters") print(self.lblInfo_01.text()) cfgl.ConfigWriter('Units', 'Custom_System_type_units', 'centimeters', PathConfig[0], PathConfig[1]) if self.cboxSysUnits.currentIndex() == 2: rt.execute("units.Systemtype = #millimeters") self.lblInfo_01.setText("Units changed to millimeters") print(self.lblInfo_01.text()) cfgl.ConfigWriter('Units', 'Custom_System_type_units', 'millimeters', PathConfig[0], PathConfig[1])
def _add_to_menu(menu, title, callback): """ Add a new action item to the menu and invokes the given callback when selected. :param menu: MaxScript menu object to add to. :param str title: Name of the action item :param callable callback: Method to call when the menu item is selected. """ from tank_vendor.shotgun_api3.lib import six # Hash the macro name just like we do in the engine for consistency. macro_name = "sg_" + hashlib.md5(six.ensure_binary( callback.__name__)).hexdigest() category = "Shotgun Bootstrap Menu Actions" # The createActionItem expects a macro and not some MaxScript, so create a # macro first... rt.execute(""" macroScript {macro_name} category: "{category}" tooltip: "{title}" ( on execute do ( python.execute "from tk_3dsmax_basic import plugin_bootstrap; plugin_bootstrap.{method_name}()" ) ) """.format( macro_name=macro_name, category=category, title=title, method_name=callback.__name__, )) # ... and then pass its name down to the createActionItem menu. menu_action = rt.menuMan.createActionItem(macro_name, category) menu_action.setUseCustomTitle(True) menu_action.setTitle(title) menu.addItem(menu_action, -1)
def runPreExportProcess(): babylonLogger.info("New Pre-Export started at " + str(datetime.datetime.now())) rt.execute('logger = dotNetObject "Max2Babylon.MaxScriptLogger" false') rt.execute( 'logger.logLevel = (dotNetClass "Max2Babylon.LogLevel").WARNING') rt.execute( 'preExportProcess = dotNetObject "Max2Babylon.PreExport.PreExportProcess" param logger' ) action = lambda: rt.preExportProcess.ApplyPreExport() successMsg = "Pre Export completed" return _runBabylonAction(action, successMsg)
def pickPoints(self): self.geo = self.geometry() self.hide() try: mxs.unregisterRedrawViewsCallback(self.debugView) except: pass try: self.pos1 = mxs.pickPoint( snap=mxs.readvalue(mxs.StringStream('#3D'))) self.pos2 = mxs.pickPoint( snap=mxs.readvalue(mxs.StringStream('#3D'))) self.moveVector = self.pos2 - self.pos1 vector = self.moveVector X = mxs.normalize(vector) Z = mxs.point3(0, 0, 1) Y = mxs.normalize(mxs.cross(Z, X)) Z = mxs.normalize(mxs.cross(X, Y)) self.transform = mxs.matrix3(Z, Y, X, mxs.point3(0, 0, 0)) mxs.WorkingPivot.SetTM(self.transform) mxs.execute("max tti") mxs.registerRedrawViewsCallback(self.debugView) mxs.execute("max move") mxs.execute("toolMode.coordsys #working_pivot") self.show() self.setGeometry(self.geo) except: print("Point Picking Cancelled")
def getAssetRefs(filename): """ Gets all references in the scene, based on the BitmapClasses list from the settings .json file. This returns a dictionary with the materials, geometry, and modifiers associated with the filename. @param {str} filename: The full filename to get all references from @return {dictionary} """ # Get the .json settings first. This'll list all of the classes to # iterate through, and what their respective 'filename' parameter # is called. data = getSettings() materials = [] geometry = [] modifiers = [] # Iterates through the different MAXScript classes to check through for classKey in data["BitmapClasses"]: # Get the respective class' denoted 'filename' parameter # These vary a bit per class paramNames = data["BitmapClasses"][classKey] # Get the MAXScript Value of the class classValue = rt.execute(classKey) # Create an empty list of the nodes we'll look through nodes = [] # If it DOES exist, meaning the standard or 3rd party plugins # are found (Max, Arnold, V-Ray, etc.) if classValue != None: # Get all the instances of that node instances = rt.GetClassInstances(classValue) for inst in instances: # If that node matches the same filename we're currently # checking against, then it's a match! try: for param in paramNames: if (rt.getProperty(inst, param)) == filename: nodes.append(inst) except: pass # If we've found 1 or more matching nodes, we'll iterate through them if len(nodes) > 0: for node in nodes: # Get the node's dependents. This'll be a giant array of every # dependent found in the scene, which'll include a bunch of # nonsense nodes. deps = rt.refs.dependents(node) # Filter through each dependent and add to each respective list # whether it's a subclass of materials, geometry, or modifiers. for dep in deps: if rt.superClassOf(dep) == MXS_MATERIAL_CLASS: materials.append(dep) if rt.superClassOf(dep) == MXS_GEOMETRY_CLASS: geometry.append(dep) if rt.superClassOf(dep) == MXS_MODIFIER_CLASS: modifiers.append(dep) # Return the mapped dictionary of nodes we found return { "Materials" : materials, "Geometry" : geometry, "Modifiers": modifiers } # If we didn't find anything, return an empty dictionary return {}
def run(): rt.execute('Assembly = dotNetClass "System.Reflection.Assembly"') dllPath = os.path.join(rt.symbolicPaths.getPathValue(1),"bin\\assemblies\\Max2Babylon.dll") rt.execute('Assembly.loadfrom "{0}"'.format(dllPath)) rt.execute('maxScriptManager = dotNetObject "Max2Babylon.MaxScriptManager"') rt.maxScriptManager.AutoAssignLodInAnimationGroup()
def setRTParameters(babylonParameters): if isinstance(babylonParameters, BabylonParameters): rt.execute( 'param = maxScriptManager.InitParameters "c:\\default.gltf"') rt.execute( 'param.logLevel = (dotNetClass "Max2Babylon.LogLevel").WARNING') rt.execute('logger = dotNetObject "Max2Babylon.MaxScriptLogger" false') rt.execute( 'logger.logLevel = (dotNetClass "Max2Babylon.LogLevel").WARNING') if (babylonParameters.exportNode): rt.param.exportNode = rt.param.GetNodeByHandle( babylonParameters.exportNode.inode.handle) if (babylonParameters.exportLayers): rt.param.exportLayers = rt.param.NameToIILayer( babylonParameters.exportLayers) rt.param.outputPath = __overwriteIfSet(rt.param.outputPath, babylonParameters.outputPath) rt.param.outputFormat = __overwriteIfSet( rt.param.outputFormat, babylonParameters.outputFormat) rt.param.textureFolder = __overwriteIfSet( rt.param.textureFolder, babylonParameters.textureFolder) rt.param.scaleFactor = __overwriteIfSet(rt.param.scaleFactor, babylonParameters.scaleFactor) rt.param.writeTextures = __overwriteIfSet( rt.param.writeTextures, babylonParameters.writeTextures) rt.param.animationExportType = __overwriteIfSet( rt.param.animationExportType, babylonParameters.animationExportType) rt.param.enableASBAnimationRetargeting = __overwriteIfSet( rt.param.enableASBAnimationRetargeting, babylonParameters.enableASBAnimationRetargeting) rt.param.enableASBUniqueID = __overwriteIfSet( rt.param.enableASBUniqueID, babylonParameters.enableASBUniqueID) rt.param.overwriteTextures = __overwriteIfSet( rt.param.overwriteTextures, babylonParameters.overwriteTextures) rt.param.exportHiddenObjects = __overwriteIfSet( rt.param.exportHiddenObjects, babylonParameters.exportHiddenObjects) rt.param.exportMaterials = __overwriteIfSet( rt.param.exportMaterials, babylonParameters.exportMaterials) rt.param.exportOnlySelected = __overwriteIfSet( rt.param.exportOnlySelected, babylonParameters.exportOnlySelected) rt.param.usePreExportProcess = __overwriteIfSet( rt.param.usePreExportProcess, babylonParameters.usePreExportProcess) rt.param.applyPreprocessToScene = __overwriteIfSet( rt.param.applyPreprocessToScene, babylonParameters.applyPreprocessToScene) rt.param.flattenGroups = __overwriteIfSet( rt.param.flattenGroups, babylonParameters.flattenGroups) rt.param.mergeContainersAndXRef = __overwriteIfSet( rt.param.mergeContainersAndXRef, babylonParameters.mergeContainersAndXRef) #rt.param.flattenScene = __overwriteIfSet(rt.param.flattenScene,babylonParameters.flattenScene) rt.param.bakeAnimationType = __overwriteIfSet( rt.param.bakeAnimationType, babylonParameters.bakeAnimationType) rt.param.removeNamespaces = __overwriteIfSet( rt.param.removeNamespaces, babylonParameters.removeNamespaces) rt.param.removeLodPrefix = __overwriteIfSet( rt.param.removeLodPrefix, babylonParameters.removeLodPrefix) rt.param.keepInstances = __overwriteIfSet( rt.param.keepInstances, babylonParameters.keepInstances) rt.param.tangentSpaceConvention = __overwriteIfSet( rt.param.tangentSpaceConvention, babylonParameters.tangentSpaceConvention) rt.param.mergeAOWithMR = __overwriteIfSet( rt.param.mergeAOWithMR, babylonParameters.mergeAOWithMR)
def createPreview(self, *args, **kwargs): """Creates a Playblast preview from currently open scene""" # rt = pymxs.runtime openSceneInfo = self.getOpenSceneInfo() if not openSceneInfo: msg = "This is not a base scene. Scene must be saved as a base scene before playblasting." # raise Exception([360, msg]) self._exception(360, msg) return # logger.warning(msg) # return -1, msg # get view info viewportType = rt.viewport.getType() if str(viewportType) == "view_camera": currentCam = str(rt.getActiveCamera().name) else: currentCam = str(viewportType) validName = currentCam.replace("|", "__").replace(" ", "_") extension = "avi" # versionName = rt.getFilenameFile(rt.maxFileName) # versionName = rt.maxFilePath + rt.maxFileName # abs path of the filename with extension relVersionName = os.path.relpath( versionName, start=openSceneInfo["projectPath"] ) # relative path of filename with ext if not os.path.isdir(os.path.normpath(openSceneInfo["previewPath"])): os.makedirs(os.path.normpath(openSceneInfo["previewPath"])) playBlastFile = os.path.join( openSceneInfo["previewPath"], "{0}_{1}_PB.{2}".format(self.niceName(versionName), validName, extension)) relPlayBlastFile = os.path.relpath(playBlastFile, start=openSceneInfo["projectPath"]) if os.path.isfile(playBlastFile): try: os.remove(playBlastFile) except WindowsError: msg = "The file is open somewhere else" logger.warning(msg) return -1, msg jsonInfo = self._loadJson(openSceneInfo["jsonFile"]) if jsonInfo == -1: msg = "Database file is corrupted" return -1, msg # returns 0,"" if everything is ok, -1,msg if error pbSettings = self.loadPBSettings() originalValues = {"width": rt.renderWidth, "height": rt.renderHeight} originalSelection = rt.execute("selection as array") # change the render settings temporarily rt.renderWidth = pbSettings["Resolution"][0] rt.renderHeight = pbSettings["Resolution"][1] if pbSettings["PolygonOnly"]: dspGeometry = True dspShapes = False dspLights = False dspCameras = False dspHelpers = False dspParticles = False dspBones = False else: dspGeometry = True dspShapes = True dspLights = True dspCameras = True dspHelpers = True dspParticles = True dspBones = True dspGrid = pbSettings["ShowGrid"] dspFrameNums = pbSettings["ShowFrameNumber"] percentSize = pbSettings["Percent"] if pbSettings["WireOnShaded"]: rndLevel = rt.execute("#litwireframe") else: rndLevel = rt.execute("#smoothhighlights") if pbSettings["ClearSelection"]: rt.clearSelection() # find the path of where the avi file be created # if rt.maxFilePath: # previewname = rt.getFilenameFile(rt.maxFileName) # else: # previewname = "Untitled" # sourceClip = rt.GetDir(rt.execute("#preview")) + "\_scene.avi" # if os.path.isfile(sourceClip): # try: # os.remove(sourceClip) # except WindowsError: # msg = "Cannot continue creating preview.\n Close '%s' and try again" %sourceClip # logger.error(msg) # return -1, msg test = rt.createPreview(filename=playBlastFile, percentSize=percentSize, dspGeometry=dspGeometry, dspShapes=dspShapes, dspLights=dspLights, dspCameras=dspCameras, dspHelpers=dspHelpers, dspParticles=dspParticles, dspBones=dspBones, dspGrid=dspGrid, dspFrameNums=dspFrameNums, rndLevel=rndLevel) # prior to version 2020, filename flag is not working if not os.path.isfile(playBlastFile): # find the path of where the avi file be created if rt.maxFilePath: previewname = rt.getFilenameFile(rt.maxFileName) else: previewname = "Untitled" sourceClip = rt.GetDir(rt.execute("#preview")) + "\_scene.avi" shutil.copy(sourceClip, playBlastFile) # if os.path.isfile(sourceClip): # try: # os.remove(sourceClip) # except WindowsError: # msg = "Cannot continue creating preview.\n Close '%s' and try again" %sourceClip # logger.error(msg) # return -1, msg # return # return the render width and height to original: rt.renderWidth = originalValues["width"] rt.renderHeight = originalValues["height"] rt.select(originalSelection) # shutil.copy(sourceClip, playBlastFile) if pbSettings["ConvertMP4"]: convertedFile = self._convertPreview(playBlastFile, overwrite=True, deleteAfter=False, crf=pbSettings["CrfValue"]) relPlayBlastFile = os.path.relpath( convertedFile, start=openSceneInfo["projectPath"]) # os.startfile(convertedFile) else: relPlayBlastFile = os.path.relpath( playBlastFile, start=openSceneInfo["projectPath"]) ## find this version in the json data for version in jsonInfo["Versions"]: if relVersionName == version["RelativePath"]: version["Preview"][currentCam] = relPlayBlastFile self._dumpJson(jsonInfo, openSceneInfo["jsonFile"]) return 0, ""
def projectVertexColor(self, nodeToBake, nodeToProject, outputPath, padding): """ Project the vertex color of a given node to a given surface and bake the result in the given path Parameters ---------- nodeToBake : INode the node used to bake the texture nodeToProject : INode the node used to project the vertex color outputPath : str the path of the baked texture """ rt.disableSceneRedraw() rt.select(nodeToBake) snap = rt.snapshot(nodeToBake, name=nodeToBake.name + "_new") snap.material = rt.standard(showInViewport=False, name="GlassMat") nodeToProject.material = rt.standard(diffuseMap=rt.Vertex_Color(), showInViewport=False, name="WiperMat") # --Clear all render elements snap.iNodeBakeProperties.removeAllBakeElements() # --Preparing the Bake Elements: be1 = rt.diffusemap() # --instance of the bake element class be1.outputSzX = be1.outputSzY = 1024 # --set the size of the baked map --specifythe full file path, name and type: be1.fileType = outputPath be1.fileName = rt.filenameFromPath(be1.fileType) be1.filterOn = True # --enable filtering be1.shadowsOn = False # --disable shadows be1.lightingOn = False # --disable lighting be1.enabled = True # --enable baking snap.iNodeBakeProperties.nDilations = padding # --expand the texturea bit snap.iNodeBakeProperties.addBakeElement(be1) # --add first element snap.iNodeBakeProperties.bakeEnabled = True # --enabling baking snap.iNodeBakeProperties.bakeChannel = 2 # --channel to bake snap.INodeBakeProjProperties.bakeEnabled = True # --enabling baking snap.INodeBakeProjProperties.bakeChannel = 2 # --channel to bake snap.INodeBakeProjProperties.subObjBakeChannel = 2 snap.INodeBakeProjProperties.enabled = True #enable projection baking # add a projection modifier and set it as the projection source projection = rt.Projection() rt.addModifier(snap, projection) projection.addObjectNode(nodeToProject) projection.resetCage() snap.INodeBakeProjProperties.projectionMod = projection snap.INodeBakeProjProperties.rayMissColor = rt.Point3(0, 0, 0) #select the object enter modify mode, offset the cage and bake the texture at the given path rt.select( snap ) # --we are baking the selection, so we select the object --Call the rendererto bake both elements: rt.execute("max modify mode") projection.pushCage(0.1) rt.render(rendertype=rt.Name("bakeSelected"), vfb=False, progressBar=True, outputSize=rt.Point2(1024, 1024)) print("baked image in {0}".format(be1.fileType)) rt.delete(snap) rt.enableSceneRedraw() rt.CompleteRedraw()
def buildWiperMesh(self, p1, p2): """ Build the wiper mesh Parameters ---------- p1 : Point3 the world position of the first dummy placed on the exterior part of the wiper p2 : Point3 the world position of the second dummy placed on the exterior part of the wiper """ animationLength = self.animInEndFrame - self.animInStartFrame + 1 projectMeshVertices = [] projectMeshFaces = [] vColors = [rt.Point3(0, 0, 0) for i in range(animationLength * 2)] vert_count = 0 if rt.DEBUG_MODE: print( "------------------------------------------------------------------" ) #fill projectMeshVertices with the exterior points of the wiper for each frame f = self.animInStartFrame while f <= self.animInEndFrame: with at(f): projectMeshVertices.append(p1.transform.position) projectMeshVertices.append(p2.transform.position) f += 1 # fill the vertexColors array during animation IN vIndex = 0 f = self.animInStartFrame while f <= self.animInEndFrame: with at(f): self.setColorByFrame(f, vColors[vIndex]) self.setColorByFrame(f, vColors[vIndex + 1]) f += 1 vIndex += 2 # fill the vertexColors array during animation OUT vIndex = 0 f = self.animOutEndFrame while f >= self.animOutStartFrame: with at(f): self.setColorByFrame(f, vColors[vIndex]) self.setColorByFrame(f, vColors[vIndex + 1]) f -= 1 vIndex += 2 axis = rt.Point3(1, 0, 0) result = rt.dot(p2.transform.position, axis) for i in range(1, len(projectMeshVertices) - 1): #build the triangle with the righ orientation if i % 2 != 0: projectMeshFaces.append( rt.Point3(vert_count + 3, vert_count + 2, vert_count + 1)) else: projectMeshFaces.append( rt.Point3(vert_count + 2, vert_count + 3, vert_count + 1)) vert_count += 1 #build the mesh with an array of vertex and triangles projectionMesh = rt.mesh(vertices=rt.Array(*(projectMeshVertices)), faces=rt.Array(*(projectMeshFaces))) rt.defaultVCFaces(projectionMesh) #set the vertex color for each vertex for i in range(len(projectMeshVertices)): rt.setVertColor(projectionMesh, i + 1, vColors[i]) if result > 0: rt.select(projectionMesh) rt.execute("max modify mode") normalModifier = rt.NormalModifier() rt.addModifier(projectionMesh, rt.NormalModifier()) normal = rt.Name("Normal") projectionMesh.modifiers[normal].flip = True rt.maxOps.CollapseNode(projectionMesh, False) #quadrify rt.select(projectionMesh) rt.convertToPoly(projectionMesh) rt.execute("max modify mode") rt.PolyToolsModeling.Quadrify(True, False) edge = rt.Name("EDGE") edgeNumber = projectionMesh.EditablePoly.getNumEdges() edgeList = [1] if result < 0 else [2] edgeSelection = rt.BitArray(*(edgeList)) rt.subObjectLevel = 2 projectionMesh.EditablePoly.SetSelection(edge, edgeSelection) projectionMesh.EditablePoly.SelectEdgeRing() projectionMesh.connectEdgeSegments = 3 rt.execute('macros.run "Ribbon - Modeling" "ConnectEdges"') return projectionMesh
def execute(): # Define the target object my_target = mxs.selection[0] # Reset the pivot my_target.pivot = my_target.center # Define the grid object my_grid = mxs.grid() # Define the vector vector = my_target.transform.position - mxs.inverse( mxs.viewport.getTM()).position # Define the length of the target distance = (mxs.length(my_target.min - my_target.max) / 2) # Normalize + UP vector (Z) X = mxs.normalize(vector) Z = mxs.point3(0, 0, 1) Y = mxs.normalize(mxs.cross(Z, X)) Z = mxs.normalize(mxs.cross(X, Y)) # Define a new transform based on vector my_transform = mxs.matrix3(Z, Y, X, my_target.transform.position) # Edit the position of the transform new_position = my_transform.position - (X * distance) my_transform = mxs.matrix3(Z, Y, X, new_position) # Assign the transform to the grid my_grid.transform = my_transform # Activate the grid mxs.activegrid = my_grid # Define spline method def setMode(name): name.curveType = 1 try: # Set iso view mxs.execute("max vpt iso user") # Define user draw curves curves = mxs.startObjectCreation(mxs.FreehandSpline, returnNewNodes=True, newNodeCallback=setMode) # Define modifiers noise_mod = mxs.Noisemodifier() quad_mod = mxs.Quadify_Mesh() extrude_mod = mxs.Extrude() # Change the parameters extrude_mod.amount = distance * 2 quad_mod.quadsize = 2 noise_mod.scale = 10 noise_mod.fractal = True noise_mod.strength = mxs.point3(2, 10, 2) # Add the modifiers mxs.addmodifier(curves, extrude_mod) mxs.addmodifier(curves, quad_mod) mxs.addmodifier(curves, noise_mod) # Define cutter splines mxs.ProCutter.CreateCutter(curves, 1, True, True, False, True, True) # Define stock object mxs.ProCutter.AddStocks(curves[0], my_target, 1, 1) # Set perspective view mxs.execute("max vpt persp user") # Deactivate and delete the grid mxs.activegrid = None mxs.delete(my_grid) except: # Set perspective view mxs.execute("max vpt persp user") # Deactivate and delete the grid mxs.activegrid = None mxs.delete(my_grid) print("cancled")
from pymxs import runtime as rt import sys, os # Paths ROOT_DIR = os.path.dirname(os.path.realpath(__file__)) sys.path.append(ROOT_DIR) # Indexes ITEM_NAME = 1 ITEM_EXT = 2 ITEM_PATH = 3 ITEM_TYPE = 4 ITEM_STATUS = 5 ITEM_SIZE = 6 # MAXScript Types MXS_MATERIAL_CLASS = rt.execute("material") MXS_GEOMETRY_CLASS = rt.execute("geometryclass") MXS_MODIFIER_CLASS = rt.execute("modifier")
from pymxs import runtime as rt import os import sys import importlib sys.path.append(os.path.dirname(__file__)) from maxsdk.globals import * # start installing FlightSim material and legacy maxscript script c = os.path.dirname(__file__) cmd = 'filein @"{0}\\..\\msfs_max_ms\\FlightSim_EntryPoint.ms"'.format(c) rt.execute(cmd) IS_PUBLIC_SDK = rt.globalVars.get("IS_PUBLIC_SDK") if not IS_PUBLIC_SDK: if MAXVERSION() >= MAX2021: from configparser import ConfigParser configur = ConfigParser() configur.read(os.path.join(c, 'internal_tools.ini')) internal_modules = [] for k in configur["INTERNAL"]: internal_modules.append(configur["INTERNAL"].get(k)) else: from ConfigParser import RawConfigParser configur = RawConfigParser() configur.read(os.path.join(c, 'internal_tools.ini')) internal_modules = [] for (a, b) in configur.items("INTERNAL"): internal_modules.append((a, b)[1].replace('"', ''))
def DeletedFrame(self, startFrame, endFrame): # rt.animationRange = rt.interval(0, 1) #프레임삭제 max_script = ''' fn GetAnimationRange_Interval target_nodeArray:(objects as Array)= ( local keyIdex_int = 0 local startKeyArray = #() local endKeyArray = #() local startFrame = undefined local endFrame = undefined for obj in target_nodeArray do ( if classof(obj.controller) == prs do ( keyIdex_int = numKeys obj.pos.controller if (keyIdex_int != undefined and keyIdex_int >= 1) do ( append startKeyArray (obj.pos.controller.keys[1]).time append endKeyArray (obj.pos.controller.keys[keyIdex_int]).time ) keyIdex_int = numKeys obj.rotation.controller if (keyIdex_int != undefined and keyIdex_int >= 1) do ( append startKeyArray (obj.rotation.controller.keys[1]).time append endKeyArray (obj.rotation.controller.keys[keyIdex_int]).time ) keyIdex_int = numKeys obj.scale.controller if (keyIdex_int != undefined and keyIdex_int >= 1) do ( append startKeyArray (obj.scale.controller.keys[1]).time append endKeyArray (obj.scale.controller.keys[keyIdex_int]).time ) ) if ClassOf obj == Biped_Object do ( keyIdex_int = numKeys obj.controller if (keyIdex_int != undefined and keyIdex_int >= 1) do ( append startKeyArray (biped.getKey obj.controller 1).time append endKeyArray (biped.getKey obj.controller keyIdex_int).time ) ) ) makeUniqueArray startKeyArray makeUniqueArray endKeyArray sort startKeyArray sort endKeyArray if startKeyArray.count > 0 then ( startFrame startKey_integer = 0 i_int = 1 --while (startFrame == undefined and i_int < startKeyArray.count ) do ( -- startKey_integer = (startKeyArray[i_int] as integer)/TicksPerFrame -- if startKey_integer > -9999 do -- ( -- startFrame = startKeyArray[i_int] -- ) -- i_int = i_int + 1 --) startFrame = startKeyArray[i_int] endFrame = endKeyArray[endKeyArray.count] ) else ( startFrame = 0 endFrame = 1 ) if (startFrame == undefined ) do ( startFrame = 0 ) if (endFrame == undefined) do ( endFrame == 1 ) if (startFrame == endFrame) do ( endFrame = endFrame+1 ) reInterval = Interval startFrame endFrame ) fn OutOfFrameDelet_fn arg_objs_array = ( local startFrame = copy(animationRange.start.frame) local endFrame = Copy(animationRange.end.frame) local goObjs_array = #() local fullAniRange_interval = GetAnimationRange_Interval() print fullAniRange_interval goObjs_array = arg_objs_array for obj in goObjs_array do ( keyIdex_int = 0 obj_ctrl = obj.controller deselectKeys obj.controller selectKeys obj.controller deselectKeys obj.controller (interval startFrame endFrame) if ClassOf(obj) == biped_Object do ( if (getClassName obj_ctrl == "Body") then ( deleteKeys obj.controller.vertical.controller.keys #selection deleteKeys obj.controller.horizontal.controller.keys #selection deleteKeys obj.controller.turning.controller.keys #selection ) else if obj.controller.keys.count > 0 do ( deleteKeys obj.controller.keys #selection ) ) if endFrame < fullAniRange_interval.end do ( deleteTime obj (endFrame+1) (fullAniRange_interval.end + 1) ) if fullAniRange_interval.start < (startFrame - 1) do ( deleteTime obj (fullAniRange_interval.start - 1) (startFrame-1) #noSlide ) ) ) OutOfFrameDelet_fn (objects as Array) ''' rt.execute(max_script)
def _import(self, filePath, prompt=True, *args, **kwargs): if prompt: fManager.Merge(filePath) else: command = 'mergeMAXFile "%s"' % filePath.replace(os.sep, "/") rt.execute(command)
def _getSelection(self, asMaxArray=False): sel = rt.execute("selection as array") if not asMaxArray: return [x.name for x in sel] else: return sel
def saveAsset(self, assetName, exportUV=True, exportOBJ=True, exportFBX=True, exportABC=True, selectionOnly=True, sceneFormat="max", notes="N/A", **info): """ Saves the selected object(s) as an asset into the predefined library """ # self.ssResolution = 1000 if assetName == "": msg = "Asset Name cannot be empty" state = rt.messageBox(msg, title='Info') return if assetName in self.assetsList: msg = "This Asset already exists.\nDo you want to overwrite?" state = rt.queryBox(msg, title='Manager Question') if state: pass else: return originalSelection = self._getSelection(asMaxArray=True) originalPath = self._getSceneFile() dump, origExt = os.path.splitext(originalPath) assetDirectory = os.path.join(self.directory, assetName) assetAbsPath = os.path.join(assetDirectory, "%s%s" % (assetName, u'.%s' % sceneFormat)) if selectionOnly: selection = self._getSelection(asMaxArray=True) if len(selection) == 0: msg = "No object selected" rt.messageBox(msg, title='Info') return else: rt.select(rt.objects) selection = self._getSelection(asMaxArray=True) # originalSelection = self._getSelection(asMaxArray=True) if not os.path.exists(assetDirectory): os.mkdir(assetDirectory) # GET TEXTURES # ------------ if selectionOnly: possibleFileHolders = rt.execute("selection as Array") filteredBitmaps = self._getFileNodes(possibleFileHolders) else: allTexture = rt.usedMaps() allBitmap = rt.getClassInstances(rt.bitmapTexture) # this makes sure only the USED bitmaps will stored filteredBitmaps = [ x for x in allBitmap if x.filename in allTexture ] textureDatabase = [ x for x in self._buildPathDatabase(filteredBitmaps, assetDirectory) ] self._copyTextures(textureDatabase) # CREATE PREVIEWS # --------------- thumbPath, ssPath, swPath = self._createThumbnail( assetName, selectionOnly=selectionOnly, viewFit=True) # CREATE UV SNAPSHOTS # ---------------- rt.select(selection) if exportUV: self._uvSnaps(assetName) # SAVE SOURCE # ----------- fManager.SaveSelected(assetAbsPath) # EXPORT OBJ # ---------- if exportOBJ: objFilePath = os.path.join(assetDirectory, "%s.obj" % assetName) if self._exportObj(objFilePath, exportSettings=self.exportSettings): objName = "{0}.obj".format(assetName) else: objName = "N/A" else: objName = "N/A" # EXPORT FBX # ---------- if exportFBX: fbxFilePath = os.path.join(assetDirectory, "%s.fbx" % assetName) frame = self._getCurrentFrame() if self._exportFbx(fbxFilePath, exportSettings=self.exportSettings, timeRange=[frame, frame]): fbxName = "{0}.fbx".format(assetName) else: fbxName = "N/A" else: fbxName = "N/A" # EXPORT ALEMBIC # -------------- if exportABC: abcFilePath = os.path.join(assetDirectory, "%s.abc" % assetName) frame = self._getCurrentFrame() if self._exportAlembic(abcFilePath, exportSettings=self.exportSettings, timeRange=[frame, frame]): abcName = "{0}.abc".format(assetName) else: abcName = "N/A" else: abcName = "N/A" # NUMERIC DATA # ------------ polyCount = sum(rt.getPolygonCount(x)[0] for x in selection) # polyCount = sum(rt.getPolygonCount(x)[0] for x in countLoop) tiangleCount = sum(rt.getPolygonCount(x)[1] for x in selection) # tiangleCount = sum(rt.getPolygonCount(x)[1] for x in countLoop) versionInfo = rt.maxversion() vInfo = [versionInfo[0], versionInfo[1], versionInfo[2]] # DATABASE # -------- dataDict = {} dataDict['sourceProject'] = "3dsMax" dataDict['version'] = vInfo dataDict['assetName'] = assetName dataDict['objPath'] = objName dataDict['fbxPath'] = fbxName dataDict['abcPath'] = abcName dataDict['sourcePath'] = os.path.basename(assetAbsPath) dataDict['thumbPath'] = os.path.basename(thumbPath) dataDict['ssPath'] = os.path.basename(ssPath) dataDict['swPath'] = os.path.basename(swPath) dataDict['textureFiles'] = [x["Texture"] for x in textureDatabase] dataDict['Faces/Triangles'] = ("%s/%s" % (str(polyCount), str(tiangleCount))) dataDict['origin'] = originalPath dataDict['notes'] = notes self._setData(assetName, dataDict) rt.clearSelection() self._returnOriginal(textureDatabase) # self.scanAssets() # scanning issued at populate function on ui class rt.select(originalSelection) rt.messageBox("Asset Created Successfully", title='Info', beep=False)