我试图为Vector3s(或者更确切地说,VertexPositionNormalTextures)编写一个Comparer类,它将按顺时针顺序对它们的列表进行排序,以便修复我的背面剔除问题。我试图在网络上采用一种非常常见的方法,它在两个向量之间得到一个有符号的角度。但是,在运行时,我的列表抱怨排序方法不一致,也就是说两个项目在不同的传递上不一致地进行比较,或者一个项目与自身进行比较而不相等。
这是比较者类:
public class ClockwiseSorter : IComparer<VertexPositionNormalTexture>
{
private Vector3 center;
public ClockwiseSorter(Vector3 c)
{
center = c;
}
public int Compare(VertexPositionNormalTexture a, VertexPositionNormalTexture b)
{
Vector3 normal = Vector3.Cross(a.Position - center, b.Position - center);
normal.Normalize();
double theta = GetSignedAngleBetween2DVectors(a.Position - center, b.Position - center, Vector3.Cross(a.Position - center, normal));
if (theta > 0)
return -1;
else if (theta < 0)
return 1;
else
return 0;
}
/// Find the angle between two vectors. This will not only give the angle difference, but the direction.
/// For example, it may give you -1 radian, or 1 radian, depending on the direction. Angle given will be the
/// angle from the FromVector to the DestVector, in radians.
/// </summary>
/// <param name="FromVector">Vector to start at.</param>
/// <param name="DestVector">Destination vector.</param>
/// <param name="DestVectorsRight">Right vector of the destination vector</param>
/// <returns>Signed angle, in radians</returns>
/// <remarks>All three vectors must lie along the same plane.</remarks>
public static double GetSignedAngleBetween2DVectors(Vector3 FromVector, Vector3 DestVector, Vector3 DestVectorsRight)
{
FromVector.Normalize();
DestVector.Normalize();
DestVectorsRight.Normalize();
float forwardDot = Vector3.Dot(FromVector, DestVector);
float rightDot = Vector3.Dot(FromVector, DestVectorsRight);
// Keep dot in range to prevent rounding errors
forwardDot = MathHelper.Clamp(forwardDot, -1.0f, 1.0f);
double angleBetween = Math.Acos(forwardDot);
if (rightDot < 0.0f)
angleBetween *= -1.0f;
return angleBetween;
}
}
我通过平均所有向量的值得到中心向量:
private Vector3 AverageVectors(List<VertexPositionNormalTexture> vectors)
{
Vector3 sum = Vector3.Zero;
foreach (VertexPositionNormalTexture vector in vectors)
sum += vector.Position;
return (sum / vectors.Count);
}
我在某个地方搞砸了,没想到这个吗?或者我是否正确计算了法线或中心?背面剔除对我来说一直是个头疼的问题,我有点迫不及待地继续前进......
答案 0 :(得分:1)
如果你有一个带顶点A,B和C的三角形,
三角形法线是用叉积运算
进行的N = (B-A) x (C-A)
现在你必须确定正常的方向。
对于你在代码中使用的网格中心非常有用,但是如果网格不是凸面,它可能会提供错误的结果。
您必须确定从三角形中心到网格中心的法线和矢量构建之间的角度。
TriangleCenter= (A+B+C) / 3;
P = MeshCenter - TriangleCenter;
P.Normalize();
N.Normalize();
the dot product d = P.N = |P||N|.cos(alfa)
if (d>0) P and N are in the same direction (AntiClockWise order)
if (d<0) P and N are in opposite direction (Clockwise order)