[Closed] Expand Material Library – More Efficient?
Can anyone suggest some ways to make this more efficient…
fn getSubMats themat theLibrary =
(
if finditem (for o in thelibrary collect o.name) themat.name == 0 do append thelibrary themat
for i = 1 to getNumSubMtls themat do
(
if (getSubMtl themat i) != undefined do thelibrary = getSubMats (getSubMtl themat i) theLibrary
)
theLibrary
)
fn expandMaterialLibrary thelib =
(
aMaterialLibrary = #()
for o in thelib do
(
getSubMats o aMaterialLibrary
)
aMaterialLibrary
)
testLib = (expandMaterialLibrary scenematerials)
- Don’t extract names on every iteration, store names in a separate array
- SceneMaterials may contain maps, which will throw an exception if you call GetNumSubMtls on them. I added superclass check against this.
- you can call GetSubMtl once instead of twice
fn getSubMats themat theLibrary libNames =
(
if finditem libNames themat.Name == 0 do
(
append thelibrary themat
append libNames theMat.Name
)
if superClassof theMat == material do
(
for i = 1 to getNumSubMtls themat do
(
local subMat = getsubMtl theMat i
if subMat != undefined do
(
thelibrary = getSubMats subMat theLibrary libNames
)
)
)
theLibrary
)
fn expandMaterialLibrary thelib =
(
aMaterialLibrary = #()
libNames = #()
for o in thelib do
(
getSubMats o aMaterialLibrary libNames
)
aMaterialLibrary
)
ts = timestamp()
expandMaterialLibrary sceneMaterials
print (timestamp()-ts)
mapped fn expandMaterials source target = try
(
for mat in source where iskindof mat material do
(
if (appendifunique target mat) do expandMaterials mat target
)
)
catch()
expandMaterials (join #() scenematerials) scenematerials
expand scenematerials into scenematerials is probably not a good idea. all ‘not scene materials’ will be wiped on next scene save action.
so the better way is to expand it to a temp library…
check by name is not right too. max allows to make materials with duplicated names… look at some architectural scenes… there are tons of multi-materials but all sub-materials are probably named: “window”, “wall”, “roof”, etc. (or “glass”, “bricks”, “concrete”, “grass”, etc.)
I am not sure which functions is correct, as I am getting different results with them. I get the same results from the functions from David and Rotem. For some reason they both seems to miss some materials in multimaterials.
Also the function from Denis as it is, seems to duplicate materials in the library.
Here is another function that runs faster for me and appears to collect all the materials in multimaterials, but I can’t tell if this one does what you need.
fn ExpandMaterialLibrary mLib =
(
materials = #()
for m in mLib where iskindof m material do
(
append materials m
for s = 1 to (getnumsubmtls m) where m[s] != undefined do append materials m[s]
)
materials
)
my function doesn’t duplicate materials… at least for my tests
can we make it faster? probably yes, but not dramatically. try/catch in this case shouldn’t take a time. all other things (append, search, etc.) we have to do anyway.
This is what I get:
(
mapped fn expandMaterials source target = try
(
for mat in source where iskindof mat material do
(
if (appendifunique target mat) do expandMaterials mat target
)
)
catch()
resetmaxfile #noprompt
for j = 1 to 10 do sphere material:(multimaterial numsubs:25)
format "scene materials:%
" scenematerials.count
expandMaterials (join #() scenematerials) scenematerials
format "scene materials:%
" scenematerials.count
)
Before runing your function:
scene materials:10
After runing your function
scene materials:260
well… try takes a time… so modified looks this way
mapped fn expandMaterials source target =
(
for k=1 to getnumsubmtls source where iskindof (mat = getsubmtl source k) material do
(
if (appendifunique target mat) do expandMaterials mat target
)
)
expandMaterials (join #() scenematerials) scenematerials
aa = makeuniquearray (join #() scenematerials)
format "% %
" scenematerials.count aa.count
Here is a simple test case and the results I am getting:
(
fn ExpandMaterialLibrary mLib =
(
materials = #()
for m in mLib where iskindof m material do
(
append materials m
for s = 1 to (getnumsubmtls m) where m[s] != undefined do append materials m[s]
)
materials
)
resetmaxfile #noprompt
for j = 1 to 100 do sphere material:(multimaterial numsubs:25)
gc()
st = timestamp(); sh = heapfree
lib = ExpandMaterialLibrary scenematerials
format "time:% ram:% mats:%
" (timestamp()-st) (sh-heapfree) lib.count
)
time:4 ram:14024L mats:2600
These are the results from the other functions:
David
time:1611 ram:88103480L mats:2501
Rotem
time:94 ram:367240L mats:2501
Notice the difference in the materials gathered.
Thanks Jorge, sorry for delayed response I finally got around to actually using this!
Found a bug in your code where material[i] would retrieve subanims for undefined submaps. This works instead…
fn ExpandMaterialLibrary mLib =
(
materials = #()
for m in mLib where iskindof m material do
(
append materials m
for s = 1 to (getnumsubmtls m) where (getsubmtl m s) != undefined do append materials (getsubmtl m s)
)
materials
)
And yes Denis I didn’t really want to expand the Scene Materials into itself, only into a temporary library so Jorge’s solution works great!