Create Smoothing Groups from UV Islands

Martin Palko 3ds Max, Scripts 14 Comments

Note: A few people have reported that this script does not work with 3ds max 2016. I haven’t had a chance to investigate yet, so it might need a few modifications to work on the latest version of max.

It’s fairly common knowledge that when creating a model that will have a baked normal map, you want to have a split in your UV wherever you have a hard edge. Usually you’d have to make sure you keep in mind your UV layout when setting up your smoothing groups, or vice-versa. I’ve been meaning to get into learning Maxscript for awhile, so I figured I’d have a go at writing a script to make the process a bit easier and less prone to error.

What the script does, is put hard edges wherever there’s a seam on the UV. You could also think of it as assigning a single smoothing group to each UV island. I’m definitely not the first person to come up with this, but the scripts I’ve come across that do this tend to have some cases in which they don’t work, or produce incorrect results.

You can download it below, and be sure to check the header of the script for usage instructions!

Uv2Smooth

Download – UVIslandsToSmoothingGroups.ms

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
------------------------------------- UV Islands To Smoothing Groups -------------------------------------
-- By Martin Palko
-- www.martinpalko.com
--
--
-- Tested:  - Max 2014
--
-- Install: - Drag script into max, then assign it to a hotkey or menu bar in "Customize -> User Interface"
--          - Can be found by setting the category to "MP_Tools" while in the "Main UI" group
--
-- Usage:   - Select any mesh object, and activate the script. Choose a UV channel and hit run.
--
-- Notes:   - This script will not affect your modifier stack, it will simply put an edit poly with the
--              smoothing groups at the top.
--          - Undo is not currently supported, so save before, just in case. You can however, just delete
--              the edit poly modifier to get your old smoothing groups back.
--          - Selecting any channel other than UV channel 1 will show a dialogue box asking if you want to
--              reset UVs. You must hit yes for it to work based on the channel you've specified. This
--              will NOT affect the model's existing UV set.
 
macroscript UVIslandsToSmoothing
category:"MP_Tools"
buttontext:"UV 2 Smooth"
tooltip:"Convert UV islands to smoothing groups"
autoUndoEnabled:false
(  
    -- Helper function to get the index of the first true element in a bit array
    function getFirstActiveInBitarray aBitArray =
    (
        for i = 1 to aBitArray.count do
        (
            if aBitArray[i] == true do return i
        )
        -- return 0 if none are found active
        return 0
    )
 
    -- Actually performs the operation on the currently selected object
    function ConvertUVIslandsToSmoothingGroups aUVChannel =
    (
        if $ != undefined then
        (          
            modPanel.addModToSelection(Edit_Poly()) ui:on
            local editPoly = $.modifiers[#edit_poly]
             
            local facesDone = #{} -- empty bit array since no faces are done
            local allFaces = #{1.. polyop.getNumFaces $}
            local facesNotDone = allFaces
             
            -- Stick on a UVW modifier
            modPanel.addModToSelection (Unwrap_UVW ()) ui:on
            local uv_modifier = $.modifiers[#unwrap_uvw]               
            uv_modifier.unwrap2.setTVSubObjectMode 3 -- Use face selection
                 
            if (aUVChannel != 1) then -- Only need to mess with this if it's not default
            (
                uv_modifier.unwrap.setMapChannel aUVChannel
                uv_modifier.unwrap.reset()
                forcecompleteredraw dodisabled:true -- Hacky fix for a bug, see http://www.polycount.com/forum/showthread.php?t=97059
            )
                 
            local uv_islands = #() -- Empty array that will store bitarrays of all our UV islands
            local abort = false -- Abort boolean for breaking out of the loop and avoid the performance penalty of using break
             
            -- Build array of UV islands
            while (facesNotDone.isEmpty == false and abort == false) do
            (              
                nextFace = getFirstActiveInBitarray facesNotDone -- Get next face that hasn't been processed yet
                 
                uv_modifier.unwrap2.selectFaces #{nextFace} -- Select that face
                uv_modifier.unwrap2.selectElement() -- Grow selection to element
                uv_island = uv_modifier.unwrap2.getSelectedFaces()  -- Get a bitaray of all those faces (representing a UV island)
                 
                -- Update faces done/not done bit masks
                facesDone += uv_island
                facesNotDone -= uv_island
                 
                insertItem uv_island uv_islands (uv_islands.count + 1) -- Add that bitarray to our array of UV islands
                 
                if uv_islands.count > allFaces.count then -- this should never happen, if it does means we are in an infinite loop and will crash max, so bail
                (
                    abort = true
                    print ("Error, calculated too many islands, something went wrong")
                )
            )
             
            deletemodifier $ uv_modifier -- Don't need the UV modifier anymore
             
            editPoly.autoSmoothThreshold = 180.0 -- If we auto smooth, it should always be in the same smoothing group
             
            for island = 1 to uv_islands.count do -- Select and auto smooth each UV island
            (
                editPoly.SetSelection #Face uv_islands[island]
                editPoly.ButtonOp #Autosmooth
            )
        )
    )
     
    local isOpen = false -- Store if the rollout is open or closed
     
    rollout UV2SmoothRollout "UV_2_Smooth"
    (
        spinner UVChannelSpinner "UV Channel" range:[1,99,1] type:#integer
        button GoBtn "        Run        "
         
        on GoBtn pressed do
        (
            ConvertUVIslandsToSmoothingGroups (UVChannelSpinner.value)
            destroyDialog UV2SmoothRollout -- Close rollout after running
        )
         
        on UV2SmoothRollout close do
        (
            isOpen = false
            updateToolbarButtons() -- Update the toolbar icon when closing
        )
    )
     
    on execute do
    (
        if isOpen then --if open, close it
        (
            destroyDialog UV2SmoothRollout
        )
         
        else --if closed, open it
        (
            createDialog UV2SmoothRollout
            isOpen = true
        )
    )
   
    on isChecked return isOpen --return the flag
     
    on isEnabled do
    (
        -- Need an editable poly selected to work
        if $ == undefined then
        (
            -- Close the window if it's open and it shouldn't be
            if (isOpen) then
                destroyDialog UV2SmoothRollout
             
            return false
        )
        else
            return true
    )
)

Comments 14

  1. Fantastic piece of software! I am getting one very nasty error while trying to apply the script on multiple meshes though — Unknown property: “modifiers” in $selection. It doesn’t crash Max, but I’d very much like to use the script on multiple objects, can you help me out?

  2. Fantastic script and very useful, ever since 3D Max introduced the amazing feature using the ‘champfer’ utility in a ‘editable poly’ upon geometry removes all your smooth groups by default, unless you remember to uncheck the stupid option!

    This has just saved my bacon and works in v2019

  3. Thank you Very much
    3Ds Max 2019 OK!

    스크립트를 맥스로 드래그 하여 설치한 후
    단축키 또는 메뉴바로 지정 한 후 사용해야 한다.
    간단한 스크립트의 경우 대부분 이런 식으로 사용한다.

    1. Post
      Author

      It does! Since the script just applies auto-smooth, it picks the next available smoothing group that isn’t being used by a neighboring island. Even on complex models, it shouldn’t use more than a handful of smoothing groups.

Leave a Reply to Jonathan Young Cancel reply

Your email address will not be published. Required fields are marked *