Beispiel #1
0
        public static Vector2 ComputeGlobalTextureCoords(LatLon latlon, Ellipsoid ellipsoid)
        {
            Vector3 pos    = LatLonToPosition(latlon, ellipsoid);
            Vector3 normal = ellipsoid.GeodeticSurfaceNormal(pos);

            return(ComputeGlobalTextureCoordinate(normal));
        }
Beispiel #2
0
        // TODO may want to treat the poles as a tri-fan instead of a tri-strip, unless we do something more sophisticated to deal with the singularity at the poles.
        public Mesh GenerateSector(LatLonBoundingBox bbox, Ellipsoid ellipsoid, int numberOfStackPartitions, int numberOfSlicePartitions)
        {
            Mesh mesh = new Mesh();
            LatLonBoundingBox geometryBBox = bbox.Clamp();

            float deltaLat = geometryBBox.DeltaLat / numberOfStackPartitions;
            float deltaLon = geometryBBox.DeltaLon / numberOfSlicePartitions;

            // Create positions
            int            numberOfVertices = NumberOfVertices(numberOfStackPartitions, numberOfSlicePartitions);
            List <Vector3> positions        = new List <Vector3>(numberOfVertices);

            // Generates geometry
            for (int i = 0; i <= numberOfStackPartitions; i++)
            {
                float lat = i * deltaLat + geometryBBox.minLat;

                // To avoid singularities at the poles, don't let the latitude quite reach 90 degrees
                lat = Mathf.Clamp(lat, -90 + eps, 90 - eps);

                // Phi is like latitude, but ranges from [0, pi]. Add 90 degrees and convert to radians to get phi.
                float phi    = (lat + 90f) * Mathf.Deg2Rad;
                float sinPhi = Mathf.Sin(phi);

                // Generate positions on Ellipsoid following Eq. 4.4 from "3D Engine Design for Virtual Globes":
                // x = a cos(theta) sin(phi)
                // y = a sin(theta) sing(phi)
                // z = c cos(phi)
                float xSinPhi = ellipsoid.Radii.x * sinPhi;
                float ySinPhi = ellipsoid.Radii.y * sinPhi;
                float zCosPhi = ellipsoid.Radii.z * Mathf.Cos(phi);

                for (int j = 0; j <= numberOfSlicePartitions; j++)
                {
                    float lon = j * deltaLon + geometryBBox.minLon;

                    float   theta = lon * Mathf.Deg2Rad;
                    Vector3 pos   = new Vector3(Mathf.Cos(theta) * xSinPhi, Mathf.Sin(theta) * ySinPhi, zCosPhi);
                    positions.Add(pos);
                }
            }

            // Compute normals & texture coordinates
            List <Vector3> normals = new List <Vector3>(numberOfVertices);
            List <Vector2> uvs     = new List <Vector2>(numberOfVertices);

            for (int i = 0; i < positions.Count; i++)
            {
                Vector3 normal = ellipsoid.GeodeticSurfaceNormal(positions[i]);

                normals.Add(normal);
                uvs.Add(GetUvFromNormal(geometryBBox, bbox, ellipsoid, normal));
            }

            // Compute triangle indices
            List <int> indices = new List <int>(NumberOfTriangles(numberOfSlicePartitions, numberOfStackPartitions) * 3);

            // Generate a triangle strip for each row
            for (int i = 0; i < numberOfStackPartitions; ++i)
            {
                int topRowOffset    = i * (numberOfSlicePartitions + 1);
                int bottomRowOffset = (i + 1) * (numberOfSlicePartitions + 1);

                for (int j = 0; j < numberOfSlicePartitions; ++j)
                {
                    indices.Add(bottomRowOffset + j);
                    indices.Add(bottomRowOffset + j + 1);
                    indices.Add(topRowOffset + j + 1);

                    indices.Add(bottomRowOffset + j);
                    indices.Add(topRowOffset + j + 1);
                    indices.Add(topRowOffset + j);
                }
            }

            List <Color> colors = new List <Color>();

            while (colors.Count < positions.Count)
            {
                colors.Add(Color.white);
            }

            // Generate skirt geometry to help hide cracks between adjacent levels of detail
            AddSkirt(positions, normals, uvs, indices, numberOfStackPartitions, numberOfSlicePartitions, ellipsoid.Radii.x * skirtHeightFactor);

            // Add colors verts for the skirt so we can fade it on if needed
            while (colors.Count < positions.Count)
            {
                colors.Add(new Color(0, 0, 0, 0));
            }

            mesh.SetVertices(positions);
            mesh.SetColors(colors);
            mesh.uv = uvs.ToArray();
            mesh.SetNormals(normals);
            mesh.triangles = indices.ToArray();

            return(mesh);
        }
Beispiel #3
0
        /// <summary>
        /// Generate geometry for an ellipsoid globe.
        /// </summary>
        /// <param name="ellipsoid">Ellipsoid model to use to generate geometry</param>
        /// <param name="numberOfStackPartitions">Number of horizontal tessellations</param>
        /// <param name="numberOfSlicePartitions">Number of vertical tessellations</param>
        /// <returns></returns>
        // TODO this method is mostly redundant with GenerateSector. See if we can consolidate this code
        public Mesh GenerateGlobe(Ellipsoid ellipsoid, int numberOfStackPartitions, int numberOfSlicePartitions)
        {
            Mesh mesh = new Mesh();

            // Precompute sin/cos
            float[] cosTheta = new float[numberOfSlicePartitions];
            float[] sinTheta = new float[numberOfSlicePartitions];

            for (int i = 0; i < numberOfSlicePartitions; ++i)
            {
                float theta = 2 * Mathf.PI * ((float)i / numberOfSlicePartitions);
                cosTheta[i] = Mathf.Cos(theta);
                sinTheta[i] = Mathf.Sin(theta);
            }

            // Create positions
            List <Vector3> positions = new List <Vector3> {
                new Vector3(0, 0, ellipsoid.Radii.z)
            };

            // Add top vertex

            // For each latitude stack...
            for (int i = 1; i < numberOfStackPartitions; ++i)
            {
                float phi    = Mathf.PI * ((float)i / numberOfStackPartitions);
                float sinPhi = Mathf.Sin(phi);

                float xSinPhi = ellipsoid.Radii.x * sinPhi;
                float ySinPhi = ellipsoid.Radii.y * sinPhi;
                float zCosPhi = ellipsoid.Radii.z * Mathf.Cos(phi);

                // For each longitude slice, add a position
                for (int j = 0; j < numberOfSlicePartitions; ++j)
                {
                    positions.Add(new Vector3(cosTheta[j] * xSinPhi, sinTheta[j] * ySinPhi, zCosPhi));
                }
            }
            // Add bottom vertex
            positions.Add(new Vector3(0, 0, -ellipsoid.Radii.z));

            // Compute normals and UVs
            List <Vector3> normals = new List <Vector3>();
            List <Vector2> uvs     = new List <Vector2>();

            for (int i = 0; i < positions.Count; i++)
            {
                Vector3 normal = ellipsoid.GeodeticSurfaceNormal(positions[i]);
                normals.Add(normal);
                uvs.Add(GetUvFromNormal(null, null, ellipsoid, normal));
            }

            // Compute triangle indices
            List <int> indices = new List <int>(NumberOfTriangles(numberOfSlicePartitions, numberOfStackPartitions) * 3);

            // Triangle fan top row
            for (int j = 1; j < numberOfSlicePartitions; ++j)
            {
                indices.Add(0);
                indices.Add(j);
                indices.Add(j + 1);
            }
            indices.Add(0);
            indices.Add(numberOfStackPartitions);
            indices.Add(1);

            // Middle rows are triangle strips
            for (int i = 0; i < numberOfStackPartitions - 2; ++i)
            {
                int topRowOffset    = i * numberOfSlicePartitions + 1;
                int bottomRowOffset = (i + 1) * numberOfSlicePartitions + 1;

                for (int j = 0; j < numberOfSlicePartitions - 1; ++j)
                {
                    indices.Add(bottomRowOffset + j);
                    indices.Add(bottomRowOffset + j + 1);
                    indices.Add(topRowOffset + j + 1);

                    indices.Add(bottomRowOffset + j);
                    indices.Add(topRowOffset + j + 1);
                    indices.Add(topRowOffset + j);
                }
                indices.Add(bottomRowOffset + numberOfSlicePartitions - 1);
                indices.Add(bottomRowOffset);
                indices.Add(topRowOffset);

                indices.Add(bottomRowOffset + numberOfSlicePartitions - 1);
                indices.Add(topRowOffset);
                indices.Add(topRowOffset + numberOfSlicePartitions - 1);
            }

            // Triangle fan bottom row
            int lastPosition = positions.Count - 1;

            for (int j = lastPosition - 1; j > lastPosition - numberOfSlicePartitions; --j)
            {
                indices.Add(lastPosition);
                indices.Add(j);
                indices.Add(j - 1);
            }
            indices.Add(lastPosition);
            indices.Add(lastPosition - numberOfSlicePartitions);
            indices.Add(lastPosition - 1);

            mesh.SetVertices(positions);
            mesh.uv = uvs.ToArray();
            mesh.SetNormals(normals);
            mesh.triangles = indices.ToArray();

            return(mesh);
        }