Home Technical Talk

Falloff Script for Max 9 - Is this possible?

polycounter lvl 12
Offline / Send Message
foreverendering polycounter lvl 12
Okay I've been trying to find an answer to this question, maybe someone here knows the answer. I'm not too great at scripting.

Basically, I have this script that I found that increments the falloff value of soft selection by a value (for example 0.5). This can be bound to a key so that every time I tap it, I can increase or decrease my falloff.


What I'd like to do, is be able to modify this script such that you could hold down a key, and then increment up & down using the mouseCursorY position. This would provide a functionality similar to a sculpting program like Mudbox. Is this even possible?

<font class="small">Code:</font><hr /><pre>
first macroscript

[begin snip]

macroScript ShrinkSoftSel
category:"MyScripts"
toolTip:"Shrink Soft Select"
(
on isEnabled return
(
if (((getcurrentselection()).count == 1) and ($ != undefined)) then
if (classof $.baseobject == Editable_Poly) then true else false
else false
)

on Execute do
(
undo off
(
local tempvalue = $.Falloff
tempvalue = tempvalue - 0.5
if (tempvalue < 0) then tempvalue = 0
$.Falloff = tempvalue
)
)
)

[end snip]


second macroscript

[begin snip]

macroScript GrowSoftSel
category:"MyScripts"
toolTip:"Grow Soft Select"
(
on isEnabled return
(
if (((getcurrentselection()).count == 1) and ($ != undefined)) then
if (classof $.baseobject == Editable_Poly) then true else false
else false
)

on Execute do
(
undo off
(
local tempvalue = $.Falloff
tempvalue = tempvalue + 0.5
$.Falloff = tempvalue
)
)
)
[end snip]
</pre><hr />

Thanks for any insight.

Replies

  • KikiAlex
    macroScript mouse_falloff_
    category:"MyScripts"
    toolTip:""
    (
    curent_mouse = undefined
    l_mouse = undefined
    tool Falloff_control_0
    (
    on mousePoint xx do
    (
    curent_mouse = viewPoint
    #stop
    )
    )

    tool Falloff_control_1
    (
    on mousePoint xx do
    (
    l_mouse = viewPoint
    #stop
    )
    )


    on execute do
    (
    if (selection[1] != undefined) and ((classof selection[1].baseobject) == Editable_Poly) do
    (
    startTool Falloff_control_0


    startTool Falloff_control_1

    mouse_o = curent_mouse - l_mouse
    tempvalue = selection[1].Falloff
    ---in order to change sensitivity use this and re-run the script
    sensitivity = 5
    tempvalue = tempvalue + (mouse_o.y/sensitivity)
    selection[1].Falloff = (tempvalue)
    )
    )
    )
  • KikiAlex
    OK that was stupid I think this is what you need :


    macroScript mouse_falloff_2
    category:"MyScripts"
    toolTip:""
    (
    rollout falloff_mouseRollout "Untitled" width:360 height:25
    (
    slider sld1 "" pos:[73,1] width:300 height:25 range:[0,100,0] orient:#horizontal ticks:0
    editText edt1 "" pos:[-3,3] width:68 height:16 enabled:false

    on sld1 buttonup do
    (
    if (selection[1] != undefined) and ((classof selection[1].baseobject) == Editable_Poly) do
    (
    selection[1].Falloff = sld1.Value
    DestroyDialog falloff_mouseRollout
    )

    )

    on falloff_mouseRollout open do
    (
    if (selection[1] != undefined) and ((classof selection[1].baseobject) == Editable_Poly) do
    (
    edt1.Text = selection[1].Falloff as string
    sld1.Value = selection[1].Falloff
    )
    )
    )

    createdialog falloff_mouseRollout style:#(#style_sysmenu)
    )
  • KikiAlex
    macroScript falloff_2
    category:"MyScripts"
    toolTip:""
    (
    rollout falloff_mouseRollout "Untitled" width:344 height:25
    (
    slider sld1 "" pos:[51,1] width:300 height:25 range:[0,selection[1].Falloff*2,selection[1].Falloff] orient:#horizontal ticks:0
    label edt1 "" pos:[2,3] width:44 height:16

    on sld1 buttonup do
    (
    if (selection[1] != undefined) and ((classof selection[1].baseobject) == Editable_Poly) do
    (
    selection[1].Falloff = sld1.Value
    selection[1].useSoftSel = true
    DestroyDialog falloff_mouseRollout
    )

    )

    on falloff_mouseRollout open do
    (
    if (selection[1] != undefined) and ((classof selection[1].baseobject) == Editable_Poly) do
    (
    edt1.Text = selection[1].Falloff as string
    sld1.Value = selection[1].Falloff
    )
    )
    )

    on execute do
    (
    try(DestroyDialog falloff_mouseRollout) catch()
    if (((classof selection[1].baseobject) == Editable_Poly)) do
    (
    createdialog falloff_mouseRollout style:#(#style_sysmenu) pos:(mouse.screenpos-[194,10])
    )
    )
    )
  • MoP
    Offline / Send Message
    MoP polycounter lvl 18
    That is pretty cool! smile.gif
    Any way to make it so that the mouse immediately controls the slider that pops up, rather than having to click again on the popup slider?
  • Rob Galanakis
    Alright dude since I took and adapted this yesterday for my team I figured I should post the code here... it is a smarter version of above, feel free to use it (I highly suggest it). The max falloff is now the largest side of the bounding box, so for large or small objects, the slider scales correctly, and the code is cleaned up some.

    <font class="small">Code:</font><hr /><pre>--Falloff Mouse Script
    macroScript MouseFalloff
    category:"MyTools"
    (
    try(DestroyDialog falloff_mouseRollout) catch()

    try (

    local sliderUpper
    bbMax = $.max
    bbMin = $.min
    bbx = bbMax.x - bbMin.x
    bby = bbMax.y - bbMin.y
    bbz = bbMax.z - bbMin.z

    if bbx >= bby then sliderUpper = bbx
    if bby >= bbz then sliderUpper = bby
    if bbz >= bby then sliderUpper = bbz

    rollout falloff_mouseRollout "Falloff" width:200 height:24
    (
    slider sld1 "" pos:[51,1] width:160 height:10 range:[0 , sliderUpper, $.Falloff ] orient:#horizontal ticks:0
    label edt1 "" pos:[2,3] width:40 height:16

    on sld1 changed val do
    (
    selection[1].Falloff = sld1.Value
    edt1.Text = selection[1].Falloff as string
    )

    on sld1 buttonup do
    (
    selection[1].useSoftSel = true
    DestroyDialog falloff_mouseRollout
    )

    on falloff_mouseRollout open do
    (
    origMousePos = mouse.screenpos
    sld1.Value = selection[1].Falloff
    edt1.Text = selection[1].Falloff as string
    )
    )

    createDialog falloff_mouseRollout pos:(mouse.screenpos-[194,10])
    )
    catch ()
    )</pre><hr />
  • MoP
    Offline / Send Message
    MoP polycounter lvl 18
    That's pretty cool. Still not exactly the ideal solution though (Silo and Mudbox's methods are the ideal IMHO).
    I'm sure it's possible in Maxscript, to actually have it increment the falloff value based on the offset of the mouse position from its original position in screenspace (either horizontally or vertically would be ideal). That way you don't have to pop up a slider which you then have to pull to a value ... you can just hold down a button while moving the mouse and let go of the button to "accept" the current falloff value. I'll maybe take a look into it over the weekend, I've been meaning to do some more maxscripting anyway.
  • Rob Galanakis
    If I get a chance I will try and do it, its more complex for sure so it wasn't worth my time ATM, though I will put it on my to-do list if you can't figure it out.
  • foreverendering
    Offline / Send Message
    foreverendering polycounter lvl 12
    Thanks for the replies so far guys...

    My workaround solution for the moment is with an AutoHotkey script I wrote that enables me to bind the falloff to shift + the scroll wheel.

    It works pretty well, the only downside is that I always have to execute the script when I reboot my computer. There's probably a way for me to tell it to run on startup, but I didn't look that much into AutoHotkey.

    I've been testing it at home, and I'm really enjoying the ability to scale my falloff on the fly when adjusting mesh.

    If anyone is interested in it, I can post it up. It's a really simple key remap.
  • Rob Galanakis
    "It works pretty well, the only downside is that I always have to execute the script when I reboot my computer."

    What I do for my scripts is, I have a directory I work on my scripts in, and in my Scripts/Startup folder I have a .ms file that uses getFiles "C:\\foo\\*.ms" and .mcr, then fileIn's them. I also delete any .bmp files in ui\icons and then copy over any bmp files in that folder.

    This way, when max starts, the artists automatically get the most recent version of my scripts and icons (as long as SVN is updated). Not as needed when you are just working on your own scripts, but having the script evaluated/executed automatically when you start Max, without having to put it in the startup folder, is good. If you want I can post the script Monday.
  • foreverendering
    Offline / Send Message
    foreverendering polycounter lvl 12
    Cool Professor, post it up on Monday!

    What I meant though was, the script I am using for key remapping is not a maxscript, but an AutoHotkey script

    www.autohotkey.com

    Which remaps Shift + MouseWheelDown to downArrow and Shift + MouseWheelUP to upArrow. Then in my scripts/startup folder I have my maxscript that binds the falloff controls to downArrow and upArrow.

    The AutoHotkey script is a .ahk file that I let run in the background all the time, it's just that when I reboot I have to start it up again
  • Rob Galanakis
    Look in help under "Executing External Commands and Programs" to launch the script when you start max. There should be a way to check whether a process is running as well, though it is probably not native to maxscript (thus you could check if autohotkey was running and if it wasn't you could launch when you open max). I checked help and can't find it (if I had ever seen it, can't remember), but maybe you can do something via DOS? Or you could add the script into things that launch automatically when you boot up your comp.
  • MoP
    Offline / Send Message
    MoP polycounter lvl 18
    My version, last updated 16:29 GMT, 05/11/07:

    1. Copy and paste this into a new Maxscript, run it, and bind a hotkey to this new function.
    2. Press the hotkey then just move the mouse up or down to set the falloff value greater or smaller.
    3. Left-click to accept the value, or right-click to cancel and reset the falloff value to the initial value.

    <font class="small">Code:</font><hr /><pre>
    macroscript falloffSlider
    category:"MoP's Tools"
    tooltip:"Soft Sel. Falloff Slider"
    buttonText:"Falloff Slider"
    (
    try
    (
    local obj = selection[1]
    local falloffValue
    local origPos = mouse.pos.y
    local origFalloff = obj.Falloff
    local avgScale = ( obj.scale.x + obj.scale.y + obj.scale.z ) / 3
    local maxFalloff

    bbMax = $.max
    bbMin = $.min
    bbx = bbMax.x - bbMin.x
    bby = bbMax.y - bbMin.y
    bbz = bbMax.z - bbMin.z

    if bbx >= bby and bbx >= bbz then maxFalloff = ( bbx * 2 ) / avgScale
    if bby >= bbz and bby >= bbx then maxFalloff = ( bby * 2 ) / avgScale
    if bbz >= bbx and bbz >= bby then maxFalloff = ( bbz * 2 ) / avgScale

    if classOf obj == Editable_Poly and subobjectlevel != 0 and subobjectlevel != undefined then
    if obj.useSoftSel == false then obj.useSoftSel = true
    tool falloffSlider
    (
    on freeMove do
    (
    falloffValue = ( mouse.pos.y - origPos ) * ( maxFalloff / 500 )
    obj.Falloff = ( origFalloff - falloffValue )
    if obj.Falloff >= maxFalloff then obj.Falloff = maxFalloff
    if obj.Falloff <= 0 then obj.Falloff = 0
    )
    on mousePoint click do #stop
    on mouseAbort click do obj.Falloff = origFalloff
    on stop do print obj.Falloff
    )
    startTool falloffSlider prompt:"Soft Selection Falloff Distance"
    )
    catch ()
    )
    </pre><hr />

    Thanks to Professor420 for sharing his code. Useful starting point for some of this stuff!

    I've added a more thorough (I think?) bounds-checker. It now takes the object's world scale into account too, since the falloff value in the EPoly isn't related to the world unit size, so just using the bounds of the object doesn't set a sensible range if the whole object has been scaled.

    Now it will only become active if you're in sub-object mode of an Editable Poly. I figured it doesn't make much sense being able to change the value when you can't see the effect it's having, so it automatically turns on soft selection if it wasn't on already when you hit the hotkey.

    At the moment it doesn't work on Editable Meshes (does anyone use those any more?) and it doesn't work on Edit Poly modifiers. If this is causing problems for people, I can quite easily build in support for those.

    Lemme know if anyone likes it, or has suggestions for improvement.

    -MoP
  • MoP
    Offline / Send Message
    MoP polycounter lvl 18
    Mildly updated the script today, I'm fairly happy with how it works. It's very smooth and works on Editable Poly objects of any size/scale.
    I still want to get it set up to only be active while a key is pressed and held down, but I'm not sure if that's even possible using Maxscript.
  • MoP
    Offline / Send Message
    MoP polycounter lvl 18
    New one on a vaguely similar slant to the falloff script, here's a script which uses the same up/down controller to shrink/grow a selection.

    Just press the hotkey you assign to the script, then move the mouse up or down to shrink or grow the selection.

    <font class="small">Code:</font><hr /><pre>
    macroscript selectionSlider
    category:"MoP's Tools"
    tooltip:"Grow/Shrink Selection Slider"
    buttonText:"Selection Slider"
    (
    try
    (
    local obj = selection[1]
    local dist
    local origPos = mouse.pos.y
    local newPos = mouse.pos.y
    local origVertSel = polyOp.getVertSelection obj
    local newVertSel = origVertSel
    local origEdgeSel = polyOp.getEdgeSelection obj
    local newEdgeSel = origVertSel
    local origFaceSel = polyOp.getFaceSelection obj
    local newFaceSel = origVertSel

    if classOf obj == Editable_Poly and subobjectlevel == 1 and obj.selectedVerts.count != 0 then (
    tool selectionSlider (
    on freeMove do (
    dist = - ( mouse.pos.y - origPos )
    if dist > 5 then (
    obj.growSelection ()
    origPos = mouse.pos.y
    )

    if dist < -5 then (
    obj.shrinkSelection ()
    origPos = mouse.pos.y
    )

    if obj.selectedVerts.count == 0 then (
    obj.selectedVerts = newVertSel
    ) else (
    newVertSel = polyOp.getVertSelection obj
    )

    if obj.selectedVerts.count == obj.verts.count then #stop
    )
    on mousePoint click do #stop
    on mouseAbort click do obj.selectedVerts = origVertSel
    )
    )

    if classOf obj == Editable_Poly and (subobjectlevel == 2 or subobjectlevel ==3) and obj.selectedEdges.count != 0 then (
    tool selectionSlider (
    on freeMove do (
    dist = - ( mouse.pos.y - origPos )
    if dist > 5 then (
    obj.growSelection ()
    origPos = mouse.pos.y
    )

    if dist < -5 then (
    obj.shrinkSelection ()
    origPos = mouse.pos.y
    )

    if obj.selectedEdges.count == 0 then (
    obj.selectedEdges = newEdgeSel
    ) else (
    newEdgeSel = polyOp.getEdgeSelection obj
    )

    if obj.selectedEdges.count == obj.edges.count then #stop
    )
    on mousePoint click do #stop
    on mouseAbort click do obj.selectedEdges = origEdgeSel
    )
    )

    if classOf obj == Editable_Poly and subobjectlevel == 4 and obj.selectedFaces.count != 0 then (
    tool selectionSlider (
    on freeMove do (
    dist = - ( mouse.pos.y - origPos )
    if dist > 5 then (
    obj.growSelection ()
    origPos = mouse.pos.y
    )

    if dist < -5 then (
    obj.shrinkSelection ()
    origPos = mouse.pos.y
    )

    if obj.selectedFaces.count == 0 then (
    obj.selectedFaces = newFaceSel
    ) else (
    newFaceSel = polyOp.getFaceSelection obj
    )

    if obj.selectedFaces.count == obj.faces.count then #stop
    )
    on mousePoint click do #stop
    on mouseAbort click do obj.selectedFaces = origFaceSel
    )
    )
    startTool selectionSlider prompt:"Growing/Shrinking Selection"
    )
    catch ()
    )
    </pre><hr />

    Lemme know how you find it. It's a bit lengthy, but it will only activate if you're in Vertex, Edge, Border or Face mode of an Editable Poly. I figure there's no point trying to grow/shrink an element selection :P
    It also won't activate if you don't have a selection.

    I also updated the soft sel. falloff script to get rid of the annoying print every time the value changed.
  • robioto
    Offline / Send Message
    robioto polycounter lvl 19
    Sorry I'm a little late with this, but if you're looking for an alternative to the slider approach for SS falloff this is a handy manipulator.

    http://www.martincoven.com/tools/SSFalloff_Manip.zip
Sign In or Register to comment.