计算最终在接缝处的 2 个网格之间的法线 [英] Calculating normals between 2 meshes ending up in seams

查看:25
本文介绍了计算最终在接缝处的 2 个网格之间的法线的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I currently creating a terrain for Unity3D which is specialized for mobile-devices with low memory for a running app. Allowing a terrain with a size of 15.000 x 15.000 kilometers and a height from -1.000 meters to 10.000 meters and it's only limits are the space on the hard disk.

现在一切正常,只是不同网格之间的法线(每个网格都有一个细分级别)没有正确计算.这里有两张图片可以形象化这个问题:

Everything is running fine right now except that the normals between different meshes ( each mesh has a subdivision level ) are not calculated correctly. Here are two pictures which visualize the problem:

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

The problem only occurs on a transition from one subdivision level to another. If both mesh have the same level it works well. I first thought i miss some faces when calculating the normals but it seems they are all included into the calculation.

每个人脸的法线计算:

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();

在计算顶点周围每个面的法线后,我将所有面法线添加到顶点法线并对其进行标准化.结果显示在图片中,正如您在背景和网格本身上看到的那样,只要没有不同的细分级别,它就可以工作.

After calculating the normal of each face around a vertex i add all the face-normals to the vertex-normal and normalize it. The result is shown in the pictures, and as you can see in the background and on the meshes itself it works as long there is no different subdivision level.

/// <summary>
/// This is a static indicies array which contains all indicies
/// for all possible meshes.
/// </summary>
private static readonly Int32[] // Subdivision
                             [] // All borders
                             [] Indicies = new Int32[8][][]; // Indicies

计算当前网格的每个法线:

Calculate each normal of the current mesh:

Int32 count = 0;
for (int y = 0; y < length; y++)
{
    for (int x = 0; x < length; x++)
    {
        ns[count++] = GetNormal(x, y, faces, vs);
    }
}

GetNormal 方法:

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;
}

CalculateNormal-方法:

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 */

AddFaceNormal-方法:

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;
}

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);
        }
    }
}

TransformPoint 方法:

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");
}

最后是 TranslationHandler-delegate 和 2 个示例处理程序:

And finally the TranslationHandler-delegate and 2 sample handlers:

/// <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);

问题

问题很简单:为什么它不适用于不同级别,我的计算中是否遗漏了什么?

Question

The question is simple: Why is it not working for different levels, do i miss something in my calculation?

推荐答案

我仍然不知道为什么会出现这种情况,但是当更换这个时....

I still don't know why it happens but when replacing this....

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 方法可以工作.我不知道为什么会这样,但现在它起作用了.

with another AddFaceNormal-method it works. I don't know why this happend but now it works.

这篇关于计算最终在接缝处的 2 个网格之间的法线的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆