def _importAlembic(self, filePath, importSettings, *args, **kwargs):
        # Set Alembic Options according to the Max Version:
        v = rt.maxVersion()[0]
        maxImp_abc = importSettings["alembicImportMax"]

        if v > 17000:  # Alembic export is not supported before 3ds Max 2016
            if rt.pluginManager.loadclass(rt.Alembic_Export):
                if 18000 <= v < 21000:  # between versions 2016 - 2018
                    rt.AlembicImport.CoordinateSystem = rt.Name(
                        maxImp_abc["CoordinateSystem"])
                    rt.AlembicImport.CacheTimeRange = rt.Name(
                        maxImp_abc["AnimTimeRange"])
                    rt.AlembicImport.ShapeName = maxImp_abc["ShapeSuffix"]
                    rt.AlembicImport.ImportToRoot = maxImp_abc["ImportToRoot"]
                    rt.AlembicImport.FitTimeRange = maxImp_abc["FitTimeRange"]
                    rt.AlembicImport.SetStartTime = maxImp_abc["SetStartTime"]
                    rt.AlembicExport.StepFrameTime = maxImp_abc[
                        "SamplesPerFrame"]

                elif v >= 21000:  # version 2019 and up
                    rt.AlembicImport.CoordinateSystem = rt.Name(
                        maxImp_abc["CoordinateSystem"])
                    rt.AlembicImport.AnimTimeRange = rt.Name(
                        maxImp_abc["AnimTimeRange"])
                    rt.AlembicImport.ShapeSuffix = maxImp_abc["ShapeSuffix"]
                    rt.AlembicImport.SamplesPerFrame = maxImp_abc[
                        "SamplesPerFrame"]
                    rt.AlembicImport.Hidden = maxImp_abc["Hidden"]
                    rt.AlembicImport.UVs = maxImp_abc["UVs"]
                    rt.AlembicImport.Normals = maxImp_abc["Normals"]
                    rt.AlembicImport.VertexColors = maxImp_abc["VertexColors"]
                    rt.AlembicImport.ExtraChannels = maxImp_abc[
                        "ExtraChannels"]
                    rt.AlembicImport.Velocity = maxImp_abc["Velocity"]
                    rt.AlembicImport.MaterialIDs = maxImp_abc["MaterialIDs"]
                    rt.AlembicImport.Visibility = maxImp_abc["Visibility"]
                    rt.AlembicImport.LayerName = maxImp_abc["LayerName"]
                    rt.AlembicImport.MaterialName = maxImp_abc["MaterialName"]
                    rt.AlembicImport.ObjectID = maxImp_abc["ObjectID"]
                    rt.AlembicImport.CustomAttributes = maxImp_abc[
                        "CustomAttributes"]

                # Export
                rt.importFile(filePath,
                              rt.Name("NoPrompt"),
                              using=rt.Alembic_Import)
                return True

            else:
                rt.messageBox("Alembic Plugin cannot be initialized. Skipping",
                              title="Alembic not supported")
                return False
        else:
            rt.messageBox(
                "There is no alembic support for this version. Skipping",
                title="Alembic not supported")
            return False
 def _exportRedshift(self,
                     filePath,
                     exportSettings,
                     exportSelected=True,
                     timeRange=[0, 10]):
     # TODO: // export redshift core function for 3ds Max
     rt.messageBox("Redshift Proxy Export for 3ds Max is under development",
                   title='Info')
     return False
def combine_selected_objects():
    """
    Convert the selected objects into an editable mesh. The selections needs to contain
    at least 2 objects to combine.
    """
    if len(rt.selection) < 2:
        msg = "Please select at least 2 nodes to combine."
        print(msg)
        rt.messageBox(msg)
    else:
        # combine all the selected nodes into one editable mesh
        combine_objects(*rt.selection)
 def _importFbx(self, filePath, importSettings, *args, **kwargs):
     if rt.pluginManager.loadclass(rt.FBXIMP):
         maxImp_fbx = importSettings["fbxImportMax"]
         # Set FBX Options
         for item in maxImp_fbx.items():
             rt.FBXImporterSetParam(rt.Name(item[0]), item[1])
         rt.FBXImporterSetParam(rt.Name("UpAxis"), "Z")
         try:
             rt.importFile(filePath, rt.Name("NoPrompt"), using=rt.FBXIMP)
             return True
         except:
             msg = "Cannot import FBX file for unknown reason. Skipping import"
             rt.messageBox(msg, title='Info')
             return False
     else:
         msg = "FBX Plugin cannot be initialized. Skipping import"
         rt.messageBox(msg, title='Info')
         return False
    def _exportFbx(self,
                   filePath,
                   exportSettings,
                   exportSelected=True,
                   timeRange=[0, 10]):
        """
        Exports FBX (.fbx) file
        Args:
            filePath: (String) Absolute File path for exported file
            exportSettings: (Dictionary) settings file (see getExportSettings)
            exportSelected: (Boolean) If True, exports only currently selected objects, else whole scene. Default True

        Returns: (Boolean) True for success False for failure

        """
        if rt.pluginManager.loadclass(rt.FBXEXP):
            maxExp_fbx = exportSettings["fbxExportMax"]

            # OVERRIDE ANIMATION SETTINGS
            if timeRange[0] != timeRange[1]:
                maxExp_fbx["Animation"] = True
                maxExp_fbx["BakeFrameStart"] = timeRange[0]
                maxExp_fbx["BakeFrameEnd"] = timeRange[1]
            else:
                maxExp_fbx["Animation"] = False

            # Set FBX Options
            for item in maxExp_fbx.items():
                rt.FBXExporterSetParam(rt.Name(item[0]), item[1])

            try:
                rt.exportFile(filePath,
                              rt.Name("NoPrompt"),
                              selectedOnly=exportSelected,
                              using=rt.FBXEXP)
                return True
            except:
                msg = "Cannot export FBX for unknown reason. Skipping FBX export"
                rt.messageBox(msg, title='Info')
                return False
        else:
            msg = "FBX Plugin cannot be initialized. Skipping FBX export"
            rt.messageBox(msg, title='Info')
            return False
示例#6
0
 def applyLayerSelectionToPreset(self, preset, layerNames):
     r = qtUtils.popup_Yes_No(title="Apply Unsaved Changes ?",text="You need to save the scene to apply")
     baseFile = rt.maxFilePath + rt.maxFileName
     if r:
         preset.edit(layerNames=layerNames)
         self.btnApplyPresetLayer.setText("Apply")
         self.treeLayer.isEdited = False
         if baseFile != None:
             s = rt.saveMaxFile(baseFile)
             if s == False:
                 rt.messageBox("Save failed, choose another path, or checkout your file.")
                 f = rt.getSaveFileName(caption="Save as", filename=baseFile)
                 while f == None:
                     f = rt.getSaveFileName(caption="Save as", filename=baseFile)
                 rt.saveMaxFile(f) if f != None else rt.messageBox("Save failed")                      
             else:
                 print("successfully saved the scene ")
         else:
             while f == None:
                 f = rt.getSaveFileName(caption="Save as", filename=baseFile)
             rt.saveMaxFile(f) if f != None else rt.messageBox("Save failed")
示例#7
0
 def _info(self, msg, *args, **kwargs):
     rt.messageBox(msg, title='Info')
示例#8
0
    def _exception(self, code, msg, *args, **kwargs):
        """Overriden Function"""

        rt.messageBox(msg, title=self.errorCodeDict[code])
        if (200 >= code < 210):
            raise Exception(code, msg)
    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)
示例#10
0
 def _importObj(self, filePath, importSettings, *args, **kwargs):
     if rt.pluginManager.loadclass(rt.ObjExp):
         # Set OBJ Options
         maxImp_obj = importSettings["objImportMax"]
         iniPath_importSettings = rt.objImp.getIniName()
         rt.setINISetting(iniPath_importSettings, "General", "UseLogging",
                          maxImp_obj["UseLogging"])
         rt.setINISetting(iniPath_importSettings, "General", "ResetScene",
                          maxImp_obj["ResetScene"])
         rt.setINISetting(iniPath_importSettings, "General", "CurrObjColor",
                          maxImp_obj["CurrObjColor"])
         rt.setINISetting(iniPath_importSettings, "General",
                          "MapSearchPath", maxImp_obj["MapSearchPath"])
         rt.setINISetting(iniPath_importSettings, "Objects", "SingleMesh",
                          maxImp_obj["SingleMesh"])
         rt.setINISetting(iniPath_importSettings, "Objects",
                          "AsEditablePoly", maxImp_obj["AsEditablePoly"])
         rt.setINISetting(iniPath_importSettings, "Objects",
                          "Retriangulate", maxImp_obj["Retriangulate"])
         rt.setINISetting(iniPath_importSettings, "Geometry", "FlipZyAxis",
                          maxImp_obj["FlipZyAxis"])
         rt.setINISetting(iniPath_importSettings, "Geometry",
                          "CenterPivots", maxImp_obj["CenterPivots"])
         rt.setINISetting(iniPath_importSettings, "Geometry", "Shapes",
                          maxImp_obj["Shapes"])
         rt.setINISetting(iniPath_importSettings, "Geometry",
                          "TextureCoords", maxImp_obj["TextureCoords"])
         rt.setINISetting(iniPath_importSettings, "Geometry",
                          "SmoothingGroups", maxImp_obj["SmoothingGroups"])
         rt.setINISetting(iniPath_importSettings, "Geometry", "NormalsType",
                          maxImp_obj["NormalsType"])
         rt.setINISetting(iniPath_importSettings, "Geometry", "SmoothAngle",
                          maxImp_obj["SmoothAngle"])
         rt.setINISetting(iniPath_importSettings, "Geometry", "FlipNormals",
                          maxImp_obj["FlipNormals"])
         rt.setINISetting(iniPath_importSettings, "Units/Scale", "Convert",
                          maxImp_obj["Convert"])
         rt.setINISetting(iniPath_importSettings, "Units/Scale",
                          "ConvertFrom", maxImp_obj["ConvertFrom"])
         rt.setINISetting(iniPath_importSettings, "Units/Scale", "ObjScale",
                          maxImp_obj["ObjScale"])
         rt.setINISetting(iniPath_importSettings, "Material",
                          "UniqueWireColor", maxImp_obj["UniqueWireColor"])
         rt.setINISetting(iniPath_importSettings, "Material",
                          "ImportMaterials", maxImp_obj["ImportMaterials"])
         rt.setINISetting(iniPath_importSettings, "Material",
                          "UseMatPrefix", maxImp_obj["UseMatPrefix"])
         rt.setINISetting(iniPath_importSettings, "Material", "DefaultBump",
                          maxImp_obj["DefaultBump"])
         rt.setINISetting(iniPath_importSettings, "Material",
                          "ForceBlackAmbient",
                          maxImp_obj["ForceBlackAmbient"])
         rt.setINISetting(iniPath_importSettings, "Material",
                          "ImportIntoMatEditor",
                          maxImp_obj["ImportIntoMatEditor"])
         rt.setINISetting(iniPath_importSettings, "Material",
                          "ShowMapsInViewport",
                          maxImp_obj["ShowMapsInViewport"])
         rt.setINISetting(iniPath_importSettings, "Material",
                          "CopyMapsToProj", maxImp_obj["CopyMapsToProj"])
         rt.setINISetting(iniPath_importSettings, "Material",
                          "OverwriteImages", maxImp_obj["OverwriteImages"])
         rt.importFile(filePath, rt.Name("NoPrompt"), using=rt.ObjImp)
         return True
     else:
         msg = "OBJ Plugin cannot be initialized. Skipping import"
         rt.messageBox(msg, title='Info')
         return False
示例#11
0
    def _exportAlembic(self,
                       filePath,
                       exportSettings,
                       exportSelected=True,
                       timeRange=[0, 10]):
        """
        Exports Alembic (.abc) file
        Args:
            filePath: (String) Absolute File path for exported file
            exportSettings: (Dictionary) settings file (see getExportSettings)
            exportSelected: (Boolean) If True, exports only currently selected objects, else whole scene. Default True

        Returns: (Boolean) True for success False for failure

        """
        # Set Alembic Options according to the Max Version:
        v = rt.maxVersion()[0]
        maxExp_abc = exportSettings["alembicExportMax"]

        # override animation related settings
        maxExp_abc["AnimTimeRange"] = "StartEnd"
        maxExp_abc["StartFrame"] = timeRange[0]
        maxExp_abc["EndFrame"] = timeRange[1]

        if v > 17000:  # Alembic export is not supported before 3ds Max 2016
            if rt.pluginManager.loadclass(rt.Alembic_Export):
                if 18000 <= v < 21000:  # between versions 2016 - 2018
                    rt.AlembicExport.CoordinateSystem = rt.Name(
                        maxExp_abc["CoordinateSystem"])
                    rt.AlembicExport.ArchiveType = rt.Name(
                        maxExp_abc["ArchiveType"])
                    rt.AlembicExport.ParticleAsMesh = maxExp_abc[
                        "ParticleAsMesh"]
                    rt.AlembicExport.CacheTimeRange = rt.Name(
                        maxExp_abc["AnimTimeRange"])
                    rt.AlembicExport.ShapeName = maxExp_abc["ShapeSuffix"]
                    rt.AlembicExport.StepFrameTime = maxExp_abc[
                        "SamplesPerFrame"]
                    rt.AlembicExport.AnimTimeRange = maxExp_abc[
                        "AnimTimeRange"]
                    rt.AlembicExport.StartFrame = maxExp_abc["StartFrame"]
                    rt.AlembicExport.EndFrame = maxExp_abc["EndFrame"]

                elif v >= 21000:  # version 2019 and up
                    rt.AlembicExport.CoordinateSystem = rt.Name(
                        maxExp_abc["CoordinateSystem"])
                    rt.AlembicExport.ArchiveType = rt.Name(
                        maxExp_abc["ArchiveType"])
                    rt.AlembicExport.ParticleAsMesh = maxExp_abc[
                        "ParticleAsMesh"]
                    rt.AlembicExport.ShapeSuffix = maxExp_abc["ShapeSuffix"]
                    rt.AlembicExport.SamplesPerFrame = maxExp_abc[
                        "SamplesPerFrame"]
                    rt.AlembicExport.Hidden = maxExp_abc["Hidden"]
                    rt.AlembicExport.UVs = maxExp_abc["UVs"]
                    rt.AlembicExport.Normals = maxExp_abc["Normals"]
                    rt.AlembicExport.VertexColors = maxExp_abc["VertexColors"]
                    rt.AlembicExport.ExtraChannels = maxExp_abc[
                        "ExtraChannels"]
                    rt.AlembicExport.Velocity = maxExp_abc["Velocity"]
                    rt.AlembicExport.MaterialIDs = maxExp_abc["MaterialIDs"]
                    rt.AlembicExport.Visibility = maxExp_abc["Visibility"]
                    rt.AlembicExport.LayerName = maxExp_abc["LayerName"]
                    rt.AlembicExport.MaterialName = maxExp_abc["MaterialName"]
                    rt.AlembicExport.ObjectID = maxExp_abc["ObjectID"]
                    rt.AlembicExport.CustomAttributes = maxExp_abc[
                        "CustomAttributes"]
                    rt.AlembicExport.AnimTimeRange = maxExp_abc[
                        "AnimTimeRange"]
                    rt.AlembicExport.StartFrame = maxExp_abc["StartFrame"]
                    rt.AlembicExport.EndFrame = maxExp_abc["EndFrame"]

                # Export
                rt.exportFile(filePath,
                              rt.Name("NoPrompt"),
                              selectedOnly=exportSelected,
                              using=rt.Alembic_Export)
                return True

            else:
                rt.messageBox("Alembic Plugin cannot be initialized. Skipping",
                              title="Alembic not supported")
                return False
        else:
            rt.messageBox(
                "There is no alembic support for this version. Skipping",
                title="Alembic not supported")
            return False
示例#12
0
    def _exportObj(self, filePath, exportSettings, exportSelected=True):
        """
        Exports wavefront Obj file
        Args:
            filePath: (String) Absolute File path for exported file
            exportSettings: (Dictionary) settings file (see getExportSettings)
            exportSelected: (Boolean) If True, exports only currently selected objects, else whole scene. Default True

        Returns: (Boolean) True for success False for failure

        """
        if rt.pluginManager.loadclass(rt.ObjExp):
            maxExp_obj = exportSettings["objExportMax"]
            # Set OBJ Options
            iniPath_exportSettings = rt.objExp.getIniName()
            rt.setINISetting(iniPath_exportSettings, "Geometry", "FlipZyAxis",
                             maxExp_obj["FlipZyAxis"])
            rt.setINISetting(iniPath_exportSettings, "Geometry", "Shapes",
                             maxExp_obj["Shapes"])
            rt.setINISetting(iniPath_exportSettings, "Geometry",
                             "ExportHiddenObjects",
                             maxExp_obj["ExportHiddenObjects"])
            rt.setINISetting(iniPath_exportSettings, "Geometry", "FaceType",
                             maxExp_obj["FaceType"])
            rt.setINISetting(iniPath_exportSettings, "Geometry",
                             "TextureCoords", maxExp_obj["TextureCoords"])
            rt.setINISetting(iniPath_exportSettings, "Geometry", "Normals",
                             maxExp_obj["Normals"])
            rt.setINISetting(iniPath_exportSettings, "Geometry",
                             "SmoothingGroups", maxExp_obj["SmoothingGroups"])
            rt.setINISetting(iniPath_exportSettings, "Geometry", "ObjScale",
                             maxExp_obj["ObjScale"])

            rt.setINISetting(iniPath_exportSettings, "Output", "RelativeIndex",
                             maxExp_obj["RelativeIndex"])
            rt.setINISetting(iniPath_exportSettings, "Output", "Target",
                             maxExp_obj["Target"])
            rt.setINISetting(iniPath_exportSettings, "Output", "Precision",
                             maxExp_obj["Precision"])

            rt.setINISetting(iniPath_exportSettings, "Optimize", "optVertex",
                             maxExp_obj["optVertex"])
            rt.setINISetting(iniPath_exportSettings, "Optimize", "optNormals",
                             maxExp_obj["optNormals"])
            rt.setINISetting(iniPath_exportSettings, "Optimize",
                             "optTextureCoords",
                             maxExp_obj["optTextureCoords"])

            try:
                rt.exportFile(filePath,
                              rt.Name("NoPrompt"),
                              selectedOnly=exportSelected,
                              using=rt.ObjExp)
                return True
            except:
                msg = "Cannot export OBJ for unknown reason. Skipping OBJ export"
                rt.messageBox(msg, title='Info')
                return False

            # objName = "{0}.obj".format(assetName)
        else:
            msg = "Wavefront(Obj) Export Plugin cannot be initialized. Skipping Obj export"
            rt.messageBox(msg, title='Info')
            return False
示例#13
0
 def _importRedshift(self, filePath, importSettings, *args, **kwargs):
     # TODO: // import redshift core function for 3ds Max
     rt.messageBox("Redshift Proxy Import for 3ds Max is under development",
                   title='Info')
示例#14
0
 def _importVray(self, filePath, importSettings, *args, **kwargs):
     # TODO: // import vray core function for 3ds Max
     rt.messageBox("Vray Proxy Import for 3ds Max is under development",
                   title='Info')
示例#15
0
def runMatSceneCleaner():
    global GLOBAL_IDENTICALS_MATS
    GLOBAL_IDENTICALS_MATS = []
    SceneMats = []
    UselessMats = []

    if MAXVERSION() < MAX2021:
        AllMatswProps = collections.OrderedDict([])
    else:
        AllMatswProps = {}

    originalsMats = []

    for matClass in rt.material.classes:
        for m in (rt.getclassinstances(matClass, processAllAnimatables=False, processChildren = True)):
            SceneMats.append(m)
        for mi in (rt.getclassinstances(matClass, processAllAnimatables=True, processChildren = True)):
            if mi not in SceneMats:
                UselessMats.append(mi)

    for i in range(len(SceneMats)):
        #if rt.classOf(SceneMats[i]) ==  rt.FlightSim:
        #if rt.classOf(SceneMats[i]) ==  rt.Physical_Material: //Uncomment if you wants to target specifics material types
        if MAXVERSION() < MAX2021:
            MatwProps = collections.OrderedDict([])
        else:
            MatwProps = {}
        propName = rt.getPropNames(SceneMats[i])
        for p in propName:
            param = rt.getProperty(SceneMats[i], p)
            MatwProps[p] = param
        AllMatswProps[SceneMats[i]] = MatwProps
            

    for mp in AllMatswProps:
        PropDicInallMapPropDic(mp, AllMatswProps[mp], AllMatswProps)


    for dbs in GLOBAL_IDENTICALS_MATS:
        MeshfromCopies = []
        DoublesMatswMultimatnID = []

        for dm in dbs.DoublesMats:
            print("[{0}] was a copy of [{1}], it has been removed and reassigned to [{1}]".format(dm,dbs.OrigMat))
            multMatsLinToCurDoublewID = material.getConnectedMultiMaterials(dm, True)
            if len(multMatsLinToCurDoublewID) != 0:
                DoublesMatswMultimatnID.append(multMatsLinToCurDoublewID)

            ndsfromMat = node.get_nodes_by_material(dm)
            for nfm in ndsfromMat:
                MeshfromCopies.append(nfm)

        for DMwM in DoublesMatswMultimatnID:
            for KeyMulToID in DMwM:
                material.assignMatToMutliMatFromID(KeyMulToID, dbs.OrigMat, DMwM[KeyMulToID])

        for mfc in MeshfromCopies:
            mfc.material = dbs.OrigMat

    rt.holdMaxFile()
    rt.fetchMaxFile(quiet = True)
    copyCounter = 0
    for dbs1 in GLOBAL_IDENTICALS_MATS:
        for dm1 in dbs.DoublesMats:
            copyCounter +=1
    rt.messageBox("Double Mat Scene Cleaner Tool finished. It has found and reasigned {0} materials duplicates".format(copyCounter))