Checking for duplicate materials
Correctness

At first, I'm afraid your code doesn't find all duplicates: If the compared materials don't use a texture or a color, they won't be marked as duplicates. In your code, if (hc) checks if the material has a color. If not, it is jumped over. If the other material has no color either, this could still be a duplicate.

Performance

The performance of your code is \$O(n^2)\$: For each additional item in allMat, the unique collection will be iterated one time. As this collection grows, this will take longer and longer. This can be certainly improved:

What you actually want to do, is "group" your Texture objects by equality. The groups with size == 1 will be your unique textures, the groups with size > 1 will contain your duplicates.

We can do this very easily using LINQ. All we need to do is implement a custom comparer, that knows how to compare two Texture instances:

public class MaterialComparer : IEqualityComparer&lt;Material&gt; 
{
    public bool Equals(Material x, Material y)
    {
        if (ReferenceEquals(x, y)) return true;

        if (x.shader.name != y.shader.name) return false;

        var xHasColor = x.HasProperty("_Color");
        var yHasColor = y.HasProperty("_Color");

        if (xHasColor != yHasColor) return false;
        if (xHasColor &amp;&amp; x.color != y.color) return false;

        var xHasTexture = x.HasProperty("_MainTex");
        var yHasTexture = y.HasProperty("_MainTex");

        if (xHasTexture != yHasTexture) return false;
        if (xHasTexture &amp;&amp; x.mainTexture != y.mainTexture) return false;

        return true;
    }

    public int GetHashCode(Material mat)
    {
        unchecked
        {
            var hasColor = mat.HasProperty("_Color");
            var hasTexture = mat.HasProperty("_MainTex");

            var hashCode = mat.shader.name.GetHashCode();
            hashCode = (hashCode * 397) ^ (hasTexture ? mat.mainTexture.GetHashCode() : 0);
            hashCode = (hashCode * 397) ^ (hasColor ? mat.color.GetHashCode() : 0);

            return hashCode;
        }
    }
}


The important thing here is to get GetHashCode right: This method is supposed to return two integers that MUST be equal when the compared objects are equal.

We can use it like that:

var groups = allMat.GroupBy(m =&gt; m, new MaterialComparer())
                .GroupBy(g =&gt; g.Count() == 1)
                .ToArray();

var unique = (groups.SingleOrDefault(g =&gt; g.Key) ?? Enumerable.Empty&lt;IEnumerable&lt;Material&gt;&gt;())
    .SelectMany(m =&gt; m).ToArray();

var duplicates = (groups.SingleOrDefault(g =&gt; !g.Key) ?? Enumerable.Empty&lt;IEnumerable&lt;Material&gt;&gt;())
    .SelectMany(m =&gt; m).ToArray();


I put this in a Unit Test to measure the performance for 20,000 random materials:

[TestMethod]
public void TestMaterials()
{
    var random = new Random();
    IEnumerable&lt;Material&gt; allMat = from i in Enumerable.Range(0, 20000)
                                let shader = random.Next(100)
                                let color = random.Next(50)
                                let texture = random.Next(50)
                                select new Material(shader.ToString(),
                                                    color == 0 ? null : color.ToString(),
                                                    texture == 0 ? null : texture.ToString());

    var comparator = new YourImplementation(allMat.ToArray());

    var stopwatch = Stopwatch.StartNew();

    comparator.InitShaderSorting();

    Console.WriteLine(stopwatch.Elapsed);
    stopwatch.Restart();

    var groups = allMat.GroupBy(m =&gt; m, new MaterialComparer())
                    .GroupBy(g =&gt; g.Count() == 1)
                    .ToArray();

    var unique = (groups.SingleOrDefault(g =&gt; g.Key) ?? Enumerable.Empty&lt;IEnumerable&lt;Material&gt;&gt;())
        .SelectMany(m =&gt; m).ToArray();

    var duplicates = (groups.SingleOrDefault(g =&gt; !g.Key) ?? Enumerable.Empty&lt;IEnumerable&lt;Material&gt;&gt;())
        .SelectMany(m =&gt; m).ToArray();

    Console.WriteLine(stopwatch.Elapsed);
}


Result:

00:00:14.0328998  // your custom implementation
00:00:00.0712459  // LINQ