[Closed] Newmat = oldmat as newmat?
How can I say…
mat1 = $Plane01.material
mat2 = mat1
mat2.diffuse = color 0 0 0
$plane02.material = mat2
Without mat1’s diffuse becoming 0 0 0 as well?
wouldn’t you just make a copy? Right now you’re essentially making an instance.
mat2 = copy mat1
It needs to be a copy but not an instance as i’m using the same material 128 times just with slight variations in parameters.
i had the exact same problem. Thanks for the simple tip. Sometimes it is hard to find the simplest thing in the mxs reference. only because I don’t know how to ask the right questions.
I have a more complicated question. How do I search for a specific map in all possible submap locations in a selection of objects or an entire scene?
We have been using multisubMap in Max9 and the author has yet to compile a 2k9 version. I would like to replace it with the similar one from Adam Grant but there is no Max 9 version (only 2k9) so it’s pointless to write a script when one of the two plugins are missing.
Anyway, I think I can build a script to create a MultiMaterial using the array of submaps from the multisubMap.
it looks like this now
theMat = $.material
submaps =(theMat.diffusemap.src_tex.mapList)
theCount = submaps.count
newMulti = multimaterial name:((theMat.name as string) + "_NEW") numsubs:theCount
setMeditMaterial 2 newMulti
for i in 1 to theCount do
(
newMat = copy theMat
newMat.texmap_diffuse = submaps[i]
setSubMtl newMulti i newMat
)
Depends on how you need it, and how you’re identifying it…
For the entire scene… say you only know the map’s name (“myGradient”) and map type (Gradient)
First figure out the class name of a gradient map
-- make a gradient map in the first medit slot and run this line
classof meditmaterials[1]
That should give you ‘Gradient’. I know, pretty logical, but sometimes they’re not quite that logical.
Then get all of the maps that are of that class…
allGradientMaps = getClassInstances Gradient
That should return an array #() with all the Gradient maps.
Now just loop over all of them, and grab all those that are named ‘myGradient’.
myMaps = for m in allGradientMaps where (m.name == "myGradient") collect ( m )
Which will return another array with all the Gradient maps named “myGradient”
What you do with them after that… depends on what you need to do.
Could figure out one of the locations it’s stored in in a natural form (sure wish this would return an array)
exprForMaxObject allGradientMaps[1]
"$GeoSphere01.material[#Maps][#Diffuse_Color__myGradient____Gradient]"
Or all of the things that depend on that map…
print (refs.dependents allGradientMaps[1])
ReferenceTarget:ReferenceTarget
02 - Default:Standard
$GeoSphere:GeoSphere01 @ [64.575645,0.000000,-1.845019]
#materialLibrary()
ReferenceTarget:Scene
But I’m not quite sure any of that is what you’re looking for
All of it is useful for sure. Having the array of the specific class is key.
The map is called MultiSub_Map(its class as well). It is like MultiMaterial except it’s a map. Very handy for multisubs where only one map is different and all of the parameters of the material are the same.
Take leaves for instance. Ten different colored leaves means ten different materials with MultiMaterial. If I want to change the translucency, I either have to do it ten times or wire all of the parameters of the ten different materials together.
With MultiSub Map this issue is greatly simplified by putting a map with 10 MatIDs in the diffuse slot. easy.
Anyway, there are two plugins that do this. One is only available in Max9 the other is only available in max2009. We are transitioning to 2009 and I am trying to write a script to translate our Max9 materials that use this map to something that will show open in Max2009 with no missing dll errors.
I need to store the structure of the map tree from Max9 then rebuild it in 2009 using the plugin that is actually available.
I have contacted the author of the Max9 plugin and he will try to recompile it after his vacation. Which would solve our problems.
But I would still like to write this script. I learn so much by these little challenges.
Thanks for the help. I’ll post what I can, when I can.
I think you’re looking at a two-part approach.
MultiSubMap is not available for 3ds Max 2009 (yet)
MutlIDMap2 is not available for 3ds Max 9 (inexplicably, as 7/8 and 2008/2009) are present.
Edit: “not”. I keep making that typo (not -> now); boy does that cause some confusion!
So you can’t transfer the data directly.
- Loading a 3ds Max 9 scene with MultiSubMap will cause a missing plugin warning, and you can’t access the submaps it uses.
- Similarly, you can’t load a 3ds Max 2009 scene into 3ds Max 9, period. Even if you could, you would just run into the same problem of missing plugins and their data being unavailable.
So the first bit to recognize is that you will have to store the data in 3ds Max 9 in a way that you can use it in 3ds Max 2009. There’s several ways you could do that – you could stick them in a composite map, you could create a custom attribute holder with a texturemapTab parameter, you could get goofy with a material library file, but I think the simplest approach is to go with a persistent global variable*, simply storing two arrays:
- a reference the original old materials
- references to the original old materials’ sub-maps.
- Persistent global variables are frowned upon, especially given that custom attributes are available, but for quick and dirty tasks as well as any storage of mixed data, they’re very useful indeed.
Here’s what that, Part 1, looks like… as usual, don’t enter the blue bits – they’re just feedback in the MaxScript Listener to give you some idea of what sort of result you should be expecting. The green bits are just comments – feel free to enter them, but there’s not much use in doing so
-- set up the variable that holds all the MultiSubMaps
persistent global myMultiSubMaps
undefined
[color=Green]-- Collect all the MultiSubMaps into that variable as an array
[/color]myMultiSubMaps = getClassInstances MultiSub_Map
#(Map #1:MultisubMap, Map #2:MultisubMap)
[color=Green]-- Another variable for the actual sub-maps
[/color]persistent global myMultiSubMaps_SubMaps
undefined
[color=Green]-- loop over the array of MultiSubMaps collected
[/color]myMultiSubMaps_SubMaps = for m in myMultiSubMaps collect (
-- loop over its mapList, and collect each map
-- (can't use the .mapList result itself, as that returns an ArrayParameter
-- which would be lost when loading into 3ds Max 2009)*
for sm in m.mapList collect ( sm )
)
#(#(Map #3:Gradient, Map #4:Mix), #(Map #5:Noise, Map #6:Speckle, Map #7:Tiles))
- You could still get the sub-maps, even if the map and the ArrayParameter is lost, using refs.dependsOn; but I’m not too sure order is preserved – better to take a safe route.
Now you’ve got two arrays that have parity to eachother (e.g.
the maps specified in myMultiSubMaps_SubMaps[3] are the sub-maps from the map in myMultiSubMaps[3]), stored as a persistent global variable in memory.
Save the file in 3ds max 9.
Open the same file in 3ds Max 2009. You will get that missing plugin warning, which you can just disregard.
If you now check the persistent global variables, you’ll see they return the maps and their submaps. The maps will be of a Missing_TextureMap class, but that’s okay… we’re only interested in the references it holds internally (which materials use it, what appdata may be set on them, etc. Stuff 3ds Max tracks on the maxwrapper (the map plugin) that isn’t part of the maxwrapper’s own data).
myMultiSubmaps
#(Map #13:Missing TextureMap, Map #14:Missing TextureMap)
myMultiSubmaps_SubMaps
#(#(Map #3:Gradient, Map #4:Mix), #(Map #5:Noise, Map #6:Speckle, Map #7:Tiles))
Excellent, so now for part 2 – replacing those MultiSubMap maps (as Missing TextureMaps) with MultiIDMap2 maps.
This is nearly the easy part, except that MultiIDMap2 does not use a mapList-style Array Parameter. It holds 15 maps at any given time – no less, no more – and each is accessed via a parameter name; .map1 through .map15. That’s a little inconvenient as we’ll want to use indices to set the parameters, but using getPropnames we can collect those parameter names as an array.
After that, we can simply:
- loop over the old MultiSubMap references
- build a new MultiIDMap2 map with the old MutlSubMap’s name
- set up the subMaps in the new MultiIDMap2 by setting parameter N to
myMultiSubmaps_SubMaps[N] - replace the old MultiSubMap with the new MultiIDMap2 reference using replaceInstances()
-- get the parameter (property) names of a MultiIDMap2 as an array
MultiIDMap2_propNames = for p in (getPropNames MultiIDMap2) collect ( p )
#(#map1, #map2, #map3, #map4, #map5, #map6, #map7, #map8, #map9, #map10, #map11, #map12, #map13, #map14, #map15)
-- loop over the old multiSubMaps
for i = 1 to myMultiSubmaps.count do (
-- get the old multiSubMap reference
oldMap = myMultiSubmaps[i]
-- get its sub-maps from the sub-maps array
oldMap_SubMaps = myMultiSubMaps_SubMaps[i]
-- create the new map, set up the name while we're at it
newMap = MultiIDMap2 name:oldMap.name
-- loop from 1 to however many sub-maps there were (with a maximum of 15)
for i = 1 to (amin oldMap_SubMaps.count 15) do (
-- set up the sub-map in the appropriate parameter of the new MultiIDMap2
setProperty newMap MultiIDMap2_propNames[i] oldMap_SubMaps[i]
)
-- and replace the old multiSubMap
replaceInstances oldMap newMap
)
OK
And you’re pretty much all done… ready to save the scene (under a new filename, just in case!).
There is, of course, one more thing you should do: There’s still that set of persistent global variables, one of which holds a reference to a plugin that’s missing. Anytime you would open the file, you would get the missing plugin warning – and not even know where on Earth it’s coming from (unless you happen to remember). So it’s best to remove them:
persistents.remove #myMultiSubMaps
OK
persistents.remove #myMultiSubMaps_SubMaps
OK
Now you should really be all done
Obviously there’s some fancying up to do – like printing out a warning if your old map does have more than 15 sub-maps, but for basic functionality… I think the above is it.
HOLY EPIC REPLY!!
i’m just getting off work at 5:20 AM.
I just wanted to say thanks for the effort!!!
i’ll look at this when I’m more awake and coherent.