예제 #1
0
    // ...

    /*public struct GenerateNoise : IJob {
     *      public int seed;
     *      public Noise.NoiseSource noiseSource;
     *      public GPUNoiseGenerator.NoiseData noiseData;
     *      public NativeArray<float> heightMapX;
     *      public NativeArray<float> heightMapY;
     *
     *      public void Execute() {
     *              float[,] heightMap;
     *
     *              switch (noiseSource) {
     *                      case Noise.NoiseSource.GPU_2DFloatArray:
     *                              heightMap = GPUNoiseGenerator.GenerateNoiseArray(seed, noiseData);
     *                              break;
     *                      case Noise.NoiseSource.GPU_RenderTextureTo2DFloatArray:
     *                              heightMap = GPUNoiseGenerator.GenerateNoiseArrayFromRenderTexture(seed, noiseData);
     *                              break;
     *                      default:
     *                              throw new System.Exception("Not Implemented");
     *              }
     *
     *              float[] x = new float[heightMap.Length];
     *              float[] y = new float[heightMap.Length];
     *              for (int i = 0; i < heightMap.Length; ++i) {
     *                      x[i] = heightMap[i, 0];
     *                      y[i] = heightMap[i, 1];
     *              }
     *              heightMapX.CopyFrom(x);
     *              heightMapY.CopyFrom(y);
     *      }
     * }*/

    // Generate Planet LOD
    public Tuple <GameObject, List <RenderTexture> > GeneratePlanetChunk(int gridSize, Vector3 position, bool hasHeight, bool hasCollider, string side = "")
    {
        string  name      = "";
        Vector2 rotation  = Vector3.zero;
        Mesh    chunkMesh = null;

        Material[] materials;
        float[][,] heightMaps;
        List <RenderTexture> renderTextureList;

        // Jos full niin pitää kaikki sivut generoida
        if (side[0] == 'F')
        {
            name = "F";
            // TODO: LOD Full planet generation jos ees haluun sitä
            return(Tuple.Create(new GameObject(side), new List <RenderTexture>()));
        }
        // Generoidaan yksi sivu tai quarter
        else
        {
            chunkMesh = GenerateSphericalMesh(Mathf.RoundToInt(gridSize), side);             // generoi spherical meshen

            GPUNoiseGenerator.Side planetSide;

            switch (side[0])
            {
            case '0':
                planetSide = GPUNoiseGenerator.Side.Bottom;
                rotation   = new Vector2(270, 0);
                break;

            case '1':
                planetSide = GPUNoiseGenerator.Side.Left;
                rotation   = new Vector2(0, 90);
                break;

            case '2':
                planetSide = GPUNoiseGenerator.Side.Front;
                rotation   = new Vector2(0, 0);
                break;

            case '3':
                planetSide = GPUNoiseGenerator.Side.Right;
                rotation   = new Vector2(0, -90);
                break;

            case '4':
                planetSide = GPUNoiseGenerator.Side.Top;
                rotation   = new Vector2(90, 0);
                break;

            default:                     //case '5':
                planetSide = GPUNoiseGenerator.Side.Back;
                rotation   = new Vector2(180, 0);
                break;
            }


            // TODO: en tiiä pitäiskö vaan parametrina laittaa planet side ja side noise generaattoriin ettei tarttee jokaiselle laittaa niitä erikseen
            ocean.side          = planetSide;
            plainHills.side     = planetSide;
            largeMountains.side = planetSide;
            mediumDetail.side   = planetSide;

            side                   = side.Substring(1);
            ocean.quarter          = side;
            plainHills.quarter     = side;
            largeMountains.quarter = side;
            mediumDetail.quarter   = side;

            name = planetSide.ToString();
            if (side != "")
            {
                name += "_" + side;
            }

            float[,] oceanHeightMap;            // = new float[(int)ocean.resolution, (int)ocean.resolution];
            float[,] plainHillsHeightMap;       // = new float[(int)plainHills.resolution, (int)plainHills.resolution];
            float[,] largeMountainsHeightMap;   // = new float[(int)largeMountains.resolution, (int)largeMountains.resolution];
            float[,] mediumDetailHeightMap;     // = new float[(int)mediumDetail.resolution, (int)mediumDetail.resolution];

            switch (noiseSource)
            {
            case Noise.NoiseSource.GPU_2DFloatArray:
                oceanHeightMap          = GPUNoiseGenerator.GenerateNoiseArray(seed, ocean, gridSize);
                plainHillsHeightMap     = GPUNoiseGenerator.GenerateNoiseArray(seed, plainHills, radius, gridSize);
                largeMountainsHeightMap = GPUNoiseGenerator.GenerateNoiseArray(seed, largeMountains, radius, gridSize);
                mediumDetailHeightMap   = GPUNoiseGenerator.GenerateNoiseArray(seed, mediumDetail, gridSize);
                break;

            case Noise.NoiseSource.GPU_RenderTextureTo2DFloatArray:
                oceanHeightMap          = GPUNoiseGenerator.GenerateNoiseArrayFromRenderTexture(seed, ocean);
                plainHillsHeightMap     = GPUNoiseGenerator.GenerateNoiseArrayFromRenderTexture(seed, plainHills);
                largeMountainsHeightMap = GPUNoiseGenerator.GenerateNoiseArrayFromRenderTexture(seed, largeMountains);
                mediumDetailHeightMap   = GPUNoiseGenerator.GenerateNoiseArrayFromRenderTexture(seed, mediumDetail);
                break;

            default:
                throw new System.Exception("Not Implemented");
            }

            heightMaps = new float[][, ] {
                oceanHeightMap, plainHillsHeightMap, largeMountainsHeightMap, mediumDetailHeightMap
            };
            //heightMaps = new float[][,] { oceanHeightMap, plainHillsHeightMap, largeMountainsHeightMap };

            materials = new Material[1];

            // Height Map material

            /*materials[0] = new Material(Shader.Find("Unlit/Texture"));
             * Texture2D noiseTexture = TextureGenerator.TextureFromHeightMap(mediumDetailHeightMap);
             * Vector2 textureScale = new Vector2(1f / gridSize, 1f / gridSize);
             * materials[0].mainTextureScale = textureScale;
             * materials[0].mainTexture = noiseTexture;*/


            // Textured
            //materials[0] = new Material(Shader.Find("Shader Forge/Terrain"));
            materials[0] = new Material(Shader.Find("Shader Graphs/TestPlanetTextureShader"));
            RenderTexture oceanTex          = GPUNoiseGenerator.GenerateNoise(seed, ocean, radius);
            RenderTexture plainHillsTex     = GPUNoiseGenerator.GenerateNoise(seed, plainHills, radius);
            RenderTexture largeMountainsTex = GPUNoiseGenerator.GenerateNoise(seed, largeMountains, radius);
            RenderTexture mediumDetailTex   = GPUNoiseGenerator.GenerateNoise(seed, mediumDetail, radius);

            materials[0].SetTexture(OCEAN_NOISE_TEXTURE_NAME, oceanTex);
            materials[0].SetTexture(PLAIN_HILLS_NOISE_TEXTURE_NAME, plainHillsTex);
            materials[0].SetTexture(LARGE_MOUNTAINS_NOISE_TEXTURE_NAME, largeMountainsTex);
            materials[0].SetTexture(MEDIUM_DETAIL_NOISE_TEXTURE_NAME, mediumDetailTex);

            Vector2 tiling = new Vector2(1f / gridSize, 1f / gridSize);
            materials[0].SetVector("_Tiling", tiling);

            materials[0].SetFloat("_Brightness1", 6.36f);
            materials[0].SetFloat("_Brightness2", 1.66f);
            materials[0].SetFloat("_Brightness3", 0.4f);
            materials[0].SetFloat("_Brightness4", 22.73f);

            materials[0].SetTexture("_MainTex", oceanTex);

            renderTextureList = new List <RenderTexture> {
                oceanTex,
                plainHillsTex,
                largeMountainsTex,
                mediumDetailTex
            };

            //
            //mat.SetTexture("_MedTex", );
            //mat.SetTexture("_HighTex", );
            //mat.SetTexture("_DisplacementTexture", );
            //
        }

        return(Tuple.Create(
                   GeneratePlanetChunkObj(name, side, position, planetSize, rotation, chunkMesh, materials, ref heightMaps, gridSize, hasHeight, hasCollider),
                   renderTextureList
                   ));
    }
예제 #2
0
    // Generate noise map

    //mapSizeSqrt, mapSizeSqrt, seed, side, offset, octaves, persistence, lacunarity, noiseSource

    public static float[,] GenerateNoiseMap(int seed, Vector3 offset, GPUNoiseGenerator.NoiseData noise, float scale, NoiseSource source, int?meshGridSize = null, float zoom = 1, int performanceTestLoops = 1, float radius = 100)
    {
        int mapSizeSqrt = (int)noise.resolution;

        float[,] noiseMap = new float[mapSizeSqrt, mapSizeSqrt];

        System.Diagnostics.Stopwatch st = new System.Diagnostics.Stopwatch();
        st.Start();
        for (int performanceLoopIndex = 0; performanceLoopIndex < performanceTestLoops; ++performanceLoopIndex)
        {
            switch (source)
            {
            case NoiseSource.Unity:
                #region [ - Unity Noise - ]

                Vector2 chunkOffset = offset;

                //GenerateFalloffMap(ref falloffMap, mapChunkSize);

                /* Generate Height Map
                 *      (mapSide tarkottaa yhen spherical cuben reunan HeightMapin kokoa)
                 *         [5]
                 *         [4]
                 *      [1][2][3]
                 *         [0]
                 */

                // Laskee sphericalCuben valitun lähtöpisteen
                for (int i = 0, len = int.Parse(((int)noise.side).ToString()); i <= len; ++i)
                {
                    switch (i)
                    {
                    case 0:
                        chunkOffset.x += mapSizeSqrt;
                        break;

                    case 1:
                        chunkOffset.x -= mapSizeSqrt;
                        chunkOffset.y += mapSizeSqrt;
                        break;

                    case 2:
                        chunkOffset.x += mapSizeSqrt;
                        break;

                    case 3:
                        chunkOffset.x += mapSizeSqrt;
                        break;

                    case 4:
                        chunkOffset.x -= mapSizeSqrt;
                        chunkOffset.y += mapSizeSqrt;
                        break;

                    case 5:
                        chunkOffset.y += mapSizeSqrt;
                        break;
                    }
                }
                // Laskee quartereitten (..quartereitten (..quartereitten (..jne))) lähtöpisteen
                int quarterSize = mapSizeSqrt;

                for (int i = 0, len = noise.quarter.Length; i < len; ++i)
                {
                    //quarterSize /= 2; // quarterin leveys\korkeus
                    scale *= 2;

                    switch (noise.quarter[i])
                    {
                    case '0':                                     // vasenala
                        // -> piste ei liiku minnekkään
                        Debug.Log("scale: " + scale + ", quarter size: " + quarterSize + ", side:" + noise.quarter[i] + ", offset: " + chunkOffset.x + " | " + chunkOffset.y);
                        break;

                    case '1':                                     // oikeeala
                        chunkOffset.x += quarterSize / scale;
                        Debug.Log("scale: " + scale + ", quarter size: " + quarterSize + ", side:" + noise.quarter[i] + ", offset: " + chunkOffset.x + " | " + chunkOffset.y);
                        break;

                    case '2':                                     // vasenylä
                        chunkOffset.y += quarterSize / scale;
                        Debug.Log("scale: " + scale + ", quarter size: " + quarterSize + ", side:" + noise.quarter[i] + ", offset: " + chunkOffset.x + " | " + chunkOffset.y);
                        break;

                    case '3':                                     // oikeeylä
                        chunkOffset.x += quarterSize / scale;
                        chunkOffset.y += quarterSize / scale;
                        Debug.Log("scale: " + scale + ", quarter size: " + quarterSize + ", side:" + noise.quarter[i] + ", offset: " + chunkOffset.x + " | " + chunkOffset.y);
                        break;
                    }
                }



                Vector2[] octaveOffset = new Vector2[noise.octaves];

                maxPossibleHeight = 0;
                noise.amplitude   = 1;
                noise.frequency   = 1;

                NormalizeMode normalizeMode        = NormalizeMode.Global;
                System.Random prng                 = new System.Random(seed);
                Vector2       randomOffsetFromSeed = new Vector2(prng.Next(-100000, 100000) - chunkOffset.x, prng.Next(-100000, 100000) - chunkOffset.y);

                for (i = 0; i < noise.octaves; ++i)
                {
                    octaveOffset[i] = randomOffsetFromSeed;

                    maxPossibleHeight += noise.amplitude;
                    noise.amplitude   *= noise.persistence;
                }

                if (scale <= 0)
                {
                    scale = 0.0001f;
                }

                maxLocalNoiseHeight = float.MinValue;
                minLocalNoiseHeight = float.MaxValue;

                halfWidth  = mapSizeSqrt / 2f;
                halfHeight = mapSizeSqrt / 2f;

                for (y = 0; y < mapSizeSqrt; ++y)
                {
                    for (x = 0; x < mapSizeSqrt; ++x)
                    {
                        noise.amplitude = 1;
                        noise.frequency = 1;
                        noiseHeight     = 0;

                        for (i = 0; i < noise.octaves; ++i)                                   // Oktaavien teko kuluttaa sikana eli tarkkana
                        {
                            sampleX = (x - mapSizeSqrt) / scale * noise.frequency + octaveOffset[i].x * noise.frequency;
                            sampleY = (y - mapSizeSqrt) / scale * noise.frequency + octaveOffset[i].y * noise.frequency;

                            perlinValue  = Mathf.PerlinNoise(sampleX, sampleY) * 2 - 1;                                    // tää on raskas, * 2 - 1 tekee sen että se menee [-1, 1])
                            noiseHeight += perlinValue * noise.amplitude;
                            //Debug.Log("X: " + x + ", Y: " + y + " | " + perlinValue + " | " + amplitude);

                            noise.amplitude *= noise.persistence;
                            noise.frequency *= noise.lacunarity;
                        }

                        if (noiseHeight > maxLocalNoiseHeight)
                        {
                            maxLocalNoiseHeight = noiseHeight;
                        }
                        else if (noiseHeight < minLocalNoiseHeight)
                        {
                            minLocalNoiseHeight = noiseHeight;
                        }

                        noiseMap[x, y] = noiseHeight;

                        //Debug.Log("X: " + x + ", Y: " + y + " | " + noiseMap[x, y]);
                        //noiseMap[x, y] = Mathf.InverseLerp(minLocalNoiseHeight, maxLocalNoiseHeight, noiseMap[x, y]);
                    }
                }
                for (int y = 0; y < mapSizeSqrt; ++y)
                {
                    for (int x = 0; x < mapSizeSqrt; ++x)
                    {
                        if (normalizeMode == NormalizeMode.Local)
                        {
                            noiseMap[x, y] = Mathf.InverseLerp(minLocalNoiseHeight, maxLocalNoiseHeight, noiseMap[x, y]);
                        }
                        else
                        {
                            float normalizedHeight = (noiseMap[x, y] + 1) / (maxPossibleHeight / 0.9f);
                            noiseMap[x, y] = Mathf.Clamp(normalizedHeight, 0, int.MaxValue);
                        }
                    }
                }
                #endregion
                break;

            case NoiseSource.LibNoise:
                #region [ - LibNoise - ]

                Perlin perlinNoise = new Perlin {
                    Quality     = QualityMode.Medium,
                    OctaveCount = noise.octaves,
                    Lacunarity  = noise.lacunarity,
                    Seed        = seed,
                    Persistence = noise.persistence,
                    Frequency   = noise.frequency
                };

                LibNoise.Unity.ModuleBase moduleBase;
                moduleBase = perlinNoise;

                Noise2D noise2D = new LibNoise.Unity.Noise2D((int)noise.resolution, (int)noise.resolution, moduleBase);
                //noise.GeneratePlanar((double)offset.x, (double)(offset.x + mapWidth), (double)(offset.y + mapHeight), (double)offset.y);
                noise2D.GeneratePlanar((int)noise.resolution, 0, (int)noise.resolution, 0);

                noiseMap = noise2D.m_data;
                #endregion
                break;


            case NoiseSource.GPU_2DFloatArray:
                #region [ - GPU 2D Float Array - ]
                noiseMap = GPUNoiseGenerator.GenerateNoiseArray(seed, noise, radius, meshGridSize, offset, zoom);
                #endregion
                break;

            case NoiseSource.GPU_RenderTextureTo2DFloatArray:
                #region [ - GPU Render Texture to 2D Float Array - ]
                noiseMap = GPUNoiseGenerator.GenerateNoiseArrayFromRenderTexture(seed, noise);
                #endregion
                break;

            default:
                return(null);
            }
        }
        st.Stop();
        if (performanceTestLoops > 1)
        {
            Debug.Log(string.Format("Generated noise with {0} {1} times and it took {2} ms to complete.", source.ToString(), performanceTestLoops, st.ElapsedMilliseconds));
        }

        return(noiseMap);
    }