예제 #1
0
    // Update is called once per frame
    void Update()
    {
        HexSphere hexSphere  = sphere.GetSphere();
        Icosphere gameSphere = hexSphere.GetHexMap();

        if (gameSphere == null)
        {
            return;
        }

        if (Input.GetButtonDown("Select"))
        {
            Ray        ray = Camera.main.ScreenPointToRay(Input.mousePosition);
            RaycastHit hit;
            if (Physics.Raycast(ray, out hit, Mathf.Infinity, LayerMask.GetMask("Sphere")))
            {
                if (outlineHighlight != null)
                {
                    GameObject.Destroy(outlineHighlight);
                }

                GameObject obj = hit.collider.gameObject;

                HexIdentifier hex = obj.GetComponent <HexIdentifier>();

                if (hex != null)
                {
                    selected = hex.location;

                    float rad = gameSphere.Radius;

                    gameSphere.SetRadius(rad + 0.001f);

                    outlineHighlight = new GameObject();

                    outlineHighlight.transform.position += sphere.transform.position;
                    outlineHighlight.transform.Rotate(sphere.transform.eulerAngles);

                    outlineHighlight.name = "Outline Highlight";
                    MeshFilter   mf = outlineHighlight.AddComponent <MeshFilter>();
                    MeshRenderer mr = outlineHighlight.AddComponent <MeshRenderer>();
                    mr.material = new Material(Shader.Find("Transparent/Diffuse"));

                    HexSphere.RenderTile(mf.mesh, selected, gameSphere);

                    if (new List <SCoord>(gameSphere.GetNeighbors(selected)).Count == 5)
                    {
                        mr.material.SetTexture("_MainTex", pentHighlight);
                    }
                    else
                    {
                        mr.material.SetTexture("_MainTex", hexHighlight);
                    }

                    gameSphere.SetRadius(rad);
                }
            }
        }
    }
예제 #2
0
    private static float GetScaleFactor(Icosphere sphere, float edgeLength)
    {
        List <SCoord> coordinates = new List <SCoord>(sphere.Coordinates);
        // Compute the scaling factor to meet the target edge length
        // Get the distance from the pole to one of its neighbors
        Vector3 scaleVec1 = sphere.GetPoint(coordinates[0]);
        IEnumerator <SCoord> scaleNeighbors = sphere.GetNeighbors(coordinates[0]).GetEnumerator();

        scaleNeighbors.MoveNext();
        Vector3 scaleVec2 = sphere.GetPoint(scaleNeighbors.Current);
        float   dist      = Vector3.Distance(scaleVec1, scaleVec2);

        // Compute the new scale factor and set this for the sphere
        float sf = edgeLength / dist;

        return(sf);
    }
예제 #3
0
    // Start is called before the first frame update
    void Start()
    {
        // Make the icosphere
        sphere = new Icosphere(transform.position, radius);

        for (int sub = 0; sub < subdivsions; sub++)
        {
            sphere = sphere.SubdivideSphere();
        }

        // Make the faces of the icosphere
        foreach (SCoord coord in sphere.Coordinates)
        {
            // Get the 3d coordinate of the sphere
            Vector3 point = sphere.GetPoint(coord);


            // Get the rotation of the face to make it tangent to the sphere
            Vector3 rotation = SCoord.GetRotation(coord);

            // Get the kind of object
            GameObject newObj = null;
            int        degree = sphere.GetDegree(coord);
            if (degree == 5)
            {
                newObj = Instantiate(pentagonPrefab);
            }
            else
            {
                newObj = Instantiate(hexagonPrefab);
            }

            // Place and rotate object tangent to the sphere
            newObj.transform.eulerAngles = rotation;
            newObj.transform.position    = point;
            newObj.transform.SetParent(this.transform);


            // Rotate the face to be line up correclty
            IEnumerator <SCoord> neighbors = sphere.GetNeighbors(coord).GetEnumerator();
            neighbors.MoveNext();
            SCoord neighbor = neighbors.Current;

            Vector3 targetVec = Vector3.ProjectOnPlane(neighbor.ToEuclidian() - coord.ToEuclidian(), newObj.transform.up).normalized;

            float angle = Mathf.Acos(Vector3.Dot(newObj.transform.right.normalized, targetVec));
            if (float.IsNaN(angle))
            {
                angle = 180;
            }
            Vector3 cross = Vector3.Cross(newObj.transform.right.normalized, targetVec);

            if (Vector3.Dot(newObj.transform.up.normalized, cross) < 0)
            {
                angle *= -1;
            }

            angle *= 180 / Mathf.PI;

            Debug.Log(angle);

            newObj.transform.Rotate(0, angle, 0, Space.Self);
            tiles.Add(coord, newObj);
        }
    }
예제 #4
0
    public static void RenderTile(Mesh mesh, SCoord tileCenter, Icosphere hexSphere)
    {
        // Make a linked list of the coordinate's neighbors
        LinkedList <SCoord> neighbors;

        // hexes are not triangles
        neighbors = new LinkedList <SCoord>(hexSphere.GetNeighbors(tileCenter));

        // Make list of vertices
        List <Vector3> vertices = new List <Vector3>(neighbors.Count + 1);
        // Make list of normals for each vertex
        List <Vector3> normals = new List <Vector3>(neighbors.Count + 1);
        // Make list of UV coordinates for each vertex
        List <Vector2> uvLocations = new List <Vector2>(neighbors.Count + 1);

        // Setup lookup table for vertices
        Dictionary <SCoord, int> keyLookup = new Dictionary <SCoord, int>();

        keyLookup.Add(tileCenter, keyLookup.Count);
        uvLocations.Add(new Vector2(0.5f, 0.5f));
        vertices.Add(hexSphere.GetPoint(tileCenter));
        normals.Add(tileCenter.ToEuclidian());

        float radPerVertex = Mathf.PI * 2 / neighbors.Count;

        SCoord startVertex = neighbors.First.Value;
        SCoord source      = startVertex;

        neighbors.RemoveFirst();

        // Get the order of neighbors (forward or backward just wrapping around center)
        LinkedList <SCoord> orderedNeighbors = new LinkedList <SCoord>();

        orderedNeighbors.AddLast(startVertex);

        // Calculate the teselated edges of the hexagon/pentagon
        while (neighbors.Count > 1)
        {
            // Find the next SCoord in the sequence of neighbors (neighbor to origin that is
            // adjacent to the previous neighbor)
            LinkedListNode <SCoord> nextVertex = neighbors.First;
            while (!new List <SCoord>(hexSphere.GetNeighbors(nextVertex.Value)).Contains(source))
            {
                nextVertex = nextVertex.Next;
            }
            orderedNeighbors.AddLast(nextVertex.Value);

            // Save current vertex as previous vertex
            source = nextVertex.Value;
            // Remove current vertex so it is not checked again
            neighbors.Remove(nextVertex);
        }
        // Finish list of ordered neighbors
        orderedNeighbors.AddLast(neighbors.First.Value);

        foreach (SCoord n in orderedNeighbors)
        {
            keyLookup.Add(n, keyLookup.Count);
        }

        List <SCoord> neighborList = new List <SCoord>(orderedNeighbors);
        List <int>    triangleList = new List <int>();

        for (int idx = 0; idx < neighborList.Count; idx++)
        {
            // Get the centroid of the three adjacent tiles
            SCoord vert = SCoord.GetCentroid(tileCenter, neighborList[idx], neighborList[(idx + 1) % neighborList.Count]);

            // Sort the coordinates in the correct order so the face is visible
            SCoord[] triangleCoords = SCoord.SortClockwiseOrder(tileCenter,
                                                                neighborList[idx],
                                                                neighborList[(idx + 1) % neighborList.Count]);

            // Add the vertex
            vertices.Add(hexSphere.GetPoint(vert));
            // Add the normal vector of the vertex
            normals.Add(vert.ToEuclidian());
            // Add UV coordinate for this vertex
            Vector2 uv = new Vector2(0.5f + Mathf.Cos(radPerVertex * idx) * 0.5f,
                                     0.5f + Mathf.Sin(radPerVertex * idx) * 0.5f);
            uvLocations.Add(new Vector2(0.5f + Mathf.Cos(radPerVertex * idx) * 0.5f,
                                        0.5f + Mathf.Sin(radPerVertex * idx) * 0.5f));

            // Add the triangles (set of three vertices)
            triangleList.Add(keyLookup[triangleCoords[2]]);
            triangleList.Add(keyLookup[triangleCoords[1]]);
            triangleList.Add(keyLookup[triangleCoords[0]]);
        }

        // Flatten out the center of the hex so it doesn't arch out
        Vector3 flatCenter = Vector3.zero;

        for (int i = 1; i < vertices.Count; i++)
        {
            flatCenter += vertices[i];
        }
        flatCenter /= (vertices.Count - 1);
        vertices[0] = flatCenter;

        // assign values to mesh
        mesh.vertices  = vertices.ToArray();
        mesh.normals   = normals.ToArray();
        mesh.triangles = triangleList.ToArray();
        mesh.uv        = uvLocations.ToArray();
    }