5
$\begingroup$

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 /\/\/\/\/\

$\endgroup$
  • $\begingroup$ Can you add images to show what you are trying to achieve? $\endgroup$ – Sazerac May 31 '19 at 0:21
  • $\begingroup$ blender.stackexchange.com/questions/78358/… $\endgroup$ – Duarte Farrajota Ramos May 31 '19 at 0:30
  • 1
    $\begingroup$ 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?? $\endgroup$ – VirtualAlex May 31 '19 at 1:16
  • 1
    $\begingroup$ @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? $\endgroup$ – gandalf3 May 31 '19 at 2:14
  • 1
    $\begingroup$ 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 $\endgroup$ – moonboots May 31 '19 at 6:42
9
$\begingroup$

Rollout Fan

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

Script, templated 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()
| improve this answer | |
$\endgroup$
  • $\begingroup$ 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??! $\endgroup$ – VirtualAlex Jun 4 '19 at 14:33
  • 2
    $\begingroup$ This should be a UV tool proposal for 2.81? Looks useful in some applications. $\endgroup$ – BK. Jun 4 '19 at 17:34
2
$\begingroup$

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

| improve this answer | |
$\endgroup$
  • $\begingroup$ Well thank you for doing the math!!! I'll give it a go, but really - why isn't there a keyboard shortcut for this?? $\endgroup$ – VirtualAlex Jun 3 '19 at 10:04
  • $\begingroup$ 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. $\endgroup$ – hatinacat2000 Jun 3 '19 at 11:02
  • $\begingroup$ 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. $\endgroup$ – batFINGER Jun 4 '19 at 1:58
  • 1
    $\begingroup$ Can also use half angle sine for perimeter n * 2 * r * sin(theta/2) to avoid a lot of computation. $\endgroup$ – batFINGER Jun 4 '19 at 13:06
  • 1
    $\begingroup$ Cool was about to mention mathjax $p = 2 n r \sin (\theta / 2)$ much more readable. ... alas can only upvote once. $\endgroup$ – batFINGER Jun 4 '19 at 13:23

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.