コード例 #1
0
    public float SphereCost(CameraGraphPortalNode Start, CameraGraphPortalNode End, CameraGraphSphereNode Focus)
    {
        // From http://www.oskam.ch/research/camera_control_2009.pdf Section 4.1
        // C(e_ij) = d(i,j) + a*d(i,j)(1-v(e_ij)

        // How much the cost is influenced by visibility.
        const float Alpha = 100f;

        // First, find the sphere shared between the portals
        CameraGraphSphereNode Sphere;

        if (Start.A == End.A)
        {
            Sphere = Start.A;
        }
        else
        {
            Sphere = Start.B;
        }

        float Dist = (Start.transform.position - End.transform.position).magnitude;

        float Visibility = 0;

        if (!Sphere.VisibilityValues.TryGetValue(Focus, out Visibility))
        {
            Debug.Log("Couldn't get visibility from " + Sphere + " to " + Focus);
            Debug.DrawLine(Sphere.transform.position, Focus.transform.position, Color.magenta, 1.0f);
        }
        return(Dist + Alpha * Dist * (1 - Visibility));
    }
コード例 #2
0
    IEnumerator GeneratePortals()
    {
        Debug.Log("Generating Portals");
        // Tell each sphere node to connect to it's neighbors
        // I'm gonna use n^2 because spheres are fast

        for (int i = 0; i < Spheres.Count; ++i)
        {
            CameraGraphSphereNode A = Spheres[i] as CameraGraphSphereNode;
            for (int j = i + 1; j < Spheres.Count; ++j)
            {
                CameraGraphSphereNode B = Spheres[j] as CameraGraphSphereNode;

                // Check if the nodes intersect, and create a portal if they do
                if (A.Intersects(B))
                {
                    CameraGraphPortalNode Node = ConnectPortal(A, B);
                    Portals.Add(Node);

                    // Yield to main thread if we've done enough operations
                    if (ShouldOperationYield())
                    {
                        yield return(new WaitForEndOfFrame());
                    }
                }
            }
        }

        yield return(null);
    }
コード例 #3
0
    CameraPath ComputePath(Vector3 Start, Vector3 End, Vector3 Focus)
    {
        CameraPath Path = new CameraPath();

        Path.Next = Start;

        // Figure out what portals we want
        CameraGraphPortalNode StartNode = Graph.GetClosestPortal(Start);
        CameraGraphPortalNode EndNode   = Graph.GetClosestPortal(End);

        CameraGraphSphereNode FocusEdge = Graph.GetClosestSphere(Focus);


        // A* that shit!
        List <CameraGraphPortalNode> PortalPath = GetPortalPath(StartNode, EndNode, FocusEdge);

        // Get the points as positions
        foreach (CameraGraphPortalNode Portal in PortalPath)
        {
            Path.Points.Enqueue(Portal.transform.position);
        }

        // Finally, add the endpoint to the back of the queue
        Path.Points.Enqueue(End);
        return(Path);
    }
コード例 #4
0
    public float CostEstimate(CameraGraphPortalNode Start, CameraGraphPortalNode End)
    {
        // From http://www.oskam.ch/research/camera_control_2009.pdf Section 4.1
        // H(n) = d(n, e)

        float Dist = (End.transform.position - Start.transform.position).magnitude;

        return(Dist);
    }
コード例 #5
0
    private IEnumerator LinkPortals()
    {
        Debug.Log("Linking Portals");

        // Figure out how big our graph is
        int NumNodes = Portals.Count;
        int NumArcs  = 0;

        // The number of arcs is equal to the sum of the number of spheres exit arcs - 1
        for (int i = 0; i < SphereGraph.numNodes; ++i)
        {
            NumArcs += SphereGraph.NumArcsForNode(i) - 1;
        }
        // Remember to double your stuff
        int BidirectionOffset = NumArcs;

        NumArcs *= 2;

        PortalGraph = new SimpleGraph(NumNodes, NumArcs);

        // We can just look at all the spheres and connect their portals to make sure the web is complete
        foreach (CameraGraphSphereNode Sphere in Spheres)
        {
            int SphereIndex = Spheres.IndexOf(Sphere);

            for (int i = 0; i < Sphere.IntersectionPortals.Count; ++i)
            {
                CameraGraphPortalNode A = Sphere.IntersectionPortals[i] as CameraGraphPortalNode;
                for (int j = i; j < Sphere.IntersectionPortals.Count; ++j)
                {
                    CameraGraphPortalNode B = Sphere.IntersectionPortals[j] as CameraGraphPortalNode;

                    // Indices for the sphere nodes
                    int PortalAIndex = Portals.IndexOf(A);
                    int PortalBIndex = Portals.IndexOf(B);

                    // Link A and B bidirectionally
                    PortalGraph.SetNodeArc(PortalAIndex, SphereIndex, PortalBIndex);
                    PortalGraph.SetNodeArc(PortalBIndex, SphereIndex + BidirectionOffset, PortalAIndex);

                    // Debug draw
                    Debug.DrawLine(A.transform.position, B.transform.position, Color.magenta, 1.0f);

                    // Yield to draw
                    if (ShouldOperationYield())
                    {
                        yield return(new WaitForEndOfFrame());
                    }
                }
            }
        }
        Debug.Log("Linked " + PortalGraph.numNodes + " spheres with " + PortalGraph.numArcs + " arcs");

        yield return(null);
    }
コード例 #6
0
    public CameraGraphPortalNode GetClosestPortal(Vector3 Position)
    {
        float BestSqrDist          = Mathf.Infinity;
        CameraGraphPortalNode Best = Portals[0] as CameraGraphPortalNode;

        // This is unoptimized
        foreach (CameraGraphPortalNode Portal in Portals)
        {
            float SqrDist = (Position - Portal.transform.position).sqrMagnitude;

            if (SqrDist < BestSqrDist)
            {
                BestSqrDist = SqrDist;
                Best        = Portal;
            }
        }

        return(Best);
    }
コード例 #7
0
    CameraGraphPortalNode GetLowest(Dictionary <CameraGraphPortalNode, float> D, HashSet <CameraGraphPortalNode> Set)
    {
        CameraGraphPortalNode BestPortal = null;
        float BestValue = Mathf.Infinity;

        foreach (CameraGraphPortalNode Portal in Set)
        {
            float PortalValue = Mathf.Infinity;
            D.TryGetValue(Portal, out PortalValue);

            if (PortalValue < BestValue)
            {
                BestValue  = PortalValue;
                BestPortal = Portal;
            }
        }

        return(BestPortal);
    }
コード例 #8
0
    private CameraGraphPortalNode ConnectPortal(CameraGraphSphereNode A, CameraGraphSphereNode B)
    {
        // Create the child object
        GameObject PortalObj = new GameObject("Portal");

        PortalObj.transform.SetParent(transform);
        PortalObj.layer = gameObject.layer;

        // Attatch the portal node logic
        CameraGraphPortalNode Portal = PortalObj.AddComponent <CameraGraphPortalNode>();


        Portal.Connect(A, B);
        Portal.Graph = this;

        // Tell the Spheres that there's a portal connecting them
        A.IntersectionPortals.Add(Portal);
        B.IntersectionPortals.Add(Portal);

        return(Portal);
    }
コード例 #9
0
    List <CameraGraphPortalNode> ReconstructPath(Dictionary <CameraGraphPortalNode, CameraGraphPortalNode> CameFrom, CameraGraphPortalNode Current)
    {
        List <CameraGraphPortalNode> Total = new List <CameraGraphPortalNode>();

        Total.Add(Current);

        while (CameFrom.ContainsKey(Current))
        {
            Current = CameFrom[Current];
            Total.Insert(0, Current);
        }

        return(Total);
    }
コード例 #10
0
    private List <CameraGraphPortalNode> GetPortalPath(CameraGraphPortalNode Start, CameraGraphPortalNode End, CameraGraphSphereNode Target)
    {
        // Nodes already evaluated
        HashSet <CameraGraphPortalNode> Closed = new HashSet <CameraGraphPortalNode>();
        // Nodes to be evaluated
        HashSet <CameraGraphPortalNode> Open = new HashSet <CameraGraphPortalNode>();
        // How we got to each node we visit
        Dictionary <CameraGraphPortalNode, CameraGraphPortalNode> CameFrom
            = new Dictionary <CameraGraphPortalNode, CameraGraphPortalNode>();
        // The value of each of the nodes we've visited
        Dictionary <CameraGraphPortalNode, float> GScore = new Dictionary <CameraGraphPortalNode, float>();
        // The estimated total cost from start to each node
        Dictionary <CameraGraphPortalNode, float> FScore = new Dictionary <CameraGraphPortalNode, float>();

        // We start at the begining
        Open.Add(Start);
        GScore[Start] = 0;
        FScore[Start] = Graph.CostEstimate(Start, End);


        // Now the looping
        while (Open.Count != 0)
        {
            // Current portal is the node in open with the lowest F score value
            CameraGraphPortalNode Current = GetLowest(FScore, Open);

            // Are we there?
            if (Current == End)
            {
                return(ReconstructPath(CameFrom, Current));
            }
            // Mark the node as visited
            Open.Remove(Current);
            Closed.Add(Current);

            Debug.Log("Visited " + Current);

            // Add the node's neighbors to the open set
            ArrayList Neighbors = new ArrayList();
            Neighbors.AddRange(Current.A.IntersectionPortals);
            Neighbors.AddRange(Current.B.IntersectionPortals);

            foreach (CameraGraphPortalNode Neighbor in Neighbors)
            {
                // Skip nodes we've already visited
                if (Closed.Contains(Neighbor))
                {
                    continue;
                }

                float TentativeGScore = GScore[Current] + Graph.SphereCost(Current, Neighbor, Target);

                // If the node is good enough, then add it to our path
                if (!Open.Contains(Neighbor) || TentativeGScore < GScore[Neighbor])
                {
                    CameFrom[Neighbor] = Current;
                    GScore[Neighbor]   = TentativeGScore;
                    FScore[Neighbor]   = TentativeGScore + Graph.CostEstimate(Neighbor, End);
                    if (!Open.Contains(Neighbor))
                    {
                        Open.Add(Neighbor);
                    }
                }
            }
        }

        // If we can't path, then we give up
        Debug.Log("Camera Pathing failure!");
        return(new List <CameraGraphPortalNode>());
    }