273 lines
7.2 KiB
Plaintext
Executable File
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
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|