Search code examples
unity-game-engine3dgeometryprocedural-generation3d-modelling

Best way to triangulate a screw/spiral/helix


I'm procedurally generating some paths and have a need to create a smooth "spiral" around a point. (Imagine a car park ramp but with a central point).

Something like this: Top down view top down

Side on side on

However - if you look closely - it's not a smooth surface. Because of the layout of the polygons. When two of the vertices go "up" around the central spoke - then there's only one point left to go to the edge.

steps

Is this impossible? Or am I just missing some specific triangle arrangement here that could make this work?

Note - this issue is only present for the inclined "curves" around a central line. Straight paths, curved paths, and inclined paths don't have this issue. It's just the inclined curves (about a point).

Thanks in advance!

EDIT -

Added some sample source code to reproduce the issue (Unity code, just add this to an empty gameobject in a blank scene and it should work. You might need to add a material to see the issue)

another image

using System.Collections.Generic;
using UnityEngine;

public class Test_Spiral : MonoBehaviour
{
    void Start()
    {
        var mesh = Generate();
        AddToGameObject("FailSpiral", mesh);
    }

    private Mesh Generate()
    {
        var mesh = new Mesh();
        var verts = new List<Vector3>();
        var tris = new List<int>();

        Vector3 centre = Vector3.zero;
        var angle = Mathf.PI * 2f / 3f;
        var height = 2f;
        var radius = 5f;
        var count = 20;

        var anglePer = angle / count;
        var heightPer = height / count; ;

        for (var i = 0; i < count; i++)
        {
            verts.Add(centre + Vector3.up * heightPer * i);
            
            var x0 = radius * Mathf.Cos(anglePer * i);
            var z0 = radius * Mathf.Sin(anglePer * i);
            verts.Add(centre + new Vector3(x0, heightPer * i, z0));

            var x1 = radius * Mathf.Cos(anglePer * (i + 1));
            var z1 = radius * Mathf.Sin(anglePer * (i + 1));
            verts.Add(centre + new Vector3(x1, heightPer * (i + 1), z1));

            verts.Add(centre + Vector3.up * heightPer * (i + 1));

            var offset = i * 4;
            tris.Add(offset + 0);
            tris.Add(offset + 2);
            tris.Add(offset + 1);
            tris.Add(offset + 2);
            tris.Add(offset + 0);
            tris.Add(offset + 3);
        }


        mesh.vertices = verts.ToArray();
        mesh.triangles = tris.ToArray();

        mesh.RecalculateNormals();
        mesh.RecalculateTangents();
        mesh.RecalculateBounds();

        return mesh;
    }

    private void AddToGameObject(string name, Mesh mesh)
    {
        var go = new GameObject(name, typeof(MeshFilter), typeof(MeshRenderer), typeof(MeshCollider));
        go.GetComponent<MeshFilter>().sharedMesh = mesh;
        go.GetComponent<MeshCollider>().sharedMesh = mesh;

        go.transform.parent = transform;
    }
}

Solution

  • The issue is that the "central column" of points needs to use two of the three points in the triangle to "go up". Thus the angle of that inner polygon is always going to be vertical.

    On the outer edges it needs to be (mostly) horizontal.

    As such, you end up needing a shape that's a twist. Cut out a thin strip of paper and twist one end just shy of 90 degrees. There is no way to achieve that with just two polgons.

    The solution isn't to subdivide further vertically, but better model that "twist".

    Here is a potential solution. There might be better ways.

    subdivided segment