Ejemplo n.º 1
0
    // Real-time Collision Detection, p179.
    public float RayCast(Vector3 from, Vector3 to, float maxFraction = 1.0f)
    {
        float tMin = float.MinValue;
        float tMax = float.MaxValue;

        Vector3 d    = to - from;
        Vector3 absD = VectorUtil.Abs(d);

        for (int i = 0; i < 3; ++i)
        {
            float dComp    = VectorUtil.GetComopnent(d, i);
            float absDComp = VectorUtil.GetComopnent(absD, i);
            float fromComp = VectorUtil.GetComopnent(from, i);
            float minComp  = VectorUtil.GetComopnent(Min, i);
            float maxComp  = VectorUtil.GetComopnent(Max, i);

            if (absDComp < float.Epsilon)
            {
                // parallel?
                if (fromComp < minComp || maxComp < fromComp)
                {
                    return(float.MinValue);
                }
            }
            else
            {
                float invD = 1.0f / dComp;
                float t1   = (minComp - fromComp) * invD;
                float t2   = (maxComp - fromComp) * invD;

                if (t1 > t2)
                {
                    float temp = t1;
                    t1 = t2;
                    t2 = temp;
                }

                tMin = Mathf.Max(tMin, t1);
                tMax = Mathf.Min(tMax, t2);

                if (tMin > tMax)
                {
                    return(float.MinValue);
                }
            }
        }

        // does the ray start inside the box?
        // does the ray intersect beyond the max fraction?
        if (tMin < 0.0f || maxFraction < tMin)
        {
            return(float.MinValue);
        }

        // intersection detected
        return(tMin);
    }
Ejemplo n.º 2
0
    public bool RayCast(Vector3 from, Vector3 to, RayCastCallback callback = null)
    {
        Vector3 r = to - from;

        r.Normalize();

        float maxFraction = 1.0f;

        // v is perpendicular to the segment.
        Vector3 v    = VectorUtil.FindOrthogonal(r).normalized;
        Vector3 absV = VectorUtil.Abs(v);

        // build a bounding box for the segment.
        Aabb rayBounds = Aabb.Empty;

        rayBounds.Include(from);
        rayBounds.Include(to);

        m_stack.Clear();
        m_stack.Push(m_root);

        bool hitAnyBounds = false;

        while (m_stack.Count > 0)
        {
            int index = m_stack.Pop();
            if (index == Null)
            {
                continue;
            }

            if (!Aabb.Intersects(m_nodes[index].Bounds, rayBounds))
            {
                continue;
            }

            // Separating axis for segment (Gino, p80).
            // |dot(v, a - c)| > dot(|v|, h)
            Vector3 c          = m_nodes[index].Bounds.Center;
            Vector3 h          = m_nodes[index].Bounds.HalfExtents;
            float   separation = Mathf.Abs(Vector3.Dot(v, from - c)) - Vector3.Dot(absV, h);
            if (separation > 0.0f)
            {
                continue;
            }

            if (m_nodes[index].IsLeaf)
            {
                Aabb tightBounds = m_nodes[index].Bounds;
                tightBounds.Expand(-FatBoundsRadius);
                float t = tightBounds.RayCast(from, to, maxFraction);
                if (t < 0.0f)
                {
                    continue;
                }

                hitAnyBounds = true;

                float newMaxFraction =
                    callback != null
            ? callback(from, to, m_nodes[index].UserData)
            : maxFraction;

                if (newMaxFraction >= 0.0f)
                {
                    // Update segment bounding box.
                    maxFraction = newMaxFraction;
                    Vector3 newTo = from + maxFraction * (to - from);
                    rayBounds.Min = VectorUtil.Min(from, newTo);
                    rayBounds.Max = VectorUtil.Max(from, newTo);
                }
            }
            else
            {
                m_stack.Push(m_nodes[index].ChildA);
                m_stack.Push(m_nodes[index].ChildB);
            }
        }

        return(hitAnyBounds);
    }
Ejemplo n.º 3
0
    private static void CreateStraightRampPart(
        StructureGeometry structure, bool isLeftRamp,
        Vertex cornerTopLeft1, Vertex cornerTopLeft2, Vertex cornerTopRight1, Vertex cornerTopRight2,
        Vertex cornerBottomLeft1, Vertex cornerBottomLeft2, Vertex cornerBottomRight1, Vertex cornerBottomRight2,
        bool addLeftSide, bool addRightSide, int segmentWidth, int segmentLength, float curvature, RenderGeometry.FaceType rampFaceType, RenderGeometry.FaceType sideFaceType)
    {
        bool hasBase = (cornerTopLeft1 != cornerBottomLeft1) && (cornerTopRight1 != cornerBottomRight1);

        SurfaceComponentGeometry rampFace = SurfaceComponentGeometries.CreatePlaneGeometry(1, 1, segmentWidth, segmentLength, 0, rampFaceType);
        SurfaceComponentGeometry rampBottom = SurfaceComponentGeometries.CreatePlaneGeometry(1, 1, 1, segmentLength, 1, sideFaceType);
        SurfaceComponentGeometry rampLeftSide = null, rampRightSide = null;

        if (addLeftSide && (cornerTopLeft1 != cornerBottomLeft1))
        {
            rampLeftSide = SurfaceComponentGeometries.CreatePlaneGeometry(1, 1, 1, segmentLength, 2, sideFaceType);
        }
        if (addRightSide && (cornerTopRight1 != cornerBottomRight1))
        {
            rampRightSide = SurfaceComponentGeometries.CreatePlaneGeometry(1, 1, 1, segmentLength, 3, sideFaceType);
        }

        if (curvature != 0)
        {
            float angle = -curvature * Mathf.PI / 2;
            rampFace.ApplySpaceWarp(new SpaceWarp($"sin(x*{angle})/{angle}", $"(1-cos(x*{angle}))/{angle}", "z"));
        }
        // Fit to a 45 degree ramp, then scale.
        rampFace.ApplyLinearTransform(
            Matrix4x4.Translate(cornerTopLeft1.p) *
            Matrix4x4.Scale(VectorUtil.Abs(cornerTopRight2.p - cornerTopLeft1.p)) *
            MatrixUtil.PointToPointTransform(
                rampFace.corners[0].p, rampFace.corners[3].p, rampFace.corners[1].p,
                Vector3.zero, new Vector3(1, isLeftRamp ? 1 : -1, 0), Vector3.forward));

        structure.CreateFace(rampFace, false, cornerTopLeft1, cornerTopLeft2, cornerTopRight2, cornerTopRight1);
        structure.CreateFace(rampBottom, true, cornerBottomRight1, cornerBottomRight2, cornerBottomLeft2, cornerBottomLeft1);
        if (rampLeftSide != null)
        {
            structure.CreateFace(rampLeftSide, true, cornerBottomLeft1, cornerBottomLeft2, cornerTopLeft2, cornerTopLeft1);
        }
        if (rampRightSide != null)
        {
            structure.CreateFace(rampRightSide, true, cornerTopRight1, cornerTopRight2, cornerBottomRight2, cornerBottomRight1);
        }

        var backVertices = new List <Vector3>();

        backVertices.Add(isLeftRamp ? cornerBottomRight1.p : cornerBottomLeft1.p);
        if (isLeftRamp && hasBase)
        {
            backVertices.Add(cornerBottomLeft1.p);
        }
        backVertices.Add(rampFace.boundaries[3].Last().prev.vertex.p);
        backVertices.AddRange(rampFace.boundaries[3].Select(e => e.vertex.p).Reverse());
        if (!isLeftRamp && hasBase)
        {
            backVertices.Add(cornerBottomRight1.p);
        }
        var movedBackVertices = backVertices.Select(p => p + (cornerTopLeft2.p - cornerTopLeft1.p));
        var frontVertices = movedBackVertices.Take(1).Concat(movedBackVertices.Reverse().Take(backVertices.Count - 1)).ToList();

        SurfaceComponentGeometry backFace  = SurfaceComponentGeometries.CreateStarConvexPolygonGeometry(backVertices, 4, RenderGeometry.FaceType.Smooth);
        SurfaceComponentGeometry frontFace = SurfaceComponentGeometries.CreateStarConvexPolygonGeometry(frontVertices, 5, RenderGeometry.FaceType.Smooth);

        if (hasBase)
        {
            if (isLeftRamp)
            {
                backFace.CombineBoundaries(1, 1, segmentWidth, 1);
                frontFace.CombineBoundaries(1, segmentWidth, 1, 1);
                structure.CreateFace(backFace, false, cornerBottomRight1, cornerBottomLeft1, cornerTopLeft1, cornerTopRight1);
                structure.CreateFace(frontFace, false, cornerBottomRight2, cornerTopRight2, cornerTopLeft2, cornerBottomLeft2);
            }
            else
            {
                backFace.CombineBoundaries(1, segmentWidth, 1, 1);
                frontFace.CombineBoundaries(1, 1, segmentWidth, 1);
                structure.CreateFace(backFace, false, cornerBottomLeft1, cornerTopLeft1, cornerTopRight1, cornerBottomRight1);
                structure.CreateFace(frontFace, false, cornerBottomLeft2, cornerBottomRight2, cornerTopRight2, cornerTopLeft2);
            }
        }
        else
        {
            backFace.CombineBoundaries(1, segmentWidth, 1);
            frontFace.CombineBoundaries(1, segmentWidth, 1);
            structure.CreateFace(backFace, false, isLeftRamp ? cornerBottomRight1 : cornerBottomLeft1, cornerTopLeft1, cornerTopRight1);
            structure.CreateFace(frontFace, false, isLeftRamp ? cornerBottomRight2 : cornerBottomLeft2, cornerTopRight2, cornerTopLeft2);
        }
    }