2
$\begingroup$

If I unwrap my model's UVs, I get lots of squares (or square-like things) like this:

enter image description here

But the squares are really tiny! I don't want the squares to be tiny, I want each island of connected vertices to fill the entire picture.Or, if they're like the triangles or other weird shapes, to expand as far as reasonably possible.

Note, if I unwrap each square individually it fills the picture as desired (but this is impractical for 100+ squares)

I do not care about overlapping UVs.

How would I do this?

Download my tree scene here

$\endgroup$
  • 2
    $\begingroup$ Hello :). Select All > UV > Reset should give you such result. $\endgroup$ – Jachym Michal Jun 6 at 18:57
  • $\begingroup$ @JachymMichal Oo, I didn't know that! However, I need to do it per linked square, if possible, as opposed to per face. $\endgroup$ – Joehot200 Jun 6 at 19:00
  • $\begingroup$ Do you mind uploading some geometry/UVs for testing? $\endgroup$ – brockmann Jun 9 at 23:31
  • $\begingroup$ @brockmann Uploaded! Thanks for the good idea. $\endgroup$ – Joehot200 Jun 10 at 20:28
3
+50
$\begingroup$

Quick script in order to select all islands and pack them individually based on How to get lists of UV island from Python script?. Credit goes to @Tlousky, I just added bpy.ops.uv.pack_islands():

enter image description here UV layout before (left) and after running the script (right)


Just select your object in Object Mode and run the following script:

import bpy
C = bpy.context
o = bpy.data.objects[ C.object.name ]

# Go to object mode to read UV data
bpy.ops.object.mode_set( mode = 'OBJECT' )

uvLayer = o.data.uv_layers.active
uvs     = [ uvLayer.data[i] for i in range( len( uvLayer.data ) ) ]

others = uvs.copy()
islands = []

def select_island( uv ):
    uv.select = True
    bpy.ops.object.mode_set( mode = 'EDIT' )
    bpy.ops.uv.select_linked()
    bpy.ops.uv.pack_islands()
    bpy.ops.object.mode_set( mode = 'OBJECT' )

    return [ i for i, uv in enumerate( uvs ) if uv.select ]

for i in range( len( uvs ) ):
    bpy.ops.object.mode_set( mode = 'EDIT' )
    bpy.ops.uv.select_all( action = 'DESELECT' )
    bpy.ops.object.mode_set( mode = 'OBJECT' )

    flat = [ idx for isle in islands for idx in isle ]
    if i in flat: continue

    island = select_island( uvs[i] )

    exists = len( set( flat ).intersection( set( island ) ) )
    if island and not exists: islands.append( island )
    

#print( islands )
#print( " number of islands: ", len( islands ) )
| improve this answer | |
$\endgroup$
1
$\begingroup$

I've written a small script that should get you where you need to be. Please be aware I'm no programmer at all, so this script might objectively suck, but it does work (tested it on your scene), even though it needs a bit of prep:

  • First, separate each object (each leaf) into a separate object. This is easiest done by first separating the leaves from the bark (Edit Mode - Material tab - Select faces with this material - P - selection), then going into them in Edit mode and choosing P - By Loose Parts.
  • Then, select all the leaf objects and run this script:
    import bpy
    
    selection = bpy.context.selected_objects #remember the currently selected objects as "selection"
    
    for ob in selection: 
        ob.select_set(False) #deselect everything. 
        #Otherwise when unwrapping each object, the algorithm seems to consider its fellow objects' UVs. 
    
    for i in selection: #do the following for each of the objects:
        bpy.context.view_layer.objects.active = i #set as active
        bpy.ops.object.mode_set(mode='EDIT') #go into edit mode
        bpy.ops.uv.unwrap(method='ANGLE_BASED', margin=0.001) #unwrap
        bpy.ops.object.mode_set(mode='OBJECT') #exit out of edit mode. This is optional.
| improve this answer | |
$\endgroup$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.