我正在尝试重新创建一个类似于直接x的mesh.Intersect(Vector3 rayPos,Vector3 rayDir,out IntersInformation3 nearestHit)函数的函数,我已经成功地将它变为一个点,如下面的一系列代码所示我自己的Traingle.Intersect(Vector3D rayPos,Vector3D rayDir,IntersectInformation3D nearestHit)。我已经能够使用所有必要的信息填充IntersectInformation3D类,但是一个 - Dist。我打算使用它作为获取nearestHit的源,如下面的代码所示,但它没有给我一致的结果。任何人都可以通过代码的这一部分来告诉我在哪里弄错了。如果需要任何额外的代码,请告诉我。
// Summary:
// Describes the intersection of a ray and a triangle.
public class IntersectInformation3D
{
/// <summary>
/// Initializes a new instance of the IntersectInformation3D class.
/// </summary>
public IntersectInformation3D() { }
/// <summary>
/// Retrieves or sets the distance along the ray where the intersection occurred.
/// </summary>
public float Dist { get; set; }
/// <summary>
/// Retrieves or sets the index of the triangle that intersected the ray.
/// </summary>
public int FaceIndex { get; set; }
/// <summary>
/// Retrieves or sets the index of the triangle that intersected the ray.
/// </summary>
public int TriangleIndex { get; set; }
/// <summary>
/// Retrieves or sets the barycentric coordinate within the triangle where the ray intersects.
/// </summary>
public float U { get; set; }
/// <summary>
/// Retrieves or sets the barycentric coordinate within the triangle where the
/// ray intersects.
/// </summary>
public float V { get; set; }
/// <summary>
/// Obtains a string representation of the current instance.
/// </summary>
/// <returns>String that represents the object.</returns>
public override string ToString()
{
return string.Format("Face={0}, Triangle={1}, tu={2}, tv={3}, Dist={4}", FaceIndex, TriangleIndex, Math.Round((decimal)U, 2), Math.Round((decimal)V, 2), Math.Round((decimal)Dist, 2));
}
}
public class Vector3D
{
public double X { get; set; }
public double Y { get; set; }
public double Z { get; set; }
public Vector3D(double x, double y, double z)
{
X = x;
Y = y;
Z = z;
}
public double SumComponentSqrs()
{
return (this.X * this.X + this.Y * this.Y + this.Z * this.Z);
}
public double Magnitude
{
get
{
return Math.Sqrt(SumComponentSqrs());
}
}
public Vector3D Normalize()
{
double magnitude = this.Magnitude;
if (magnitude == 0)
{
return (new Vector3D()); //throw new DivideByZeroException("Can not normalize a vector when it's magnitude is zero");
}
else
{
return (new Vector3D(X, Y, Z) / magnitude);
}
}
}
public class Utility
{
public static double Dot3(Vector3D p1, Vector3D p2)
{
return ((p1.X * p2.X) + (p1.Y * p2.Y) + (p1.Z * p2.Z));
}
public static Vector3D Cross3(Vector3D a, Vector3D b)
{
double outx = a.Y * b.Z - a.Z * b.Y;
double outy = a.Z * b.X - a.X * b.Z;
double outz = a.X * b.Y - a.Y * b.X;
return new Vector3D(outx, outy, outz);
}
public static double modv(Vector3D v)
{
return System.Math.Sqrt(v.X * v.X + v.Y * v.Y + v.Z * v.Z);
}
}
public class Triangle : Face
{
/// <summary>
/// Retrieves the normal for this triangle.
/// </summary>
/// <returns>Vector3D object that represents the normal of this triangle</returns>
public Vector3D GetNormal()
{
Vector3D p1 = VertexInformation.Vertex[0];
Vector3D p2 = VertexInformation.Vertex[1];
Vector3D p3 = VertexInformation.Vertex[2];
Vector3D u = p2 - p1;
Vector3D w = p3 - p1;
Vector3D n = Utility.Cross3(u, w);
return n.Normalize();
}
/// <summary>
/// Checks for intersection between a ray and this triangle
/// </summary>
/// <param name="rayPos">A Vector3D structure that specifies the origin coordinate of the ray</param>
/// <param name="rayDir">A Vector3D structure that specifies the direction of the ray</param>
/// <returns> Intersection Information (when it exists) </returns>
public bool Intersect(Vector3D rayPos, Vector3D rayDir, out IntersectInformation3D closestHit)
{
closestHit = new IntersectInformation3D();
// Triangle vertices
Vector3D V1 = VertexInformation.Vertex[0];
Vector3D V2 = VertexInformation.Vertex[1];
Vector3D V3 = VertexInformation.Vertex[2];
//Find vectors for two edges sharing V1
Vector3D e1 = V2 - V1; //Edge1
Vector3D e2 = V3 - V1; //Edge2
//Begin calculating determinant - also used to calculate u parameter
Vector3D P = Utility.Cross3(rayDir, e2);
//if determinant is near zero, ray lies in plane of triangle
float det = (float)Utility.Dot3(e1, P);
//NOT CULLING
if (det > -float.Epsilon && det < float.Epsilon) return false;
float inv_det = 1.0f / det;
//calculate distance from V1 to ray origin
Vector3D T = rayPos - V1;
//Calculate u parameter and test bound
float u = (float)Utility.Dot3(T, P) * inv_det;
//The intersection lies outside of the triangle
if (u < 0.0f || u > 1.0f) return false;
//Prepare to test v parameter
Vector3D Q = Utility.Cross3(T, e1);
//Calculate V parameter and test bound
float v = (float)Utility.Dot3(rayDir, Q) * inv_det;
//The intersection lies outside of the triangle
if (v < 0.0f || u + v > 1.0f) return false;
float t = (float)Utility.Dot3(e2, Q) * inv_det;
if (t > float.Epsilon)
{
Vector3D basePoint = new Vector3D();
//ray intersection
closestHit.U = u;
closestHit.V = v;
closestHit.Dist = DistToPoint(rayPos, out basePoint);
return true;
}
// No hit, no win
return false;
}
/// <summary>
/// Calculates the distance between this triangle's intersect point
/// with a ray at position P
/// </summary>
/// <param name="P">A Vector3D structure that specifies the origin coordinate of the ray</param>
/// <param name="B"></param>
/// <returns></returns>
public float DistToPoint(Vector3D P, out Vector3D B)
{
Vector3D normal = GetNormal();
Vector3D V0 = VertexInformation.Vertex[0];
float sn = -(float)-Utility.Dot3(normal, (P - V0));
float sd = (float)Utility.Dot3(normal, normal);
float sb = sn / sd;
B = P + sb * normal;
return (float)Utility.modv(P - B);
}
}
public bool Intersect(Vector3D rayPos, Vector3D rayDir, out IntersectInformation3D closestHit)
{
bool result = false;
int FaceIndex = 0;
IList<IntersectInformation3D> intersectInfos = new List<IntersectInformation3D>();
foreach (Face face in faces)
{
int TriangleIndex = 0;
foreach (Triangle triangle in face.GetTriangles())
{
IntersectInformation3D intersectInfo = new IntersectInformation3D();
bool tmp = triangle.Intersect(rayPos, rayDir, out intersectInfo);
if (tmp)
{
result = tmp;
intersectInfo.FaceIndex = FaceIndex;
intersectInfo.TriangleIndex = TriangleIndex;
intersectInfos.Add(intersectInfo);
}
TriangleIndex++;
}
FaceIndex++;
}
closestHit = new IntersectInformation3D();
closestHit.Dist = float.MinValue;
foreach (IntersectInformation3D intersectInfo in intersectInfos)
{
if (intersectInfo.Dist > closestHit.Dist)
closestHit = intersectInfo;
}
return result;
}
答案 0 :(得分:1)
问题1:
如果我清楚地了解你,你想要计算光线起点和交点之间的距离。这两点是函数DistToPoint的参数。但为什么你在下面的代码中传递basePoint
?这点是什么意思?
if (t > float.Epsilon)
{
Vector3D basePoint = new Vector3D();
//ray intersection
closestHit.U = u;
closestHit.V = v;
closestHit.Dist = DistToPoint(rayPos, out basePoint);
return true;
}
问题2:
在下面的代码中,VertexInformation
做了什么?它来自哪里?
public float DistToPoint(Vector3D P, out Vector3D B)
{
Vector3D normal = GetNormal();
Vector3D V0 = VertexInformation.Vertex[0];
float sn = -(float)-Utility.Dot3(normal, (P - V0));
float sd = (float)Utility.Dot3(normal, normal);
float sb = sn / sd;
B = P + sb * normal;
return (float)Utility.modv(P - B);
}
我不确定上面的代码是做什么的,但是AFAIK,要计算两个3d点P1和P2之间的距离,你可以简单地使用下面的公式。
你可以计算函数Intersect
中的交点,假设你得到u,v和t,那么点是(1 - u - v)V0 + uV1 + vV2
,其中V0,V1和V2是三角形的3个点。有了这一点和光线的起点,你可以应用公式,这只是代码行。
答案 1 :(得分:0)
实际上答案始终在代码中:float t
是我正在寻找的距离。它似乎没有提前工作,可能是因为我在其他地方犯了一个错误。