예제 #1
0
    // this function generates a copy of the original planet map and adds a number of rows to the top and bottom of the map (to prevent pole pinching)
    float[,] PrepareHeightMap(PG_Planet pgPlanet)
    {
        // compute height of the new map
        var height = PG_Planet.c_height + m_numPolePaddingRows * 2;

        // allocate the new map
        var buffer = new float[height, PG_Planet.c_width];

        // get the maximum height for the top row
        var maximumHeight = 0.0f;

        for (var x = 0; x < PG_Planet.c_width; x++)
        {
            if (pgPlanet.m_color[0, x] == m_topPaddingColor)
            {
                if (pgPlanet.m_height[0, x] > maximumHeight)
                {
                    maximumHeight = pgPlanet.m_height[0, x];
                }
            }
        }

        if (m_topPaddingColor == pgPlanet.m_waterColor)
        {
            maximumHeight = 0.0f;
        }

        // set the height of the padded rows
        for (var i = 0; i < m_numPolePaddingRows; i++)
        {
            var y = m_numPolePaddingRows - i - 1;

            var t = (float)(i + 1) / (float)m_numPolePaddingRows;

            t *= 2.0f;

            for (var x = 0; x < PG_Planet.c_width; x++)
            {
                var originalHeight = pgPlanet.m_height[0, x];

                buffer[y, x] = Mathf.Lerp(originalHeight, maximumHeight, t);
            }
        }

        // get the maximum height for the bottom row
        maximumHeight = 0.0f;

        for (var x = 0; x < PG_Planet.c_width; x++)
        {
            if (pgPlanet.m_color[PG_Planet.c_height - 1, x] == m_bottomPaddingColor)
            {
                if (pgPlanet.m_height[0, x] > maximumHeight)
                {
                    maximumHeight = pgPlanet.m_height[0, x];
                }
            }
        }

        if (m_bottomPaddingColor == pgPlanet.m_waterColor)
        {
            maximumHeight = 0.0f;
        }

        // set the height of the padded rows
        for (var i = 0; i < m_numPolePaddingRows; i++)
        {
            var y = m_numPolePaddingRows + i + PG_Planet.c_height;

            var t = (float)(i + 1) / (float)m_numPolePaddingRows;

            t *= 2.0f;

            for (var x = 0; x < PG_Planet.c_width; x++)
            {
                var originalHeight = pgPlanet.m_height[PG_Planet.c_height - 1, x];

                buffer[y, x] = Mathf.Lerp(originalHeight, maximumHeight, t);
            }
        }

        // copy the original map into the are in between the padded rows
        for (var y = 0; y < PG_Planet.c_height; y++)
        {
            for (var x = 0; x < PG_Planet.c_width; x++)
            {
                buffer[y + m_numPolePaddingRows, x] = pgPlanet.m_height[y, x];
            }
        }

        // all done
        return(buffer);
    }
예제 #2
0
    // this function generates a copy of the original planet map and adds a number of rows to the top and bottom of the map (to prevent pole pinching)
    Color[,] PrepareColorMap(PG_Planet pgPlanet)
    {
        // compute height of the new map
        var height = PG_Planet.c_height + m_numPolePaddingRows * 2;

        // allocate the new map
        var buffer = new Color[height, PG_Planet.c_width];

        // find the most used color on the top row
        var tally = new Dictionary <Color, int>();

        for (var x = 0; x < PG_Planet.c_width; x++)
        {
            var color = pgPlanet.m_color[0, x];

            if (!tally.ContainsKey(color))
            {
                tally.Add(color, 0);
            }

            tally[color]++;
        }

        var mostUsedColor = Color.black;
        var mostUsedCount = 0;

        foreach (var key in tally.Keys)
        {
            if (tally[key] > mostUsedCount)
            {
                mostUsedCount = tally[key];
                mostUsedColor = key;
            }
        }

        m_topPaddingColor = mostUsedColor;

        // add north pole color
        for (var i = 0; i < m_numPolePaddingRows; i++)
        {
            var y = m_numPolePaddingRows - i - 1;

            for (var x = 0; x < PG_Planet.c_width; x++)
            {
                buffer[y, x] = m_topPaddingColor;
            }
        }


        // find the most used color on the bottom row
        tally = new Dictionary <Color, int>();

        for (var x = 0; x < PG_Planet.c_width; x++)
        {
            var color = pgPlanet.m_color[PG_Planet.c_height - 1, x];

            if (!tally.ContainsKey(color))
            {
                tally.Add(color, 0);
            }

            tally[color]++;
        }

        mostUsedColor = Color.black;
        mostUsedCount = 0;

        foreach (var key in tally.Keys)
        {
            if (tally[key] > mostUsedCount)
            {
                mostUsedCount = tally[key];
                mostUsedColor = key;
            }
        }

        m_bottomPaddingColor = mostUsedColor;

        // add south pole color
        for (var i = 0; i < m_numPolePaddingRows; i++)
        {
            var y = m_numPolePaddingRows + i + PG_Planet.c_height;

            for (var x = 0; x < PG_Planet.c_width; x++)
            {
                buffer[y, x] = m_bottomPaddingColor;
            }
        }

        // copy the original map into the are in between the padded rows
        for (var y = 0; y < PG_Planet.c_height; y++)
        {
            for (var x = 0; x < PG_Planet.c_width; x++)
            {
                buffer[y + m_numPolePaddingRows, x] = pgPlanet.m_color[y, x];
            }
        }

        // all done
        return(buffer);
    }
예제 #3
0
    // call this to generate the planet texture maps
    bool GeneratePlanetTextureMaps(PG_Planet pgPlanet, string filename)
    {
        // vars for the progress bar
        var currentStep = 1;
        var totalSteps  = 8;

        // update the progress bar
        EditorUtility.DisplayProgressBar("Planet " + (pgPlanet.m_id + 1), "Preparing color map...", (float)currentStep++ / totalSteps);

        // prepare the color map
        var preparedColorMap = PrepareColorMap(pgPlanet);

        if (m_debugMode)
        {
            EditorUtility.DisplayProgressBar("Planet " + (pgPlanet.m_id + 1), "Saving prepared color map...", 0.0f);

            PG_Tools.SaveAsPNG(preparedColorMap, Application.dataPath + "/Exported/Debug - Prepared Color Map.png");
        }

        // update the progress bar
        EditorUtility.DisplayProgressBar("Planet " + (pgPlanet.m_id + 1), "Preparing height map...", (float)currentStep++ / totalSteps);

        // prepare the height map
        var preparedHeightMap = PrepareHeightMap(pgPlanet);

        if (m_debugMode)
        {
            EditorUtility.DisplayProgressBar("Planet " + (pgPlanet.m_id + 1), "Saving prepared height map...", 0.0f);

            PG_Tools.SaveAsPNG(preparedHeightMap, Application.dataPath + "/Exported/Debug - Prepared Height Map.png");
        }

        float minimumDifference = 0.0f;
        float maximumDifference = 0.0f;

        byte[] differenceBuffer = null;

        if (pgPlanet.m_surfaceId != 1)
        {
            // scale to power of two
            EditorUtility.DisplayProgressBar("Planet " + (pgPlanet.m_id + 1), "Scaling to power of two...", (float)currentStep++ / totalSteps);

            var bicubicScale = new PG_BicubicScaleElevation();

            var elevation = bicubicScale.Process(preparedHeightMap, m_textureMapWidth, m_textureMapHeight);

            if (m_debugMode)
            {
                EditorUtility.DisplayProgressBar("Planet " + (pgPlanet.m_id + 1), "Saving bicubic scale map...", 0.0f);

                var contourMap = new PG_ContourMap();

                var tempBuffer = contourMap.Process(elevation, pgPlanet.m_waterElevation);

                PG_Tools.SaveAsEXR(tempBuffer, Application.dataPath + "/Exported/Debug - Bicubic Scale.exr");
            }

            // craters pass
            EditorUtility.DisplayProgressBar("Planet " + (pgPlanet.m_id + 1), "Creating craters...", (float)currentStep++ / totalSteps);

            if (pgPlanet.m_atmosphericDensityId == 0)
            {
                var craters = new PG_Craters();

                elevation = craters.Process(elevation, pgPlanet.m_id, m_craterGain, pgPlanet.m_waterElevation);

                if (m_debugMode)
                {
                    EditorUtility.DisplayProgressBar("Planet " + (pgPlanet.m_id + 1), "Saving craters map...", 0.0f);

                    var contourMap = new PG_ContourMap();

                    var tempBuffer = contourMap.Process(elevation, pgPlanet.m_waterElevation);

                    PG_Tools.SaveAsEXR(tempBuffer, Application.dataPath + "/Exported/Debug - Craters.exr");
                }
            }

            // at this point we want to save the current elevation buffer to use when calculating the difference map later
            var baseElevationBuffer = elevation;

            // mountains pass
            EditorUtility.DisplayProgressBar("Planet " + (pgPlanet.m_id + 1), "Creating mountains...", (float)currentStep++ / totalSteps);

            if (pgPlanet.m_atmosphericDensityId != 0)
            {
                var mountains = new PG_Mountains();

                elevation = mountains.Process(elevation, pgPlanet.m_id, m_octaves, m_mountainScale, m_mountainLacunarity, m_mountainPersistence, m_mountainGain, pgPlanet.m_waterElevation);

                if (m_debugMode)
                {
                    EditorUtility.DisplayProgressBar("Planet " + (pgPlanet.m_id + 1), "Saving mountains map...", 0.0f);

                    var contourMap = new PG_ContourMap();

                    var tempBuffer = contourMap.Process(elevation, pgPlanet.m_waterElevation);

                    PG_Tools.SaveAsEXR(tempBuffer, Application.dataPath + "/Exported/Debug - Mountains.exr");
                }
            }

            // hydraulic erosion pass
            var minimumElevation = pgPlanet.m_waterElevation - (pgPlanet.m_waterElevation / 16.0f);

            EditorUtility.DisplayProgressBar("Planet " + (pgPlanet.m_id + 1), "Hydraulic erosion pass...", (float)currentStep++ / totalSteps);

            if (m_doHydraulicErosionPass)
            {
                if (pgPlanet.m_atmosphericDensityId != 0)
                {
                    var hydraulicErosion = new PG_HydraulicErosion();

                    var gravityConstant = m_gravityConstant * pgPlanet.m_gravity;
                    var rainWaterAmount = m_rainWaterAmount * (float)pgPlanet.m_atmosphericDensityId / 3.0f;

                    elevation = hydraulicErosion.Process(elevation, minimumElevation, m_xyScaleToMeters, m_zScaleToMeters, rainWaterAmount, m_sedimentCapacity, gravityConstant, m_frictionConstant, m_evaporationConstant, m_depositionConstant, m_dissolvingConstant, m_stepDeltaTime, m_finalBlurRadius);

                    if (elevation == null)
                    {
                        return(false);
                    }

                    if (m_debugMode)
                    {
                        EditorUtility.DisplayProgressBar("Planet " + (pgPlanet.m_id + 1), "Saving hydraulic erosion map...", 0.0f);

                        var contourMap = new PG_ContourMap();

                        var tempBuffer = contourMap.Process(elevation, pgPlanet.m_waterElevation);

                        PG_Tools.SaveAsEXR(tempBuffer, Application.dataPath + "/Exported/Debug - Hydraulic Erosion.exr");
                    }
                }
            }

            if (m_debugMode)
            {
                // generate and save the albedo map
                EditorUtility.DisplayProgressBar("Planet " + (pgPlanet.m_id + 1), "Saving albedo map...", 0.0f);

                var albedoMap = new PG_AlbedoMap();

                var albedoBuffer = albedoMap.Process(elevation, preparedColorMap, pgPlanet.m_waterElevation, pgPlanet.m_waterColor, pgPlanet.m_groundColor);

                PG_Tools.SaveAsPNG(albedoBuffer, Application.dataPath + "/Exported/Debug - Albedo Map.png");

                // generate and save the normal map
                EditorUtility.DisplayProgressBar("Planet " + (pgPlanet.m_id + 1), "Saving normal map...", 0.0f);

                var normalMap = new PG_NormalMap();

                var normalsBuffer = normalMap.Process(elevation, 256.0f, pgPlanet.m_waterElevation, 1);

                PG_Tools.SaveAsPNG(normalsBuffer, Application.dataPath + "/Exported/Debug - Normal Map.png");

                // generate and save the specular map
                EditorUtility.DisplayProgressBar("Planet " + (pgPlanet.m_id + 1), "Saving specular map...", 0.0f);

                var waterSpecularColor = new Color(1.0f, 1.0f, 1.0f);

                var specularMap = new PG_SpecularMap();

                var specularBuffer = specularMap.Process(elevation, albedoBuffer, pgPlanet.m_waterElevation, waterSpecularColor, 0.75f, 1);

                PG_Tools.SaveAsPNG(specularBuffer, Application.dataPath + "/Exported/Debug - Specular Map.png", true);

                // generate and save the water mask map
                EditorUtility.DisplayProgressBar("Planet " + (pgPlanet.m_id + 1), "Saving water mask map...", 0.0f);

                var waterMaskMap = new PG_WaterMaskMap();

                var waterMaskBuffer = waterMaskMap.Process(elevation, pgPlanet.m_waterElevation, 1);

                PG_Tools.SaveAsPNG(waterMaskBuffer, Application.dataPath + "/Exported/Debug - Water Mask Map.png", true);

                // generate and save the elevation map (for the terrain grid)
                EditorUtility.DisplayProgressBar("Planet " + (pgPlanet.m_id + 1), "Saving elevation map...", 0.0f);

                PG_Tools.SaveAsEXR(elevation, Application.dataPath + "/Exported/Debug - Elevation Map.exr");
            }

            // figure out what our minimum and maximum deltas are
            EditorUtility.DisplayProgressBar("Planet " + (pgPlanet.m_id + 1), "Computing deltas...", (float)currentStep++ / totalSteps);

            minimumDifference = 0;
            maximumDifference = 0;

            for (var y = 0; y < m_textureMapHeight; y++)
            {
                for (var x = 0; x < m_textureMapWidth; x++)
                {
                    var difference = elevation[y, x] - baseElevationBuffer[y, x];

                    if (difference < minimumDifference)
                    {
                        minimumDifference = difference;
                    }

                    if (difference > maximumDifference)
                    {
                        maximumDifference = difference;
                    }
                }
            }

            // rescale float deltas to 0 to 255
            var elevationScale = 255.0f / (maximumDifference - minimumDifference);

            differenceBuffer = new byte[m_textureMapWidth * m_textureMapHeight];

            for (var y = 0; y < m_textureMapHeight; y++)
            {
                for (var x = 0; x < m_textureMapWidth; x++)
                {
                    var difference = (byte)Mathf.RoundToInt((elevation[y, x] - baseElevationBuffer[y, x] - minimumDifference) * elevationScale);

                    differenceBuffer[y * m_textureMapWidth + x] = difference;

                    elevation[y, x] = difference / 255.0f;
                }
            }

            if (m_debugMode)
            {
                EditorUtility.DisplayProgressBar("Planet " + (pgPlanet.m_id + 1), "Saving difference buffer...", 0.0f);

                PG_Tools.SaveAsPNG(elevation, Application.dataPath + "/Exported/" + "Debug - Difference Buffer.png");

                AssetDatabase.Refresh();
            }
        }

        // save the map!
        EditorUtility.DisplayProgressBar("Planet " + (pgPlanet.m_id + 1), "Compressing and saving the planet data...", (float)currentStep++ / totalSteps);

        SavePlanetMap(filename, pgPlanet, preparedHeightMap, preparedColorMap, minimumDifference, maximumDifference, differenceBuffer);

        return(true);
    }
예제 #4
0
    void SavePlanetMap(string filename, PG_Planet pgPlanet, float[,] preparedHeightMap, Color[,] preparedColorMap, float minimumDifference, float maximumDifference, byte[] differenceBuffer)
    {
        // save map to compressed bytes file with a header
        using (var fileStream = new FileStream(filename, FileMode.Create))
        {
            using (var gZipStream = new GZipStream(fileStream, CompressionMode.Compress, false))
            {
                var binaryWriter = new BinaryWriter(gZipStream);

                // version number
                binaryWriter.Write(c_versionNumber);

                // misc data
                binaryWriter.Write(pgPlanet.m_minimumElevation);
                binaryWriter.Write(pgPlanet.m_waterElevation);
                binaryWriter.Write(pgPlanet.m_snowElevation);

                binaryWriter.Write(pgPlanet.m_waterColor.r);
                binaryWriter.Write(pgPlanet.m_waterColor.g);
                binaryWriter.Write(pgPlanet.m_waterColor.b);

                binaryWriter.Write(pgPlanet.m_groundColor.r);
                binaryWriter.Write(pgPlanet.m_groundColor.g);
                binaryWriter.Write(pgPlanet.m_groundColor.b);

                binaryWriter.Write(pgPlanet.m_snowColor.r);
                binaryWriter.Write(pgPlanet.m_snowColor.g);
                binaryWriter.Write(pgPlanet.m_snowColor.b);

                // prepared map width and height
                var preparedMapWidth  = preparedHeightMap.GetLength(1);
                var preparedMapHeight = preparedHeightMap.GetLength(0);

                binaryWriter.Write(preparedMapWidth);
                binaryWriter.Write(preparedMapHeight);

                // prepared height map
                for (var y = 0; y < preparedMapHeight; y++)
                {
                    for (var x = 0; x < preparedMapWidth; x++)
                    {
                        binaryWriter.Write(preparedHeightMap[y, x]);
                    }
                }

                // prepared color map
                for (var y = 0; y < preparedMapHeight; y++)
                {
                    for (var x = 0; x < preparedMapWidth; x++)
                    {
                        binaryWriter.Write(preparedColorMap[y, x].r);
                        binaryWriter.Write(preparedColorMap[y, x].g);
                        binaryWriter.Write(preparedColorMap[y, x].b);
                    }
                }

                // difference buffer
                if (differenceBuffer != null)
                {
                    // minimum and maximum difference
                    binaryWriter.Write(minimumDifference);
                    binaryWriter.Write(maximumDifference);

                    // difference buffer
                    binaryWriter.Write(differenceBuffer);
                }
            }
        }
    }
예제 #5
0
    // generate maps and show them on the planet game object
    void MakeSomeMagic()
    {
        // show progress bar
        EditorUtility.DisplayProgressBar("Planet Generator", "Initializing...", 0.0f);

        // load the game data
        var textAsset = Resources.Load(m_gameDataFileName) as TextAsset;

        // convert it from the json string to our game data class
        var gameData = JsonUtility.FromJson <GameData>(textAsset.text);

        // initialize the game data
        gameData.Initialize();

        // initialize static components of planet generator
        PG_AlbedoMap.Initialize();
        PG_Craters.Initialize();

        // calculate the texture map scale (and it must be an even number)
        m_textureMapScaleX = Mathf.FloorToInt((float)m_textureMapWidth / (float)PG_Planet.c_width);
        m_textureMapScaleY = Mathf.FloorToInt((float)m_textureMapHeight / (float)(PG_Planet.c_height + m_numPolePaddingRows * 2));

        if (m_textureMapScaleX < 2)
        {
            m_textureMapScaleX = 2;
        }
        else if ((m_textureMapScaleX & 1) == 1)
        {
            m_textureMapScaleX--;
        }

        if (m_textureMapScaleY < 2)
        {
            m_textureMapScaleY = 2;
        }
        else if ((m_textureMapScaleY & 1) == 1)
        {
            m_textureMapScaleY--;
        }

        // do some magic
        PG_Planet pgPlanet;

        for (var id = 0; id < c_numPlanets; id++)
        {
            if (m_debugMode)
            {
                id = m_debugPlanetID;
            }

            pgPlanet = new PG_Planet(gameData, m_planetImagesPath, id);

            if (pgPlanet.m_mapIsValid)
            {
                var filename = Application.dataPath + "/" + m_resourcesPath + "/Planets/" + pgPlanet.m_id + ".bytes";

                if (m_debugMode || !File.Exists(filename))
                {
                    if (!GeneratePlanetTextureMaps(pgPlanet, filename))
                    {
                        break;
                    }
                }
            }

            if (m_debugMode)
            {
                break;
            }
        }

        // show progress bar
        EditorUtility.ClearProgressBar();
    }