thanks a lot guys for the info, I’ll need to study all of this code and try to learn something from it! thanks again, really appreciated
I believe this is not exactly the case for “ascending” sorting, as the target with 100% is the one used to create the channel and so the first one added.
While the other part of the code I added is not relevant, as I mentioned, it might be useful for the OP and it was indeed useful for me to test it.
Also I think the feature of adding channels later on, is not a bad idea. Anyway, if it’s not needed, it can be simply removed.
As far as I could test, the first code I posted works well with Max 2011, the later modification (while not elegant) seems to work well in Max 2012+.
I know Denis your code works, but it is creating the channel using the lower Weight. In that case you can do ascending sorting, but what would happen if you must create the channel using the highest Weight (100) as it is in the original code from Alex?
Perhaps it’s just a matter of some minor changes, but I havent tried it.
i didn’t work a lot with morphers… is any difference what target was used to build a channel in case of multi-targets?
Honestly I have no idea, I just followed what Alex’s code does and the instructions he gave to us. There could or could not be a solid reason to do so, I can’t tell.
If there is no reason to create the channel from the target with a weight of 100%, then the ascending sorting would be the way to go, as you have proposed. After that, you could just rename the channel to “smile_100” or “leg_100” or whatever name you need.
wow I didn’t get any notifications from this thread anymore!
ok, let me see if i can reply the questions, and ask some more myself!
1.Weight ascending order: is true that while you can add them in this order, the ideal thing is to have it working in any order. Let me explain what im trying to do: the idea is to build a simple morpher manager, where you can create channels and add targets to them via naming convention, lets say you want to create a smile, so you model the smile at 100% , then you can create a smile_050 if you need to, to add a progressive target, to make the movement work in a better way. The problem by adding now a progressive is that max adds this new morph target assuming that is going to be a 100% value, and then changes the other target at 50 %. this happens again if you add another target, it will assign 100% to the latest and change the values for the inbetween targets, which is far from ideal. max ideally would keep the already given values and assign a new value for every new progressive…
Now with the code I had, I wanted to be able to assign automatically all the weights in all the targets, but due to a bug in max’s morpher or me being not too smart, i didn’t manage to do it ( max was assigning the values right via my script, but the order would be messed up, according to Jorge something got broken in max2012 or something… ) so since i’m a noob in this I didn’t know how to work around that bug. here is where Jorge came in and saved the day! the script you did Jorge works awesome ( although I admit i don’t really understand what you are doing in it, to me feels like black magic )
the problem now, is that I integrated that into my scrip ( which does some other things! ) but the problem I have now, is that the script Jorge wrote, works fine the first time, it adds all the targets and progressives as it should, but lets say I want to add an extra progressive that I didn’t have earlier when i ran the script, I could try and run the script again and select my new progressive to be added ( let’s say a new target called smile_070 )
this won’t add it where it should be, instead I’d have the same problem I had by adding them by hand, it changes the weights of all the targets in that channel again…
I’m not sure I’m explaining myself well as this is bloody abstract! thanks for the heads up anyway, really appreciated the help!
Thank you Alex for your comments and explanation.
As you said, the previous script is not prepared to handle Morph Targets insertion, so if you want to add just one target to an existing list, the order will be messed up.
The behavior of the list is a little weird to me. If you delete a target, then all the weights are reassigned. Perhaps this is a common expected behavior, but I don't understand it.
I was hoping to find a "switch" to turn this behavior off but I couldn't find anything.
The following (quite messy) script should allow you to insert new Morph Targets at any time, I hope.
(
struct morphTarget (node, channel, weight)
fn SortByName n1 n2 =
(
if n1.node.name < n2.node.name then 1
else if n1.node.name > n2.node.name then -1
else 0
)
fn GetMorphUsedChannels mMod =
(
usedChannels = for j = 1 to 100 where WM3_MC_HasData mMod j collect #(j, WM3_MC_GetName mMod j)
if usedChannels.count > 0 do
(
answer = querybox "Would you like to delete existing Morph Channels?"
if answer do
(
for j in usedChannels do WM3_MC_Delete mMod j[1]
usedChannels = #()
)
)
usedChannels = for j in usedChannels collect (filterString j[2] "_")[1]
return usedChannels
)
fn AddMorphTargets =
(
-- Make sure the current modifier is a Morpher
morpherMod = modPanel.getCurrentObject()
if classof morpherMod != Morpher do return undefined
-- Get the used Channels
channels = GetMorphUsedChannels morpherMod
-- Display the Node's Selection Dialog
trgs = selectByName single:false
if trgs == undefined do return undefined
/*
From the selected nodes, create an array only with those that have
the correct format in their names "NAME_000". Also look if a channel
for them is already created.
*/
targets = for i in trgs collect
(
chop=filterString i.name "_"
if (chop.count==2) then
(
chnName = chop[1]
appendIfUnique channels chnName
chnIdx = findItem channels chnName
morphTarget node:i channel:chnIdx weight:(chop[2] as float)
)else(
dontcollect
)
)
/*
Sort the selected nodes in descending order so we will catch the
one with 100% weight first and create the channel
*/
qsort targets SortByName
-- Get all the used Progressive Morphs so we can add new ones to the existing ones
usedProgressiveMorphs = #()
usedNodes = #()
for j = 1 to channels.count do
(
pMorphCount = WM3_NumberOfProgressiveMorphs morpherMod j
for i = 1 to pMorphCount do
(
pMorph = WM3_GetProgressiveMorphNode morpherMod j i
pMorphWight = WM3_GetProgressiveMorphWeight morpherMod j pMorph
append usedProgressiveMorphs (morphTarget node:pMorph channel:j weight:pMorphWight)
append usedNodes pMorph
)
)
/*
For each node we have previously collected, create a new Morph channel
if its Weight is 100, otherwise add it to the matching Channel
*/
for i in targets where (finditem usedNodes i.node == 0) do
(
if (i.weight==100.0) then
(
WM3_MC_BuildFromNode morpherMod i.channel i.node
)else(
WM3_AddProgressiveMorphNode morpherMod i.channel i.node
)
append usedProgressiveMorphs i
)
/*
As a workaround for Max 2012+, we first set all the targets Weights to 0.0
and then we set the weight of wach target.
*/
for i in usedProgressiveMorphs do WM3_SetProgressiveMorphWeight morpherMod i.channel i.node 0.0
for i in usedProgressiveMorphs do WM3_SetProgressiveMorphWeight morpherMod i.channel i.node i.weight
)
AddMorphTargets()
)
Due to the weights being reassigned every time you delete a Target, you might need to also fix that. After you have deleted some Target/s you could run the following script to fix the Weights and the order of the list for all channels.
(
struct morphTarget (node, channel, value)
fn FixMorphTargetListAndWeights =
(
morpherMod = modPanel.getCurrentObject()
if classof morpherMod != Morpher do return undefined
targets = #()
for j = 1 to 100 where WM3_MC_HasData morpherMod j do
(
pMorphCount = WM3_NumberOfProgressiveMorphs morpherMod j
for i = 1 to pMorphCount do
(
pMorphNode = WM3_GetProgressiveMorphNode morpherMod j i
pMorphWeight = (filterString pMorphNode.name "_")[2] as float
append targets (morphTarget node:pMorphNode channel:j value:pMorphWeight)
)
)
for i in targets do WM3_SetProgressiveMorphWeight morpherMod i.channel i.node 0.0
for i in targets do WM3_SetProgressiveMorphWeight morpherMod i.channel i.node i.value
)
FixMorphTargetListAndWeights()
)
Thanks Jorge for the info, I’ll need to sit down and study what you are doing as I never used structures etc…
as for the last part of the script, to update weights when deleting targets, would that also work when adding targets and not only when deleting them? Doesnt seem to different from what I did to update the weights…I’ll check later on tonight as I don’t have access to max right now
thanks again for this
The first script works as the previous one but this modified version allows you to add more targets to an existing list. That fixes the problem you were having.
The second script is a different script that you can run at any time. It does two things:
- Fixes all the Weights for all Morph targets in all channels
- Fixes the order in the List.
It should work when adding or deleting any Morph targets, being that done manually from the Morpher UI or via Maxscript.
So if you have deleted a target “smile_085” and its Weight was changed to 63.3, it will set the Weight to 85.0 and move it to the correct place in the List.
It worked on my tests, but the behavior of the “Target List” box is so weird that I can assure it won’t fail in some situations.
i still think that the best way is the adding targets in their weight order. so to add new target we have to collect all old target nodes and their weights from a specified channel, delete old targets, add new target to the list, sort this list by weights, and add this list of targets to thechannel.
the easiest way to do sorting is using of structures.
here is my previous snippet extended to add new target… you can see in viewport all targets in order of their creation. the last one (yellow) is a target to add. heights of the targets correspond to their weights.
delete objects
fn getTargetWeight node =
(
prefix = trimright node.name "0123456789"
(substring node.name (prefix.count + 1) -1) as float
)
fn sortByTargetWeight n1 n2 =
(
(getTargetWeight n1) - (getTargetWeight n2)
)
struct ProgressiveMorph(node, weight)
fn sortByProgressiveMorphWeight n1 n2 = (if n1.weight < n2.weight then -1 else if n1.weight > n2.weight then 1 else 0)
fn findProgressiveMorph list node =
(
local n = 0
for k=1 to list.count while n == 0 where list[k].node == node do n = k
n
)
fn getProgressiveMorphNodes morpher channel sorted:on =
(
targets = for k=1 to WM3_NumberOfProgressiveMorphs morpher channel collect
(
node = WM3_GetProgressiveMorphNode morpher channel k
weight = WM3_GetProgressiveMorphWeight morpher channel node
ProgressiveMorph node:node weight:weight
)
if sorted do qsort targets sortByProgressiveMorphWeight
targets
)
fn deleteAllProgressiveMorphNodes morpher channel =
(
for k=WM3_NumberOfProgressiveMorphs morpher channel to 1 by -1 do
(
WM3_DeleteProgressiveMorphNode morpher channel k
)
)
fn addProgressiveMorphs morpher channel targets sorted:on =
(
if sorted do qsort targets sortByProgressiveMorphWeight
deleteAllProgressiveMorphNodes morpher channel
for k=1 to targets.count do
(
(if k==1 then WM3_MC_BuildFromNode else WM3_AddProgressiveMorphNode) morpher channel targets[k].node
)
for k=1 to targets.count do
(
WM3_SetProgressiveMorphWeight morpher channel targets[k].node targets[k].weight
)
)
fn addProgressiveMorphNode morpher channel node weight sorted:on =
(
targets = getProgressiveMorphNodes morpher channel sorted:on
if (k = findProgressiveMorph targets node) == 0 then
(
append targets (ProgressiveMorph node:node weight:weight)
)
else targets[k].weight = weight
addProgressiveMorphs morpher channel targets
)
numtargets = 5
b0 = converttomesh (box name:#source width:10 length:10 height:10 wirecolor:brown)
targets = for k=1 to numtargets collect
(
weight = random 0 100
name = "target_" + formattedprint weight format:"03d"
converttomesh (box name:name width:(random 5 20) length:(random 5 20) height:weight pos:[30*k,0,0] wirecolor:orange)
)
qsort targets sortByTargetWeight
target_to_add =
(
weight = random 0 100
name = "target_" + formattedprint weight format:"03d"
converttomesh (box name:name width:(random 5 20) length:(random 5 20) height:weight pos:[30*(numtargets+1),0,0] wirecolor:yellow)
)
_morpher = Morpher()
addmodifier b0 _morpher
for k=1 to targets.count do
(
target = targets[k]
(if k==1 then WM3_MC_BuildFromNode else WM3_AddProgressiveMorphNode) _morpher 1 target
)
for k=1 to targets.count do
(
target = targets[k]
weight = getTargetWeight target
WM3_SetProgressiveMorphWeight _morpher 1 target weight
)
addProgressiveMorphNode _morpher 1 target_to_add (getTargetWeight target_to_add)
format "target to add >> %
" target_to_add.name
select b0