我目前正在为Unity3D创建一个地形,专门用于运行应用程序的内存不足的移动设备。允许大小为15.000 x 15.000千米,高度为-1.000米到10.000米的地形,它的唯一限制是硬盘上的空间。
现在一切都运行正常,除了不正确地计算不同网格之间的法线(每个网格具有细分级别)。这是两张可视化问题的图片:
问题仅发生在从一个细分级别到另一个细分级别的转换中。如果两个网格具有相同的级别,则效果很好。我首先想到的是在计算法线时我会错过一些面孔,但似乎它们都包含在计算中。
每张脸的正常计算:
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();
在计算顶点周围的每个面的法线之后,我将所有面法线添加到顶点法线并对其进行标准化。结果显示在图片中,正如您在背景和网格本身中看到的那样,只要没有不同的细分级别,它就可以工作。
/// <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
计算当前网格的每个法线:
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
- 委托和2个样本处理程序:
/// <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);
问题很简单:为什么它不适用于不同的级别,我在计算中是否会遗漏某些内容?
答案 0 :(得分:1)
我仍然不知道为什么会发生这种情况,但在更换时......
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
- 方法。我不知道为什么会发生这种情况,但现在可行了。