实现nearestHit

时间:2014-06-08 21:16:03

标签: directx

我正在尝试重新创建一个类似于直接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;
    }

2 个答案:

答案 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之间的距离,你可以简单地使用下面的公式。

enter image description here

你可以计算函数Intersect中的交点,假设你得到u,v和t,那么点是(1 - u - v)V0 + uV1 + vV2,其中V0,V1和V2是三角形的3个点。有了这一点和光线的起点,你可以应用公式,这只是代码行。

答案 1 :(得分:0)

实际上答案始终在代码中:float t是我正在寻找的距离。它似乎没有提前工作,可能是因为我在其他地方犯了一个错误。