Files
2025-09-29 00:52:08 +02:00

273 lines
7.2 KiB
Plaintext
Executable File

-- 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