-- Scene Info Browser for optimisation -- Rick Stirling, Rockstar North, October 2011 -- The original request from Aaron was -- Would it be possible to quickly knowck something up that displays the selections polycount, shader count, and a bunch of attributes… -- Lod distance -- Txd -- Low priority -- Don’t add to ipl ------------------------------------------------------------------------------------------------------------------------- -- This line loads the custom header filein (RsConfigGetWildWestDir() + "script/3dsMax/_config_files/Wildwest_header.ms") --sceneInfoUI = undefined -- declare the UI -- item to check, what we are looking for, test when a string (true = good, false = bad) abnormalDataChecks = #( --#("TXD", "CHANGEME",false), --#("Collision Group", "undefined",true), #("IPL Group", "undefined",true), #("Dont Export", true, false), #("Level Design Object", true, false), #("Is time object", true, false), #("Dont Add To IPL", true, false), #("Has Door Physics", true, false), #("Has Anim", true, false), #("Has UvAnim", true, false), #("Is Cloth", true, false), #("Dont cast shadows", true, false), #("padding",false,false) ) -- animation flags --is door --is level design object badgeoData =#() fn processgeo geoObj polyshaderusage = ( geoData=#() -- Parse the geo to get the polycount and shader data -- Create a virtual copy of the mesh as a trimesh for better stats tempdatamesh = snapshotAsMesh geoObj as TriMesh -- Polycount thepolycount = getnumfaces tempdatamesh append geoData thepolycount objMaterials = #() uobjMaterials = #() materialClass = classof geoObj.material if (materialClass == Multimaterial) then ( for facecount = 1 to thepolycount do ( face = getFace tempdatamesh facecount matid = getFaceMatId tempdatamesh facecount append objMaterials matid appendifunique uobjMaterials matid ) ) else ( append objMaterials "1" append uobjMaterials "1" ) shadercount = uobjMaterials.count append geoData shadercount -- find shaders with low poly usages lowpolyshaders=#() for spf = 1 to uobjMaterials.count do ( -- go through each used shader in turn theShaderID = uobjMaterials[spf] -- count the number of polys that use that. mycounter = 0 for pus = 1 to objMaterials.count do ( if objMaterials[pus] == theShaderID then mycounter+=1 ) -- Under the check amount? if mycounter < polyshaderusage then append lowpolyshaders theShaderID ) sort lowpolyshaders append geodata lowpolyshaders --return this: geoData ) -- read all geo in the scene to see if it's good fn selectAbnormalObjects = ( badgeoData =#() isbad = false -- find bad shit in the scene for selObj in geometry do ( -- Check attributes for abnormalcheckindex = 1 to abnormalDataChecks.count do ( selObjAttrib = readAttribute selObj abnormalDataChecks[abnormalcheckindex][1] false checkObjAttrib = abnormalDataChecks[abnormalcheckindex][2] tfcheck = abnormalDataChecks[abnormalcheckindex][3] reasondata = #(selobj, abnormalDataChecks[abnormalcheckindex][1]) if ((selObjAttrib == checkObjAttrib) and (tfcheck == false)) then appendifunique badgeoData reasondata ) -- Check children selKids = selobj.children kidcount = selKids.count for kidIndex = 1 to kidcount do ( thekid = selKids[kidIndex] -- is it a light? if superclassof thekid == light then appendifunique badgeoData (#(selobj,"LIGHT CHILD")) ) ) max unhide all clearSelection() for baddata in badgeoData do selectmore baddata[1] max hide inv clearSelection() ) fn populateUI = ( -- is anything selected? theSelection = getcurrentselection() if (theSelection.count > 0) do ( selObj = theSelection[1] if (classof selObj == Editable_mesh) or (classof selObj == Editable_poly) then ( --get geo data returnedgeodata = processgeo selObj sceneInfoUI.spnPolysPerShader.value -- Only look at the first object in the selection sceneInfoUI.edtSelObjectName.text = selObj.name sceneInfoUI.edtTXDName.text = (readAttribute selObj "TXD" false) sceneInfoUI.edtSelObjectPolycount.text = (returnedgeodata[1] as string) sceneInfoUI.edtSelObjectNumShaders.text = (returnedgeodata[2] as string) sceneInfoUI.edtLODVal.text = ((readAttribute selObj "LOD distance" false) as string) sceneInfoUI.edtLowPolyShaders.text = (returnedgeodata[3] as string) sceneInfoUI.chkAddToIPL.state = (readAttribute selObj "Dont Add To IPL" false) sceneInfoUI.chkLowPriority.state = (readAttribute selObj "Low Priority" false) sceneInfoUI.edtAbnormalReason.text = "" -- Try to report abnormal data here for baddata in badgeoData do ( if baddata[1] == selObj then (sceneInfoUI.edtAbnormalReason.text = baddata[2]) ) ) else -- not a valid geometry object ( sceneInfoUI.edtSelObjectName.text = selObj.name sceneInfoUI.edtTXDName.text = "NOT READABLE" sceneInfoUI.edtSelObjectPolycount.text = "UNKNOWN" sceneInfoUI.edtSelObjectNumShaders.text = "UNKNOWN" ) ) ) if sceneInfoUI != undefined then ( destroydialog sceneInfoUI ) ------------------------------------------------------------------------------------------------------------------------- rollout sceneInfoUI "Scene Info Browser" width:220 height:360 ( --hyperlink lnkHelp "Help?" address:"https://devstar.rockstargames.com/wiki/index.php/Scene_Info_Browser" align:#right color:(color 20 20 255) hoverColor:(color 255 255 255) visitedColor:(color 0 0 255) --Head button btnLogo tooltip:"Feedback" border:false align:#left offset:[0, 2] images:#("RockStarNorthLogo.bmp", "RockStarNorthLogo_Mask.bmp", 1, 1, 1, 1, 1, false) across:2 button btnHelp tooltip:"Help?" border:false align:#right offset:[0, 2] images:#("HelpIcon_32.bmp", "HelpIcon_32a.bmp", 1, 1, 1, 1, 1, false) groupbox grpHeader width:210 height:46 pos:[4, 0] group "Object Info" ( edittext edtSelObjectName "Object" text:"OBJECT NAME" fieldWidth:150 labelOnTop:false readOnly:true bold:false edittext edtTXDName " TXD" text:"TXD NAME" fieldWidth:150 labelOnTop:false readOnly:true edittext edtSelObjectPolycount "Polycount" text:"POLYCOUNT" fieldWidth:80 labelOnTop:true across:2 readOnly:true edittext edtSelObjectNumShaders "Shader count" text:"SHADER COUNT" fieldWidth:80 offset:[8, 0]labelOnTop:true readOnly:true edittext edtLODVal "LOD Distance" fieldwidth:50 readOnly:true spinner spnPolysPerShader "Poly:shader threshold" type:#integer fieldwidth:30 range:[0,500,50] align:#left edittext edtLowPolyShaders "" text:"SHADER LIST" fieldWidth:190 labelOnTop:true readOnly:true checkbox chkLowPriority "Low Priority" across:2 checkbox chkAddToIPL "Don't Add To IPL" ) --button btnGReadSelected "Read Selected Geo" width:170 height:25 button btnScenStats "Launch Scene Stats" width:210 height:25 button btnSelectAbnormal "Show Abnormal Objects" width:210 height:25 edittext edtAbnormalReason "Reason" text:"" fieldWidth:160 labelOnTop:false readOnly:true button btnCollisionReporter "Collision Mesh Reporter" width:210 height:25 on sceneInfoUI open do ( populateUI() ) on sceneInfoUI close do ( callbacks.removescripts #selectionsetchanged id:#sceneinfo ) -------------------------------------------------------------- --Launch help docs in browser -------------------------------------------------------------- on btnHelp pressed do ( process = dotnetobject "System.Diagnostics.Process" process.start "https://devstar.rockstargames.com/wiki/index.php/Scene_Info_Browser" process.dispose() ) on btnGReadSelected pressed do populateUI() on btnScenStats pressed do filein (theProjectToolsRoot + "/dcc/current/max2012/scripts/rockstar/helpers/scenestats.ms") on btnSelectAbnormal pressed do selectAbnormalObjects() on btnCollisionReporter pressed do filein (RsConfigGetWildWestDir() + "script/3dsMax/Maps/Optimization/Collision_mesh_reporter.ms") ) callbacks.addScript #selectionSetChanged "populateUI()" id:#sceneinfo createDialog sceneInfoUI