Exemple #1
0
        protected override TerrainMeshData RescaleMeshHeight(TerrainMeshData referenceMeshData)
        {
            float scale  = _metadata.HeightScale / TerrainModelScale;
            float radius = _metadata.Radius;

            Vector3[] referenceVertices = referenceMeshData.Vertices;
            int       vertexCount       = referenceVertices.Length;

            Vector3[] rescaledVertices = new Vector3[vertexCount];

            for (int i = 0; i < vertexCount; i++)
            {
                Vector3 vertex = referenceVertices[i];

                // Calculate new distance
                float distance    = vertex.magnitude;
                float newDistance = (distance - radius) * scale + radius;

                // Apply new distance
                vertex *= newDistance / distance;

                // Store vertex in new array.
                rescaledVertices[i] = vertex;
            }

            return(new TerrainMeshData()
            {
                Vertices = rescaledVertices
                           // TODO Normals
            });
        }
        // TODO Use a struct or class to pass DEM metadata (ie. scale) to the GenerateMesh methods.

        /// <summary>
        ///     Generates the mesh data and store it in the member variable.
        /// </summary>
        protected override void Generate()
        {
            Stopwatch stopwatch = new Stopwatch();

            stopwatch.Start();

            // TODO Add support other image types if necessary.

            // Create and execute task to convert first image into an RGBImage object.
            // The task can be executed syncronously in the same thread since Generate()
            // is called outside of the main thread.
            IntensityImage baseImage = new LoadIntensityImageFromFileTask(_demFilePaths[0]).ExecuteInCurrentThread();

            Debug.Log($"Took {stopwatch.ElapsedMilliseconds}ms to read DEM image file.");


            // If there are more files to process, then load and merge each image.
            for (int i = 1; i < _demFilePaths.Length; i++)
            {
                // Load the additional image.
                IntensityImage image = new LoadIntensityImageFromFileTask(_demFilePaths[i]).ExecuteInCurrentThread();

                // Merge the images together.
                try {
                    baseImage.Merge(image, -32768);

                    // NOTE: -32768 happens to be the "blank" value for the global DEM (and probably
                    // any other files in 16-bit integer). This may not work for files in other formats.
                    // Update if necessary.
                }
                catch (Exception e) {
                    Debug.LogError(e.Message);
                    continue;
                }
            }

            TerrainMeshData[] meshData = new TerrainMeshData[_metadata.TotalLodLevels];

            for (int lodLevel = 0; lodLevel <= _metadata.LodLevels; lodLevel++)
            {
                int downsample = 1 << (_metadata.BaseDownsample + lodLevel);
                meshData[lodLevel] = GenerateForLod(baseImage, downsample);
            }

            if (_metadata.GenerateAdditionalPhysicsLod)
            {
                meshData[meshData.Length - 1] = GenerateForLod(baseImage, 1 << _metadata.PhysicsDownsample);
            }

            _progress = 1.0f;
            _meshData = meshData;
        }
        protected override TerrainMeshData RescaleMeshHeight(TerrainMeshData referenceMeshData)
        {
            float scale  = _metadata.HeightScale / TerrainModelScale;
            float radius = _metadata.Radius;

            Vector3 min = new Vector3(float.PositiveInfinity, 0, 0);

            Vector3[] referenceVertices = referenceMeshData.Vertices;
            int       vertexCount       = referenceVertices.Length;

            Vector3[] rescaledVertices = new Vector3[vertexCount];

            for (int i = 0; i < vertexCount; i++)
            {
                // Undo radius offset
                Vector3 vertex = referenceVertices[i] + new Vector3(radius, 0, 0);

                // Calculate new distance
                float distance    = vertex.magnitude;
                float newDistance = (distance - radius) * scale + radius;

                // Apply new distance
                vertex *= newDistance / distance;

                // Redo radius offset
                vertex -= new Vector3(radius, 0, 0);

                // Store vertex in new array.
                rescaledVertices[i] = vertex;

                // Keep track of minimum.
                if (vertex.x < min.x)
                {
                    min = vertex;
                }
            }

            Vector3[] referenceExtraVertices = referenceMeshData.ExtraVertices;
            int       extraVertexCount       = referenceExtraVertices.Length;

            Vector3[] rescaledExtraVertices = new Vector3[extraVertexCount];

            for (int i = 0; i < extraVertexCount; i++)
            {
                Vector3 vertex;

                // Only the first half of the vertex follows the terrain coutours;
                // the second half is the flat base.
                if (i >= extraVertexCount / 2)
                {
                    vertex = referenceExtraVertices[i];
                    rescaledExtraVertices[i] = new Vector3(min.x, vertex.y, vertex.z);
                    continue;
                }

                // Undo radius offset
                vertex = referenceExtraVertices[i] + new Vector3(radius, 0, 0);

                // Calculate new distance
                float distance    = vertex.magnitude;
                float newDistance = (distance - radius) * scale + radius;

                // Apply new distance
                vertex *= newDistance / distance;

                // Redo radius offset
                vertex -= new Vector3(radius, 0, 0);

                // Store vertex in new array.
                rescaledExtraVertices[i] = vertex;
            }


            return(new TerrainMeshData()
            {
                Vertices = rescaledVertices,
                ExtraVertices = rescaledExtraVertices,
                MinimumVertex = min
                                // TODO Normals
            });
        }
        protected override void Generate()
        {
            float latIncrement = _boundingBox.LatSwing / (LatLongVertCount - 1);
            float lonIncrement = _boundingBox.LonSwing / (LatLongVertCount - 1);

            Vector3[] verts     = new Vector3[LatLongVertCount * LatLongVertCount];
            Vector2[] uvs       = new Vector2[LatLongVertCount * LatLongVertCount];
            Vector3[] edgeVerts = new Vector3[8 * (LatLongVertCount - 1) + 2];

            Vector2 latLongOffset = BoundingBoxUtils.MedianLatLon(_boundingBox);

            Vector3 min = new Vector3(float.PositiveInfinity, 0, 0);

            int yIndex = 0, vertIndex = 0;

            for (float vy = _boundingBox.LatStart; yIndex < LatLongVertCount; vy += latIncrement)
            {
                // Create a new vertex using the latitude angle. The coordinates of this vertex
                // will serve as a base for all the other vertices of the same latitude.
                Vector3 baseLatVertex = _metadata.Radius * GenerateBaseLatitudeVertex(vy);

                int xIndex = 0;
                for (float vx = _boundingBox.LonStart; xIndex < LatLongVertCount; vx += lonIncrement)
                {
                    Vector3 vertex = GenerateVertex(baseLatVertex, vx, latLongOffset, _metadata.Radius);

                    // Keep track of minimum; this will be used later to position the terrain on the table-top.
                    if (vertex.x < min.x)
                    {
                        min = vertex;
                    }

                    // Add to edge vertices
                    if (yIndex == 0)
                    {
                        edgeVerts[xIndex] = vertex;
                    }
                    else if (xIndex == LatLongVertCount - 1)
                    {
                        edgeVerts[LatLongVertCount + yIndex - 1] = vertex;
                    }
                    else if (yIndex == LatLongVertCount - 1)
                    {
                        edgeVerts[3 * (LatLongVertCount - 1) - xIndex] = vertex;
                    }
                    else if (xIndex == 0)
                    {
                        edgeVerts[4 * (LatLongVertCount - 1) - yIndex] = vertex;
                    }

                    verts[vertIndex] = vertex;
                    uvs[vertIndex]   = GenerateUVCoord(xIndex, yIndex, LatLongVertCount, LatLongVertCount, _uvBounds);

                    xIndex++;
                    vertIndex++;
                }

                yIndex++;
            }

            // Finish generating the data for the terrain edge.
            ProcessEdgeVertices(edgeVerts, min.x);

            _progress = 1f;

            // Only one LOD is generated.
            _meshData = new TerrainMeshData[] {
                new TerrainMeshData()
                {
                    Vertices       = verts,
                    TexCoords      = uvs,
                    Triangles      = GenerateTriangles(LatLongVertCount, LatLongVertCount),
                    ExtraVertices  = edgeVerts,
                    ExtraTriangles = GenerateTriangles(edgeVerts.Length / 2, 2, true),
                    MinimumVertex  = min
                }
            };
        }