Splitting Vertices - Hard Edges for Low Poly Procedural Generation
/This isn’t a procedural generation post. There are plenty of videos and posts explaining how to generate procedural meshes. There’s no need for me to recreate that.
Rather this post should help in turning your procedurally generated mesh into a mesh with hard edges that is used in most “low poly” models. The post assumes is that you ALREADY have a procedural mesh who’s edges are smooth and you’d like a more traditional low poly or hard edge appearance. It also assumes that you understand the basics of vertices and triangles that make up a mesh.
What is a split edge?
Have you ever noticed that “low poly” assets often have a large number of vertices when imported to Unity? I had. I knew it was a thing, but never knew why.
The reason comes from the normals of the vertices, which are generally calculated from the normals of the triangles (which make up the faces) that use a given vertex. If multiple triangles use a vertext then the normal of the vertex is the average of the all the triangle normals. Which can cause a smoothing of the edges.
To fix this we need each vertex to only be used by a single triangle. This way the vertex normal is the same as the individual triangle normal. But how does that work? Surely the vertex on the corner of a cube must be used by three sides!
The trick is to duplicate the vertex for each triangle. In a normal cube, this means we go from 8 vertices to 24. Each side of the cube has 2 triangles, so 12 total triangles and each triangle needs 3 vertices. Which is why when we import models from Blender into Unity that are flat shaded the number of vertices increases substantially - it may not always be 3 times as it depends on the geometry but it’s often close to tripling. When we import into Unity, it can do the vertex splitting automatically, but when generating models procedurally we need to do it ourselves.
The images above are from Blender where you can toggle what normals are shown. So it’s a bit fudged, but it demostrates the idea. Both cubes are also shown with hard edges since this is the default in Blender. Smooth rendering in Blender looks a bit different than in Unity so I just left them both with hard edges :)
How do we do it?
I struggled with this part as I wanted to split the vertices as I created the mesh, but I quickly realized the easiest way would be to split the vertices after the mesh is created - which also makes it a pretty universal method. With that approach its relativiely simple.
Big picture: To split the vertices we need to duplicate the vertices and then reassign triangles indices so the triangles refer to the new and correct vertices.
To get started, we create a new array for the split vertices that is the length of mesh’s triangle array - each point on a triangle needs a unique vertex. For simplicity and clarity, I also create a new triangle array for use by are new mesh.
From there we iterate through our number of triangles storing vertices for each point on a triangle and reassigning indices in the triangle array.
The last step is to build a new mesh with the new vertices and new triangles. You could reuse the incoming mesh, but creating a new one felt clearer. Reusing the incoming mesh could also let you avoid creating a new array for the triangles.
That’s it. Pretty simple but something that I hadn’t found documented in other places. Hopefully its useful to someone.