Loading files
fe3105350This file is pinned to the selected release. Download the original to open it in your design tool.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Numerics;
using System.Text;
namespace SharpGLTF.Geometry
{
static class VertexNormalsFactory
{
#pragma warning disable CA1034 // Nested types should not be visible
public interface IMeshPrimitive
#pragma warning restore CA1034 // Nested types should not be visible
{
int VertexCount { get; }
Vector3 GetVertexPosition(int idx);
void SetVertexNormal(int idx, Vector3 normal);
IEnumerable<(int A, int B, int C)> GetTriangleIndices();
}
public static void CalculateSmoothNormals<T>(IReadOnlyList<T> primitives)
where T : IMeshPrimitive
{
Guard.NotNull(primitives, nameof(primitives));
var normalMap = new Dictionary<Vector3, Vector3>();
// calculate
foreach (var primitive in primitives)
{
foreach (var (ta, tb, tc) in primitive.GetTriangleIndices())
{
var p1 = primitive.GetVertexPosition(ta);
var p2 = primitive.GetVertexPosition(tb);
var p3 = primitive.GetVertexPosition(tc);
var d = Vector3.Cross(p2 - p1, p3 - p1);
_AddDirection(normalMap, p1, d);
_AddDirection(normalMap, p2, d);
_AddDirection(normalMap, p3, d);
}
}
// normalize
foreach (var pos in normalMap.Keys.ToList())
{
var nrm = Vector3.Normalize(normalMap[pos]);
normalMap[pos] = nrm._IsFinite() && nrm.LengthSquared() > 0.5f ? nrm : Vector3.UnitZ;
}
// apply
foreach (var primitive in primitives)
{
for (int i = 0; i < primitive.VertexCount; ++i)
{
var pos = primitive.GetVertexPosition(i);
if (normalMap.TryGetValue(pos, out Vector3 nrm))
{
primitive.SetVertexNormal(i, nrm);
}
else
{
primitive.SetVertexNormal(i, Vector3.UnitZ);
}
}
}
}
private static void _AddDirection(Dictionary<Vector3, Vector3> dict, Vector3 pos, Vector3 dir)
{
if (!dir._IsFinite()) return;
if (!dict.TryGetValue(pos, out Vector3 n)) n = Vector3.Zero;
dict[pos] = n + dir;
}
}
}