C# 计算最终形成接缝的两个网格之间的法线 我的任务

C# 计算最终形成接缝的两个网格之间的法线 我的任务,c#,3d,mesh,normals,C#,3d,Mesh,Normals,我目前正在为Unity3D创建一个地形,该地形专门用于内存不足的移动设备,用于运行应用程序。允许地形大小为15000 x 15000公里,高度为-1000米到10000米,唯一的限制是硬盘上的空间 处境 除了不同网格之间的法线(每个网格都有一个细分级别)计算不正确之外,现在一切都正常。以下是两张显示问题的图片: 该问题仅在从一个细分级别过渡到另一个细分级别时发生。如果两个网格具有相同的级别,则效果良好。我最初以为在计算法线时会遗漏一些面,但它们似乎都包含在计算中 一些代码 每个面的正常计算:

我目前正在为Unity3D创建一个地形,该地形专门用于内存不足的移动设备,用于运行应用程序。允许地形大小为15000 x 15000公里,高度为-1000米到10000米,唯一的限制是硬盘上的空间

处境 除了不同网格之间的法线(每个网格都有一个细分级别)计算不正确之外,现在一切都正常。以下是两张显示问题的图片:

该问题仅在从一个细分级别过渡到另一个细分级别时发生。如果两个网格具有相同的级别,则效果良好。我最初以为在计算法线时会遗漏一些面,但它们似乎都包含在计算中

一些代码 每个面的正常计算:

Vector3 u = vertices[item.Face1] - vertices[item.Face0];
Vector3 v = vertices[item.Face2] - vertices[item.Face0];

Vector3 fn = new Vector3((u.Y * v.Z) - (u.Z * v.Y), (u.Z * v.X) - (u.X * v.Z), (u.X * v.Y) - (u.Y * v.X));
fn.Normalize();
在计算顶点周围每个面的法线后,我将所有面法线添加到顶点法线并对其进行规格化。结果显示在图片中,正如您在背景和网格本身上看到的,只要没有不同的细分级别,它就可以工作

还有代码吗
CalculateNormal
-方法:

private unsafe Vector3 GetNormal(Int32 x, Int32 y, Int32[] indicies, Vector3* vertices)
{
    Vector3 normal = new Vector3();
    CalculateNormal(x, y, indicies, vertices, ref normal);
    normal.Normalize();
    // Calculate all face normals and normalize
    return normal;
}
private unsafe void CalculateNormal(Int32 x, Int32 y, Int32[] indicies, Vector3* vertices, ref Vector3 normal)
{
    Int32 p = ((y * Length) + x);
    Int32 length = Length - 1;

    foreach (Face item in FindFaces(this, indicies, p))
    {
        Vector3 u = vertices[item.Face1] - vertices[item.Face0];
        Vector3 v = vertices[item.Face2] - vertices[item.Face0];

        Vector3 fn = new Vector3((u.Y * v.Z) - (u.Z * v.Y), (u.Z * v.X) - (u.X * v.Z), (u.X * v.Y) - (u.Y * v.X));
        fn.Normalize();
        normal += fn;
    }

    SegmentHeighmap heightmap;
    if (x == 0 && y == 0)
    {
        foreach (Face item in FindFaces(Neighbor.Left, out heightmap, TranslateLeftX, TranslateLeftY, x, y))
        {
            Face f = item;
            AddFaceNormal(ref f, ref normal, heightmap);
        }

... /* A lot of more code here for each possible combination */
private static void AddFaceNormal(ref Face face, ref Vector3 normal, SegmentHeighmap heightmap)
{
    Vector3 v0;
    Vector3 v1;
    Vector3 v2;
    heightmap.CalculateVertex(face.Face0, out v0);
    heightmap.CalculateVertex(face.Face1, out v1);
    heightmap.CalculateVertex(face.Face2, out v2);

    Vector3 u = v1 - v0;
    Vector3 v = v2 - v0;

    Vector3 fn = new Vector3((u.Y * v.Z) - (u.Z * v.Y), (u.Z * v.X) - (u.X * v.Z), (u.X * v.Y) - (u.Y * v.X));
    fn.Normalize();
    normal += fn;
}
private Int32 TranslatePoint(Int32 point, Segment segment)
{
    Int32 subdiv = segment.SubdivisionLevel - Parent.SubdivisionLevel;
    if (subdiv == 0)
    {
        return point;
    }
    if (Math.Abs(subdiv) == 1)
    {
        if (subdiv > 0)
        {
            return point * 2;
        }
        return point / 2;
    }

    throw new InvalidOperationException("Subdivision difference is greater than 1");
}
AddFaceNormal
-方法:

private unsafe Vector3 GetNormal(Int32 x, Int32 y, Int32[] indicies, Vector3* vertices)
{
    Vector3 normal = new Vector3();
    CalculateNormal(x, y, indicies, vertices, ref normal);
    normal.Normalize();
    // Calculate all face normals and normalize
    return normal;
}
private unsafe void CalculateNormal(Int32 x, Int32 y, Int32[] indicies, Vector3* vertices, ref Vector3 normal)
{
    Int32 p = ((y * Length) + x);
    Int32 length = Length - 1;

    foreach (Face item in FindFaces(this, indicies, p))
    {
        Vector3 u = vertices[item.Face1] - vertices[item.Face0];
        Vector3 v = vertices[item.Face2] - vertices[item.Face0];

        Vector3 fn = new Vector3((u.Y * v.Z) - (u.Z * v.Y), (u.Z * v.X) - (u.X * v.Z), (u.X * v.Y) - (u.Y * v.X));
        fn.Normalize();
        normal += fn;
    }

    SegmentHeighmap heightmap;
    if (x == 0 && y == 0)
    {
        foreach (Face item in FindFaces(Neighbor.Left, out heightmap, TranslateLeftX, TranslateLeftY, x, y))
        {
            Face f = item;
            AddFaceNormal(ref f, ref normal, heightmap);
        }

... /* A lot of more code here for each possible combination */
private static void AddFaceNormal(ref Face face, ref Vector3 normal, SegmentHeighmap heightmap)
{
    Vector3 v0;
    Vector3 v1;
    Vector3 v2;
    heightmap.CalculateVertex(face.Face0, out v0);
    heightmap.CalculateVertex(face.Face1, out v1);
    heightmap.CalculateVertex(face.Face2, out v2);

    Vector3 u = v1 - v0;
    Vector3 v = v2 - v0;

    Vector3 fn = new Vector3((u.Y * v.Z) - (u.Z * v.Y), (u.Z * v.X) - (u.X * v.Z), (u.X * v.Y) - (u.Y * v.X));
    fn.Normalize();
    normal += fn;
}
private Int32 TranslatePoint(Int32 point, Segment segment)
{
    Int32 subdiv = segment.SubdivisionLevel - Parent.SubdivisionLevel;
    if (subdiv == 0)
    {
        return point;
    }
    if (Math.Abs(subdiv) == 1)
    {
        if (subdiv > 0)
        {
            return point * 2;
        }
        return point / 2;
    }

    throw new InvalidOperationException("Subdivision difference is greater than 1");
}
FindFaces
-方法:

private IEnumerable<Face> FindFaces(Neighbor neighbor, out SegmentHeighmap heightmap, TranslationHandler translateX, TranslationHandler translateY, Int32 x, Int32 y)
{
    Segment segment = Segment.GetNeighbor(neighbor);
    if (segment != null)
    {
        heightmap = segment.Heighmap;
        Int32 point = ((translateY(this, heightmap, y) * Length) + translateX(this, heightmap, x));

        return FindFaces(heightmap, null, point);
    }
    heightmap = null;
    return Enumerable.Empty<Face>();
}
private IEnumerable<Face> FindFaces(SegmentHeighmap heightmap, Int32[] indicies, Int32 point)
{
    indicies = indicies ?? Indicies[heightmap.Segment.SubdivisionLevel][heightmap.SideFlag];

    for (int i = 0; i < indicies.Length; i += 3)
    {
        Int32 a = indicies[i], b = indicies[i + 1], c = indicies[i + 2];
        if (a == point || b == point || c == point)
        {
            yield return new Face(a, b, c);
        }
    }
}
最后是
TranslationHandler
-委托和两个示例处理程序:

/// <summary>
/// Handles the translation from one coordinate space into another
/// This handler is used internal only
/// </summary>
private delegate Int32 TranslationHandler(SegmentHeighmap @this, SegmentHeighmap other, Int32 v);

private static readonly TranslationHandler TranslateLeftX = (t, o, v) => o.Length - 1;
private static readonly TranslationHandler TranslateLeftY = (t, o, v) => t.TranslatePoint(v, o.Segment);
//
///处理从一个坐标空间到另一个坐标空间的转换
///此处理程序仅在内部使用
/// 
私有委托Int32 TranslationHandler(SegmentHeighmap@this,SegmentHeighmap-other,Int32 v);
私有静态只读TranslationHandler TranslateLeftX=(t,o,v)=>o.Length-1;
私有静态只读TranslationHandler TranslateLeftY=(t,o,v)=>t.TranslatePoint(v,o.Segment);
问题:
问题很简单:为什么它不适用于不同的级别,我的计算中是否遗漏了一些内容?

我仍然不知道为什么会发生这种情况,但当替换这个时

Vector3 u = vertices[item.Face1] - vertices[item.Face0];
Vector3 v = vertices[item.Face2] - vertices[item.Face0];

Vector3 fn = new Vector3((u.Y * v.Z) - (u.Z * v.Y), (u.Z * v.X) - (u.X * v.Z), (u.X * v.Y) - (u.Y * v.X));
fn.Normalize();
normal += fn;

使用另一种
AddFaceNormal
-方法,它可以工作。我不知道为什么会发生这种情况,但现在它起作用了。

而且您确定在计算顶点法线时,您正在遍历所有相邻的面,也就是属于另一个子网格的面?您可能希望提供更多的代码来帮助我们了解问题所在。@ChristianRau我已经在一个网格上使用调试器对其进行了测试。这是一种相对简单的技术,我将顶点转换为另一个网格的坐标空间,并迭代每个面,以找到属于接缝顶点的所有面。我可以在这里发布计算的代码,但是这是很多东西。添加了所有代码,除了标记生成,这是另一大块代码。