-- Tool to split collision meshes into sub groups to improce memory in game -- Rick Stirling -- Rockstar North filein (RsConfigGetWildWestDir() + "script/3dsMax/_config_files/Wildwest_header.ms") -- Define the size in bytes for each collision type -- Meshes are complicated, that's handled in a function Col_SphereCosts = 112 Col_BoxCosts = 112 Col_CapsuleCosts = 128 Col_CylinderCosts = 128 -- Takes and object and builds an array of the collision objects attached to it fn build_collision_array meshobj = ( -- Grab all the child objects childArray =#() childArray = heirarchyWalk meshobj collisionArray = #() for childItem in childArray do ( childType = classof childItem case childType of ( Col_Mesh : append collisionArray childItem Col_Sphere : append collisionArray childItem Col_Box : append collisionArray childItem Col_Capsule : append collisionArray childItem Col_Cylinder : append collisionArray childItem ) ) collisionArray --return the collisionArray ) -- Take a collision mesh and return the cost in bytes fn get_coll_Mesh_cost collisionItem = ( -- Formula from Eugene -- 224 + 16 * (number of polys) + 6 * number of verts + a few more bytes for material array, octant map and such tempdatamesh = getColMesh collisionItem thepolycount = getnumfaces tempdatamesh thevertcount = getnumverts tempdatamesh basemeshcost = 224 colltricost = 16 * thepolycount collvertcost = 6 * thevertcount extrabytes = 20 calculatedmeshcost = basemeshcost + colltricost + collvertcost + extrabytes calculatedmeshcost --return calculatedmeshcost ) -- Take an objects collision data and calculate the collision costs for it fn get_collision_costs collisionArray = ( -- Firstly build the array of collision objects for the mesh collisionBytes = 0 -- Get the costs in Bytes from each child collision item -- Byte size provided by Eugene Foss for collisionItem in collisionArray do ( localCollisionCosts = 0 collisionType = classof collisionItem -- Get the cost of each type case collisionType of ( Col_Mesh : localCollisionCosts = (get_coll_Mesh_cost collisionItem) Col_Sphere : localCollisionCosts = Col_SphereCosts Col_Box : localCollisionCosts = Col_BoxCosts Col_Capsule : localCollisionCosts = Col_CapsuleCosts Col_Cylinder : localCollisionCosts = Col_CylinderCosts ) -- Increment the running total collisionBytes = collisionBytes + localCollisionCosts ) collisionBytes -- return the memory costs ) fn get_collision_breakdown meshobj = ( collisionArray = #() collisionArray = (build_collision_array meshobj) collisionBytes = get_collision_costs collisionArray collisionKBBytes = (collisionBytes as float)/1024 --collisionKBBytes = (collisionBytes as float)/1000 meshCollisionGroup = (readAttribute meshobj "Collision Group" true) --print ("Mesh object = " + meshobj.name) --print ("Collision group = " +(meshCollisionGroup as string)) --print ("Number of collision elements = " +(collisionArray.count as string)) --print ("Collision size in bytes = " + (collisionBytes as string)) --print ("Collision size in kilobytes = " + (collisionKBBytes as string)) collisionstats = #() append collisionstats meshobj append collisionstats collisionArray append collisionstats meshCollisionGroup append collisionstats collisionKBBytes collisionstats -- return this ) fn collect_collision_groups tempmeshArray = ( collisionGroupArray = #() for themesh in tempmeshArray do ( local colldata = #() append colldata themesh.name meshCollisionGroup = (readAttribute themesh "Collision Group" true) append colldata meshCollisionGroup append collisionGroupArray colldata ) collisionGroupArray ) try( destroyDialog collisionSizeTool )catch() rollout collisionSizeTool "Collision Size Tool" ( dotNetControl rsBannerPanel "Panel" pos:[0,0] height:32 width:collisionSizeTool.width local banner = makeRsBanner dn_Panel:rsBannerPanel wiki:"Collision Size Tool" filename:(getThisScriptFilename()) on collisionSizeTool open do banner.setup() button btnSelectAllGeo "(Select All Geo)" width:160 height:30 tooltip:"Select all geo in the scene. A quick way to grab stuff" button btnAnalyseSelected "Analyse Selected Geo" width:160 height:30 tooltip:"Analyse collision on selected geo" spinner spnKBthreshold "Object KB Threshold" range:[0,48,16] type:#integer width:150 fieldwidth:40 tooltip:"kb threshold for new groups" button btnnewCollGroupLO "Object collision by threshold" width:160 height:30 tooltip:"New groups by threshold" spinner spnKBthresholdNG "Group KB Threshold" range:[0,128,64] type:#integer width:150 fieldwidth:40 tooltip:"kb threshold for new groups" button btnnewCollGroupOG "Selected > groups by threshold" width:160 height:30 tooltip:"New groups by threshold" local allcollisionstats = #() on btnSelectAllGeo pressed do ( clearSelection() for theobj in geometry do selectmore theobj ) on btnAnalyseSelected pressed do ( Tcollisionstats = #() -- Collect the collision data for the selected objects for selmeshobj in selection do ( if superClassOf selmeshobj == GeometryClass then ( collisionstats = (get_collision_breakdown selmeshobj) append Tcollisionstats collisionstats ) ) -- Sort and reverse this data to make the highest collision first in the list qsort Tcollisionstats sortArraybySubIndex subIndex:4 allcollisionstats = (for i=Tcollisionstats.count to 1 by -1 collect Tcollisionstats[i]) -- Punt this out to a debug window debugWindow = newScript() for collentry in allcollisionstats do ( format "Name: %, collision (kb): %, collision group: %\n" (collentry[1].name) collentry[4] collentry[3] to:debugWindow ) ) -- end button -- if an object is higher than the threshold, give it a new collision group using the objectname on btnnewCollGroupLO pressed do ( for collentry in allcollisionstats do ( objcollsize = collentry[4] if objcollsize > collisionSizeTool.spnKBthreshold.value then ( themesh = collentry[1] themeshname = themesh.name newcolgroup = themeshname+ "_collision" setAttribute themesh "Collision Group" newcolgroup ) ) ) -- end button -- split objects into a new group -- if an object selection is higher than the threshold, give it a new collision group using the groupname on btnnewCollGroupOG pressed do ( cumulativesize = 0 collgroupsuffix = 1 for collentry in allcollisionstats do ( objcollsize = collentry[4] cumulativesize = cumulativesize + objcollsize if cumulativesize > collisionSizeTool.spnKBthresholdNG.value then ( collgroupsuffix = collgroupsuffix + 1 cumulativesize = 0 ) collgroupname = (allcollisionstats[1][1].name) + "_coll_" + (collgroupsuffix as string) themesh = collentry[1] setAttribute themesh "Collision Group" collgroupname ) ) -- end button ) createDialog collisionSizeTool 180 300