PDA

View Full Version : Find material by bitmap name


BebeteLANUITE
02-15-2006, 09:53 PM
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 ;)

justdintdoit
02-15-2006, 10:04 PM
atleast with standard material you can use this

$object.material.maps[i].filename

where i = 0 - 11

BebeteLANUITE
02-16-2006, 09:30 AM
Hello justdintdoit !! :thumbsup:

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. :sad:

You or somedbody know how pass through it ?

justdintdoit
02-16-2006, 10:03 AM
try something as:

if $object.material.diffusemap.filename != undefined then

galagast
02-16-2006, 10:20 AM
you could try parsing through a material using its "getnumsubmtls" and "getnumsubtexmaps"

I used it in this (http://forums.cgsociety.org/showthread.php?t=317640) 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!

galagast
02-16-2006, 10:59 AM
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...

BebeteLANUITE
02-17-2006, 07:53 AM
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 :thumbsup:

galagast
02-17-2006, 10:16 AM
no problem.. I'll write down some comments for the fuction line by line..:thumbsup:


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]


1 fn lookForMatMap matmap =
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.

3 submatcount = try(getnumsubmtls matmap)catch(0)
- 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 because a Blend Material would always only contain 2 sub-materials.
- the try()catch() sort of works like error catchers, whenever an error occurs, you could do something about it
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.

4 if submatcount != 0 do
- 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!

6 for i in 1 to submatcount do
8 the_submat = getsubmtl matmap i
- 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...

9 if the_submat != undefined do
- 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.

11 print the_submat.name
12 lookForMatMap the_submat
- 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! :)

BebeteLANUITE
02-22-2006, 09:53 AM
Hello Galagast.

Thank you so much for your explanations ;)
It's very useful ;)

Thanks, thanks, thanks. :thumbsup:

BebeteLANUITE
03-07-2006, 11:15 AM
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 :thumbsup:

galagast
03-08-2006, 01:43 AM
im not sure if you've pasted it wrong, but i can see that you defined your funcion as "scanslots" with an "s", but you called it inside "Scanslot" recursively without an "s"... that might be the cause of problem. :)

BebeteLANUITE
03-08-2006, 07:44 AM
Hello Galagast :thumbsup:

yes i made a wrong paste. i put a good here.
I don't understand why it doesn't work. its your code i just change the name. I test your code alone and it work perfectly.
That's a bit weird. :surprised


fn scanslots mat =
(
-- Search in Blend Material
if matclassid == "#(592, 0)" do
(
Global BlendSubMatCount = try(getnumsubmtls mat) catch(0)
if BlendSubMatCount != 0 do
(
for i in 1 to BlendSubMatCount do
(
global BlendSubMat = getsubmtl mat i
if BlendSubMat != undefined do
(
--print (getsubmtl mat i)
scanslots BlendSubMat
)--end if
)--end for
)--end if
)--end if
)--end fn scanslots


Thanks for your help galagast ;)

BebeteLANUITE
03-08-2006, 07:51 AM
OH NOOOOO !!! :surprised :surprised :surprised

I find the way.
In fact, i made a big function with a lot of "if" and in each "if" i recall the "scanslots" function. It seem that a function can only have one recalling to make it recursively.

This is my function:

fn scanslots mat =
(
global matclassid = (mat.classid as string)

-- Search in Standard Material
if matclassid == "#(2, 0)" do
(
global MatSubMaps = getnumsubtexmaps mat
global SimilarMaps = for i = 1 to Matsubmaps where mat.maps[i] != undefined and pathdisp.text == mat.maps[i].filename do
(
append CorrespMats (mat as string)
)--end for
)--end if

-- Search in Raytrace Material
if matclassid == "#(655953908, 849023086)" do
(
global RayMatSubMaps = getnumsubtexmaps mat
global RaySimilarMaps = for i = 1 to RayMatSubMaps where mat.maps[i] != undefined and (mat.maps[i].classid as string) == "#(576, 0)" and pathdisp.text == mat.maps[i].filename do
(
append CorrespMats (mat as string)
)--end for
)--end if

-- Search in Blend Material
if matclassid == "#(592, 0)" do
(
Global BlendSubMatCount = try(getnumsubmtls mat) catch(0)
if BlendSubMatCount != 0 do
(
for i in 1 to BlendSubMatCount do
(
global BlendSubMat = getsubmtl mat i
if BlendSubMat != undefined do
(
--print (getsubmtl mat i)
scanslots BlendSubMat
)--end if
)--end for
)--end if
)--end if

-- Search in MultiSub Material
if matclassid == "#(512, 0)" do
(
Global MultiSubMatCount = try(getnumsubmtls mat) catch(0)
if MultiSubMatCount != 0 do
(
for i in 1 to MultiSubMatCount do
(
global MultiSubMat = getsubmtl mat i
if MultiSubMat != undefined do
(
--print (getsubmtl mat i)
scanslots MultiSubMat
)--end if
)--end for
)--end if
)--end if
)--end fn


If i delete one of the two "scanslots" recall the function works. If i let the two, it makes me an error.
This is a function to scan all slot in a material and if the material is a multimat it scan the slot to find a standard or a raytrace mat. If it find a multimat or a blendmat in the slot, it recall the function to rescan all the slot.
if the user put 50 submultimats the function is able to find it.
But if a can't put two or more recalling of the function it this one, its a problem for me. Because if in a slot of a multimat, there is a blend mat, the function don't see it because it search only a multimat.

I know it for after :D

CGTalk Moderation
03-08-2006, 07:51 AM
This thread has been automatically closed as it remained inactive for 12 months. If you wish to continue the discussion, please create a new thread in the appropriate forum.