H3XED

# Create 2D Mesh Outline in Unity (Silhouette)

Mar 6, 2017   Programming   Nick Vogt   Comments (2)
Please note that this post is over a year old and may contain outdated information.
This code creates an outline of a 2D mesh utilizing the LineRenderer component in Unity. It does not require any shaders and seems to run very quickly from my testing. It also supports meshes that have mutliple non-connected components.

How to Use It
To use it, create an OutlineCreator C# script, copy the below code in, and add the Script component to a GameObject that has a 2D mesh. You can specify the line width and material it should use, which are the two public configurable options. When you hit Play, the script will generate child GameObjects with Line Renderers.

OutlineCreator C# Code
`using System.Collections.Generic;using UnityEngine;public class OutlineCreator : MonoBehaviour{    public float lineWidth;    public Material material;    void Start()    {        // Stop if no mesh filter exists        if (GetComponent<MeshFilter>() == null) {            return;        }                // Get triangles and vertices from mesh        int[] triangles = GetComponent<MeshFilter>().mesh.triangles;        Vector3[] vertices = GetComponent<MeshFilter>().mesh.vertices;        // Get just the outer edges from the mesh's triangles (ignore or remove any shared edges)        Dictionary<string, KeyValuePair<int, int>> edges = new Dictionary<string, KeyValuePair<int, int>>();        for (int i = 0; i < triangles.Length; i += 3) {            for (int e = 0; e < 3; e++) {                int vert1 = triangles[i + e];                int vert2 = triangles[i + e + 1 > i + 2 ? i : i + e + 1];                string edge = Mathf.Min(vert1, vert2) + ":" + Mathf.Max(vert1, vert2);                if (edges.ContainsKey(edge)) {                    edges.Remove(edge);                } else {                    edges.Add(edge, new KeyValuePair<int, int>(vert1, vert2));                }            }        }        // Create edge lookup Dictionary        Dictionary<int, int> lookup = new Dictionary<int, int>();        foreach (KeyValuePair<int, int> edge in edges.Values) {            if (lookup.ContainsKey(edge.Key) == false) {                lookup.Add(edge.Key, edge.Value);            }        }                // Create line prefab        LineRenderer linePrefab = new GameObject().AddComponent<LineRenderer>();        linePrefab.transform.name = "Line";        linePrefab.numPositions = 0;        linePrefab.material = material;        linePrefab.startWidth = linePrefab.endWidth = lineWidth;        // Create first line        LineRenderer line = Instantiate(linePrefab.gameObject).GetComponent<LineRenderer>();        line.transform.parent = transform;        // This vector3 gets added to each line position, so it sits in front of the mesh        // Change the -0.1f to a positive number and it will sit behind the mesh        Vector3 bringFoward = new Vector3(0f, 0f, -0.1f);        // Loop through edge vertices in order        int startVert = 0;        int nextVert = startVert;        int highestVert = startVert;        while (true) {            // Add to line            line.numPositions++;            line.SetPosition(line.numPositions - 1, vertices[nextVert] + bringFoward);            // Get next vertex            nextVert = lookup[nextVert];            // Store highest vertex (to know what shape to move to next)            if (nextVert > highestVert) {                highestVert = nextVert;            }            // Shape complete            if (nextVert == startVert) {                // Finish this shape's line                line.numPositions++;                line.SetPosition(line.numPositions - 1, vertices[nextVert] + bringFoward);                // Go to next shape if one exists                if (lookup.ContainsKey(highestVert + 1)) {                    // Create new line                    line = Instantiate(linePrefab).GetComponent<LineRenderer>();                    line.transform.parent = transform;                    // Set starting and next vertices                    startVert = highestVert + 1;                    nextVert = startVert;                    // Continue to next loop                    continue;                }                // No more verts                break;            }        }    }}`
Unity Guide Books
Unity in Action C# Game Dev
See More Details
Unity From Zero to Proficiency
See More Details
Unity Cookbook
See More Details
Unity 2D Platformer Guide
See More Details

Nick Vogt   May 19, 2017
You're right. I had a prefab that I forgot about. I just updated the code to no longer need that external prefab. The prefab is now created in the code, and it's a little cleaner as well.
Jarrett Dunn   May 18, 2017
Question, did you leave out a step as in line 44 you are setting up a lineprefab for a game object which does not exist by default. The Resources.LoadGameObject>("Levels/Line");