[Closed] Find material by bitmap name
Hello Guys.
Somebody knows how to select material by bitmap name.
Imagine i type the name of a bitmap or a part of it in a edittext and i have all material that use this bitmap in a listbox.
I have a chunk of code but i’am oblige to precise in which material slot to search.
For Ex: filenamefrompath ($object.material.diffusemap.filename). The only way i find to search the bitmap. I want a code line to search in the entire material slot to find the bitmap.
Somebody knows how to do it ?
Thank You for your help guys
atleast with standard material you can use this
$object.material.maps[i].filename
where i = 0 – 11
Hello justdintdoit !!
Thanks a lot for your trick.
I test it but when it scan the slot, if i don’t have a bitmap in the map numbered slot it search. The code makes me an error. Like: “Unknown property: “filename” in undefined”.
In map slot where there is a map it works greatfully.
This bug don’t allow me to scan all of the slots. 🙁
You or somedbody know how pass through it ?
try something as:
if $object.material.diffusemap.filename != undefined then
you could try parsing through a material using its “getnumsubmtls” and “getnumsubtexmaps”
I used it in this script. You might want to take a look at the code… but I guess it would look messy as an example because there a lot of other stuff going on inside that are only really relevant to the whole script structure…
But the backbone of it is to create two functions. the first function is used to dig through a materials’ sub properties, then the other one is used to dig through a texturemaps’ sub properties…
you would first run it through a MATERIAL, then look for submaterials using the “getnumsubs”. then if you found one, look for sub submaterials again using the same function… something like this:
fn lookForMat mat =
(
submatcount = getnumsubmtls mat
if submatcount != 0 do
(
for i in 1 to submatcount do
(
the_submat = getsubmtl mat i
if the_submat != undefined do
(
print the_submat.name
lookForMat the_submat
)
)
)
)
lookForMat meditmaterials[1]
create a material structure on slot 1 (multisub with blend, with shellac etc…) run the script and it will print the names of all the materials and submaterials of those materials to the listener, no matter how deep they are in the hierarchy. (this is called a recursive funtion)
Then you could do the same with texturemaps… so after recursing(?) through the texturemaps, you could then pass on a checking function which will check if the texturemap is a bitmap class, and if .filename property is what you’re looking for, you could then exit the function…
hope this helps!
oops, got it working as a single function…
(I forgot that i needed to separate it last time for some scripting reasons that i cant even remember, hehe)
fn lookForMatMap matmap =
(
submatcount = try(getnumsubmtls matmap)catch(0)
if submatcount != 0 do
(
for i in 1 to submatcount do
(
the_submat = getsubmtl matmap i
if the_submat != undefined do
(
print the_submat.name
lookForMatMap the_submat
)
)
)
submapcount = getnumsubtexmaps matmap
if submapcount != 0 do
(
for j in 1 to submapcount do
(
the_submap = getsubtexmap matmap j
if the_submap != undefined do
(
print the_submap.name
lookForMatMap the_submap
)
)
)
)
lookForMatMap meditmaterials[1]
This code would print out all the names of submaterials and subtexturemaps of a given material.
I suppose I’ll be busy rewriting stuff in the weekends…
Thank galagast for your help.
Your code works. I analyse it to understand how to make a function. I don’t understand yet.
In fact, i want to work with filename and path on the hard disk.
When i search a bitmap, this is with the name of it : like “grass.jpg”, you know.
because if in a list i have fifty path like “\server\data\maps\ground\grass.jpg”, it’s difficult to find a map. So i use “filenamefrompath” to have only maps names in my “Maps list”.
And i want to get all materials that use this map (grass.jpg) in a “material list” like i click on it in the “Maps list”. For that i must scan “filenamefrompath” in all texture slots in a material to see if the map is used and “collect” them in a array i’ll use in my “material list”.
My code works for diffusemap only. Because i don’t know how to scan other slot in the same time.
do you understand my problem ?
I’am stuck in my code because of that.
I think, like you said, i must write a function to walk in all slot of any kind of material and use a for loop to walk in all material in the scene.
Thank you for your lights
no problem… I’ll write down some comments for the fuction line by line…
1 fn lookForMatMap matmap =
2 (
3 submatcount = try(getnumsubmtls matmap)catch(0)
4 if submatcount != 0 do
5 (
6 for i in 1 to submatcount do
7 (
8 the_submat = getsubmtl matmap i
9 if the_submat != undefined do
10 (
11 print the_submat.name
12 lookForMatMap the_submat
13 )
14 )
15 )
-- the lines after this basically works like the above
)
lookForMatMap meditmaterials[1]
[color=cyan]1 fn lookForMatMap matmap =[/color]
Funtions can be your best friend when writing scripts.
Try out this test rollout and have a glimpse of the power of funtions…
rollout test "Funtion Test" width:160 height:170
(
checkbutton btn1 "1" pos:[5,5] width:150 height:20
checkbutton btn2 "2" pos:[5,30] width:150 height:20
checkbutton btn3 "3" pos:[5,55] width:150 height:20
checkbutton btn4 "4" pos:[5,80] width:150 height:20
checkbutton btn5 "5" pos:[5,105] width:150 height:20
label lbl "" pos:[10,140] width:140 height:20
groupBox grp "" pos:[5,125] width:150 height:40
fn PressAll state =
(
btn1.checked = \
btn2.checked = \
btn3.checked = \
btn4.checked = \
btn5.checked = state
txt = if state then "All Buttons Pressed"
else "No Buttons Pressed"
lbl.caption = txt
)
on btn1 changed state do PressAll state
on btn2 changed state do PressAll state
on btn3 changed state do PressAll state
on btn4 changed state do PressAll state
on btn5 changed state do PressAll state
)
createDialog test
Imagine if you didnt have functions, you would have had to write eveything (5 times) inside the buttons’ change event handler in order to get this effect. But with the help of a function, you only needed to write it once, then just distribute it to you button handlers.
So for the aforementioned line, the “lookforMat” funtion is defined, and it needs a “mat” value containing preferably a Material passed onto it in order to work.
[color=cyan]3 submatcount = try(getnumsubmtls matmap)catch(0)[/color]
- we create a variable called “submatcount”
- here, we need it to contain integer number values
- getnumsubmtls is an example of a function that comes with maxscript, it reads the number of submaterials that a material has.
For example, if you specify a blend material:
getnumsubmtls myBlendMat
It would definitely return an integer number of 2 [font=Verdana][color=white]because a Blend Material would always only contain 2 sub-materials.[/color][/font] - the [color=yellow]try()catch() sort of works like error catchers, whenever an error occurs, you could do something about it[/color]
For example,
try(…do somthing here that would cause an error…)
catch(…in here, if an error occured while trying, you can do something here…)
try(print $imaginary_obect.name)catch( 1 + 1 )
if you run this code, it will always return 2 unless you really do have an object named “imaginary object” on your scene.
- so for line 3, in case the value of matmap cannot contain submaterials, it would return 0 instead of an error or undefined.
[color=cyan]4 if submatcount != 0 do[/color]
- this line would check if the material that you passed has some submaterials slots in it. Now if the submatcount is not ZERO, it means that it found some submaterials slots.
For example, a blend, shellac and a two sided material has 2 submaterial slots each, whereas a composite material has 10, and a multi-material can have as many as 1000 or more!
[color=cyan]6 for i in 1 to submatcount do[/color]
[color=cyan]8 the_submat = getsubmtl matmap i[/color]
- line 6 would now start a loop, and it would loop through the number of sub materials.
- then on line 8, we use another function called “getsubmtl” which would let you acquire the actual sub-material of the material that you passed… and it gets it by index.
For example, on a Double Sided Material,
getsubmtl my2SidedMat 1
would return the Facing Material
getsubmtl my2SidedMat 2
would return the Back Material - for line 8, we also set a variable “the_submat” in which we would store the sub-material returned…
[color=cyan]9 if the_submat != undefined do[/color]
- this line would now check if there really is a material, assigned to the slot… because sometimes, a slot can contain a “noMaterial()” or an undefined value.
[color=cyan]11 print the_submat.name[/color]
[color=cyan]12 lookForMatMap the_submat[/color]
- now, the whole process would only reach this far if it found an existing submaterial for the material that you passed on the function…
- for line 12, since a submaterial is still considered as a “Material”… why not check if it also has a submaterial of its own? Now THIS is where we’ll re-use the very same lookForMatMap function to check for it, and so the process repeats to line 1. From here onwards, the function is now considered recursive.
I hope this helps!
Hello Galagast.
Thank you so much for your explanations
It’s very useful
Thanks, thanks, thanks.
Hello Guys !!
I need your help, again, Galagast or Bobo, or the two in the same time
I use your code to make a function but it make me an error
This is my code:
fn scanslots mat =
(
-- Search in MultiSub Material
if matclassid == "#(512, 0)" do
(
MultiSubMatCount = try(getnumsubmtls mat)catch(0)
if MultiSubMatCount != 0 do
(
for i in 1 to MultiSubMatCount do
(
MultiSubMat = getsubmtl mat i
if MultiSubMat != undefined do
(
Scanslot MultiSubMat
)--end if
)--end for
)--end if
)--end fn
But when i make evaluate, makes me an error:
– Compile error: No outer local variable references permitted here: scanslot
– In line: Scanslot M
Do you have an idea of what happens ?
Thank for your lights