0
\$\begingroup\$

I have create a Terrain using perlin-noise map, I am successful so far. But, now when i am trying to add texture, I can't figure out how. I am using using a colorMap to test, I want grass to have grass like texture instead of green color. Also, I want to spawn GameObject in certain area depending on heightMap (like Minecraft spawn bear in snow mountain). can someone help

HeightMap Generation Script

using UnityEngine;  using System.Collections;

public static class Noise {

    public static float[,] GenerateNoiseMap(int mapWidth, int mapHeight, int seed, float scale, int octaves, float persistance, float lacunarity, Vector2 offset) {
        float[,] noiseMap = new float[mapWidth,mapHeight];

        System.Random prng = new System.Random (seed);
        Vector2[] octaveOffsets = new Vector2[octaves];
        for (int i = 0; i < octaves; i++) {
            float offsetX = prng.Next (-100000, 100000) + offset.x;
            float offsetY = prng.Next (-100000, 100000) + offset.y;
            octaveOffsets [i] = new Vector2 (offsetX, offsetY);
        }

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

        float maxNoiseHeight = float.MinValue;
        float minNoiseHeight = float.MaxValue;

        float halfWidth = mapWidth / 2f;
        float halfHeight = mapHeight / 2f;


        for (int y = 0; y < mapHeight; y++) {
            for (int x = 0; x < mapWidth; x++) {

                float amplitude = 1;
                float frequency = 1;
                float noiseHeight = 0;

                for (int i = 0; i < octaves; i++) {
                    float sampleX = (x-halfWidth) / scale * frequency + octaveOffsets[i].x;
                    float sampleY = (y-halfHeight) / scale * frequency + octaveOffsets[i].y;

                    float perlinValue = Mathf.PerlinNoise (sampleX, sampleY) * 2 - 1;
                    noiseHeight += perlinValue * amplitude;

                    amplitude *= persistance;
                    frequency *= lacunarity;
                }

                if (noiseHeight > maxNoiseHeight) {
                    maxNoiseHeight = noiseHeight;
                } else if (noiseHeight < minNoiseHeight) {
                    minNoiseHeight = noiseHeight;
                }
                noiseMap [x, y] = noiseHeight;
            }
        }

        for (int y = 0; y < mapHeight; y++) {
            for (int x = 0; x < mapWidth; x++) {
                noiseMap [x, y] = Mathf.InverseLerp (minNoiseHeight, maxNoiseHeight, noiseMap [x, y]);
            }
        }

        return noiseMap;
    }

}

MapGenerator Script

using UnityEngine;
using System.Collections;

public class TerrainGenerator : MonoBehaviour {

    public enum DrawMode    {
        NoiseMap,
        ColorMap,
        Mesh
    };

    public DrawMode drawMode;
    public int mapWidth;
    public int mapHeight;
    public float noiseScale;

    public int octaves;
    [Range(0,1)]
    public float persistance;
    public float lacunarity;

    public int seed;
    public int meshHeightMultiplyer;
    public AnimationCurve meshHeightCurve;

    public Vector2 offset;

    public bool autoUpdate;

    public TerrainType[] regions;   float[,] noiseMap;

    public void GenerateMap() {
        noiseMap = Noise.GenerateNoiseMap (mapWidth, mapHeight, seed, noiseScale, octaves, persistance, lacunarity, offset);

        Color[] colourMap = new Color[mapWidth * mapHeight];
        for (int y = 0; y < mapHeight; y++) {
            for (int x = 0; x < mapWidth; x++) {
                float currentHeight = noiseMap [x, y];
                for (int i = 0; i < regions.Length; i++) {
                    if (currentHeight <= regions [i].height) {
                        colourMap [y * mapWidth + x] = regions[i].colour;
                        break;
                    }
                }
            }
        }

        MapDisplay display = FindObjectOfType<MapDisplay> ();
        if (drawMode == DrawMode.NoiseMap) {
            display.DrawTexture(TextureGenerator.TextureFromHeightMap (noiseMap));
        } else if (drawMode == DrawMode.ColorMap) {
            display.DrawTexture (TextureGenerator.TextureFromColourMap (colourMap, mapWidth, mapHeight));
        } else if (drawMode == DrawMode.Mesh) {
            display.DrawMesh (MeshGenerator.GenerateMesh (noiseMap, meshHeightMultiplyer, meshHeightCurve), TextureGenerator.TextureFromColourMap (colourMap, mapWidth, mapHeight));
        }
    }

    public void CreateMob()
    {
      MobSpawner ms = new MobSpawner (noiseMap);
      ms.GenerateMod ();
    }

    void OnValidate() {
        if (mapWidth < 1) {
            mapWidth = 1;
        }
        if (mapHeight < 1) {
            mapHeight = 1;
        }
        if (lacunarity < 1) {
            lacunarity = 1;
        }
        if (octaves < 0) {
            octaves = 0;
        }
        if (meshHeightMultiplyer < 1) {
            meshHeightMultiplyer = 1;
        }
    }

    [System.Serializable]
    public struct TerrainType {
        public string name;
        public float height;
        public Color colour;
    }
 }
\$\endgroup\$

1 Answer 1

0
\$\begingroup\$

You could Use a shader that takes multiple textures and then depending on a weightmap, or the height of some vertices interpolate between those textures.

I did that once and it works pretty well, only issue is that you cannot use an array of textures (yet).

Internally Unity seems to be using something at the renderer level, that is blind to the material/shader and to the number of textures used.

At some point they were using Vertex mapping, but it seems it's not the case anymore.

All those are valid ways to deal with this issue.

\$\endgroup\$

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .