5

enter image description hereenter image description hereThis is the hat I am makingHow can I UV unwrap a circle (which is divided into segments) into a straight line of segments (triangles) - I can only get segments placed randomly.

enter image description here

I.E. a row of triangular segments with the circumference flattened into a straight line, giving a saw-tooth a pattern like /\/\/\/\/\

  • Can you add images to show what you are trying to achieve? – Sazerac May 31 '19 at 00:21
  • https://blender.stackexchange.com/questions/78358/how-to-straighten-curved-uvs-into-straight-belt/78376#78376 – Duarte Farrajota Ramos May 31 '19 at 00:30
  • 1
    These links are not what i am looking for. I need the UV map to be a row of triangles, not quads. I don't know how to upload images. These answers give maps like this ☐☐☐☐☐☐

    and I need this

    //////\

    Is that clearer??

    –  May 31 '19 at 01:16
  • 1
    @VirtualAlex You can upload images with the little picture icon at the top of the editor, see here for how to format them. Is your circle made of triangles already? Or are you trying to unwrap quads as triangles? – gandalf3 May 31 '19 at 02:14
  • !([IMG]http://i63.tinypic.com/x397d0.jpg[/IMG]) Not sure if that image will work?? I have a circle made of triangles and I want to unwrap into the sawtooth pattern, not a row of quads. –  May 31 '19 at 02:24
  • 1
    please edit your post and show a picture of your object in wireframe display mode, when you'll edit you'll find a button for adding pictures – moonboots May 31 '19 at 06:42
  • I added a pic of the error message I get when trying to run the script –  Jun 05 '19 at 01:08
  • The script in my answer was written using 2.8 See https://blender.stackexchange.com/questions/129473/typeerror-element-wise-multiplication-not-supported-between-matrix-and-vect simply replace any @ symbols with * to use in 2.79 or prior. – batFINGER Jun 05 '19 at 08:13
  • How about the @ before classmethod? or do you mean every single instance? can I do replace all? so, 4 or 5 of them? –  Jun 05 '19 at 12:20
  • Ah I guess you mean just the mathematical ones, because after changing them all and NOPE, I changed the first 4 and YESSS!!!!!! OMG it worked! Genius, I just love it. I will never be afraid of circles again. I will try and post an image!! –  Jun 05 '19 at 12:25
  • Good one edited answer. If you use @batFINGER in a message I will get an alert. Most times too if it is next comment, perhaps because I had this page open in browser I didn't on this occasion. – batFINGER Jun 05 '19 at 13:21
  • Ok @batFINGER! And many, many thanks. On with my hat for my Sims 2 child! –  Jun 06 '19 at 03:53

2 Answers2

9

Rollout Fan

enter image description here Test run, cone: 12 segments, triangle fan view, default UV map, aligned to view

Script, template from text editor > templates > python > Operator Mesh UV Logic:

  • For the selected vertex, get all the linked tri faces.
  • Transform the selection such that vertex coordinate is zero, vertex normal is z axis, ie translate by the vector coordinate and rotate such that the normal is now up, using the rotation difference.
  • Calculate the perimeter by summing lengths of all edges that dont include center vertex of faces .
  • Much like a Mercator projection, map the angle difference of Y axis to each transformed perimeter vertex to U. Will be in range -pi to pi, or -180 to 180 degrees.

To Install:

  • Run the script in text editor Only once to register

To Run:

  • In edit mode select the center vertex of the circle fan
  • Run the operator, F3 Circle Unfold

NOTE:

The script is written for 2.8. Have added addon header to reflect this.

For prior versions replace @ with * except @classmethod and blender version to "blender" : (2, 78, 0) if installing as addon.

bl_info = {
    "name": "UV Unfurl Circle",
    "author": "batFINGER",
    "version": (1, 0),
    "blender": (2, 80, 0),
    "location": "View3D > UV > Circle Unfurl",
    "description": "Select circle center vertex, to unfurl UV",
    "warning": "",
    "wiki_url": "",
    "category": "UV",
}

import bpy import bmesh from mathutils import Vector, Matrix

def main(obj, up=Vector((0, 0, 1)), to=Vector((0, 1))):

from math import pi
me = obj.data
bm = bmesh.from_edit_mesh(me)

uv_layer = bm.loops.layers.uv.verify()
v = bm.select_history.active
if not isinstance(v, bmesh.types.BMVert):
    print("Not a vert")
    return False      

tris = [t for t in v.link_faces if len(t.edges) == 3]      
n = v.normal
T = Matrix.Translation(-v.co)
R = n.rotation_difference(up).to_matrix().to_4x4()

# calc perimeter

p = sum(e.calc_length() for f in tris for e in f.edges 
        if not any(v in e.verts for x in e.verts))

for f in tris:
    f.select = True
    e = next(e for e in f.edges if v not in e.verts)
    e.select = True
    ec = sum([v.co for v in e.verts], Vector()) / 2
    fu = R @ (T @ ec)
    fx = to.xy.angle_signed(fu.xy)

    for l in f.loops:
        luv = l[uv_layer]
        y = 0

        if l.vert is v:
            x,y = fx, (ec - v.co).length
        else:
            u = R @ (T @ l.vert.co)
            x = to.xy.angle_signed(u.xy)
            if abs(fx - x) >= 1.5 * pi:
                x -= 2 * pi if x > 0 else -2 * pi        
        luv.uv = (x + pi) / (2 * pi), y / p

bmesh.update_edit_mesh(me)


class UV_OT_circle_unfurl(bpy.types.Operator): """Circle Unfurl Select circle fan center vertex Unfurl perimeter to U = 0 """ bl_idname = "uv.circle_unfurl" bl_label = "UV Circle Unfurl"

@classmethod
def poll(cls, context):
    return (context.mode == 'EDIT_MESH')

def execute(self, context):
    main(context.edit_object)
    return {'FINISHED'}

def draw(self, context): ''' menu item ''' self.layout.operator("uv.circle_unfurl")

def register(): bpy.utils.register_class(UV_OT_circle_unfurl) bpy.types.VIEW3D_MT_uv_map.append(draw)

def unregister(): bpy.types.VIEW3D_MT_uv_map.remove(draw) bpy.utils.unregister_class(UV_OT_circle_unfurl)

if name == "main": register()

batFINGER
  • 84,216
  • 10
  • 108
  • 233
  • this looks a LITTLE simpler! I will also give this a go. The other method suggested (the math heavy one) gave the result I wanted but ... does life have to be that difficult??! –  Jun 04 '19 at 14:33
  • 3
    This should be a UV tool proposal for 2.81? Looks useful in some applications. – BK. Jun 04 '19 at 17:34
2

I get what you mean. Try marking only the interior edges as seams and unwrapping. If that doesn't quite do it, you can re-position the vertices manually from there. Normalize your UV layout. Then the length of the circumference will be 1 and the "height" of each triangle will be 1/(2pi)***(approx, see note below). This is not a good optimization of space if your entire map is just the circle, so maybe split it up a few times.

An alternative (last resort) strategy could be to mark all edges as seams and do a planar projection. Then, tediously rotate each face into the proper position. A benefit of this is that you will know exactly how much to rotate each face just from the number of triangle segments there are in the model. You have 32 triangle faces. Then each triangle has a central angle of $11.25^\text{o}$ and the 2 remaining interior angles are $(180-11.25)/2 = 84.375^\text{o}$. If you draw a picture you can see that each triangle is rotated by half its interior angle(since $84.375 + x = 90 \to x = 5.625 = 11.25/2$) plus an integer multiple of the interior angle (since each triangle is offset by $11.25^\text{o}$).

This means that in the UV editor, if you have done a planar projection, you just need to rotate the first triangle by $5.625^\text{o}$ to straighten it, and every triangle after that by $5.625 + (k-1)11.25^\text{o}$. Snap the corners to vertices. This may go faster than you think.

enter image description here

First triangle gets rotated 5.625 + (1-1)*11.25 = 5.625 degrees.

Second triangle gets rotated 5.625 + (2-1)*11.25 = 16.875 degrees.

Third triangle gets rotated 5.625 + (3-1)*11.25 = 28.125 degrees.

...

32nd triangle gets rotated 5.625 + (32-1)*11.25 = 354.375 degrees.

//////// NOTE: it was incorrect of me to say that the cap's Circumference was the same as for a circle. We have a 32-sided n-gon circumscribed by that circle. We can use Law of Cosines to get the length of the edge opposite the central angle. Let that edge length be $x$ and circumradius (length of side from center of circle to a vertex) be $r$. Then

$\begin{align} x &= \sqrt{2r^2 - 2r^2\cos{(11.25^\text{o})}} \\ &= \sqrt{2}r\sqrt{1 - \cos{(11.25^\text{o})}} \end{align}$

And the Perimeter of the shape, $P$, is 32 times this:

$\begin{align} P &= 32x \\ &=32\sqrt{2}r\sqrt{1 - \cos{(11.25^\text{o})}} \\ &= 2nr\sin{(\theta/2)} \quad (^{*}\text{simpler abstraction thanks to batFINGER})\end{align}$

So if we scale the UV coordinates so that the Perimeter is "unrolled" about an edge of the UV mapping area, the ratio of the inradius, $h$ (height of the sawtooth pattern) to the Perimeter is $0.1586432873$.

$\begin{align}\frac{h}{P} &= \frac{r\cos{(5.625^\text{o})}}{32\sqrt{2}r\sqrt{(1-\cos{(11.25^\text{o})})}} \\ &= \frac{\cos{(5.625^\text{o})}}{32\sqrt{2}\sqrt{(1-\cos{(11.25^\text{o})})}} \\ &= \frac{\cos{(5.625^\text{o})}}{64\sin{(5.625^\text{o})}} \quad \text{(via other formula)}\\ &= \frac{1}{64\tan{(5.625^\text{o})}} \\ &\approx 0.1586432873 \end{align}$

Compare this to the ratio of $r$ to $C$ for any circle, which is $1/2\pi \approx 0.1595008945$.

All this means is that when you stretch out your sawtooth patter to be as long as the dimensions of the UV map, the height of the teeth should be about $0.1586432873$ times that length.

enter image description here

hatinacat2000
  • 1,075
  • 1
  • 6
  • 21
  • Well thank you for doing the math!!! I'll give it a go, but really - why isn't there a keyboard shortcut for this?? –  Jun 03 '19 at 10:04
  • Idunno, try marking the seams first, maybe it will do it for you via "Unwrap" or "Smart Unwrap"? Probably not though. Then just mark all the edges as seams and planar project, rotate each triangle in the UV editor as above. – hatinacat2000 Jun 03 '19 at 11:02
  • To clarify: The height of each triangle would be r * cos(theta / 2) Eg for the trivial "square" 4 segment circle, ie theta = 90 degrees, normalized with perimeter 1, would mean side length one quarter, triangle height one eighth. The "circle" radius would be h / cos(45) or sqrt(2) / 8 The radius or height suggested of 1 / 2pi will be the limit result as theta approaches zero, and regular ngon perimeter approaches circle circumference. – batFINGER Jun 04 '19 at 01:58
  • 1
    Can also use half angle sine for perimeter n * 2 * r * sin(theta/2) to avoid a lot of computation. – batFINGER Jun 04 '19 at 13:06
  • 1
    Cool was about to mention mathjax $p = 2 n r \sin (\theta / 2)$ much more readable. ... alas can only upvote once. – batFINGER Jun 04 '19 at 13:23
  • ^agreed, then the ratio of the incircle $h$ to $P$ would be $\cot{(\theta/2)}/2n$ – hatinacat2000 Jun 04 '19 at 13:26
  • I'll take your word for it. (lot of rust on my trig) Def would use this, or similar, to create UV when creating a fan filled circle (via script) – batFINGER Jun 04 '19 at 13:40
  • Yep, verified. My calculation was off for a few minutes because I made a typo with one of the angles but it matches now. Thank you for helping me make this explanation better. – hatinacat2000 Jun 04 '19 at 13:45
  • I thought I followed your instructions:

    To Install:

    Run the script in text editor Only once to register

    [I copied the text you gave into the text editor (created new file and pasted it in). I clicked the Register box, and clicked the "run script" button]

    To Run:

    In edit mode select the center vertex of the circle fan Run the operator, F3 Circle Unfold

    [I did this but nothing happened, except the error message which I have added to this post (I think).

    Can I have more specific instructions please!! Thanks.]

    –  Jun 05 '19 at 04:33