尝试通过代码根据图像纹理颜色设置高度图

时间:2018-03-07 18:18:29

标签: c# unity3d texture2d terrain heightmap

我正在尝试从图像/纹理颜色(从像素)设置地形的高度图,我做了这个简单的例子:

using UnityEngine;

public class TerrainExample : MonoBehaviour
{
    public Texture2D map, grassTexture;
    public float amp = 8;
    public Color waterColor = new Color(0.427f, 0.588f, 0.737f); //new Color32(127, 168, 200, 255); //0.427, 0.588, 0.737

    private Vector3 mapPlane = new Vector3(4200, 0, 3000);

    public void Start()
    {
        GameObject TerrainObj = new GameObject("TerrainObj");
        TerrainData _TerrainData = new TerrainData();
        Debug.Log(new Vector3(mapPlane.x, 600, mapPlane.z));
        _TerrainData.size = new Vector3(mapPlane.x / (1.6f * amp), 600, mapPlane.z / (1.6f * amp));
        _TerrainData.heightmapResolution = 4096;
        _TerrainData.baseMapResolution = 1024;
        _TerrainData.SetDetailResolution(1024, 16);

        //Set terrain data
        int _heightmapWidth = _TerrainData.heightmapWidth,
            _heightmapHeight = _TerrainData.heightmapHeight;
        float[,] heights = new float[_heightmapWidth, _heightmapHeight];
        float stepX = (float)map.width / _heightmapWidth, stepY = (float)map.height / _heightmapHeight;
        int w = 0;
        for (float i = 0; i < map.width; i += stepX)
            for (float k = 0; k < map.height; k += stepY)
            {
                int ii = (int)i, kk = (int)k, i2 = (int)(i / stepX), k2 = (int)(k / stepY);
                heights[i2, k2] = map.GetPixel(ii, kk) == waterColor ? .25f : .5f;
            }
        _TerrainData.SetHeights(0, 0, heights);

        //Set terrain grass texture
        SplatPrototype terrainTexture = new SplatPrototype();
        terrainTexture.texture = grassTexture;
        SplatPrototype[] splatPrototype = new SplatPrototype[1] { terrainTexture };
        _TerrainData.splatPrototypes = splatPrototype;
        TerrainCollider _TerrainCollider = TerrainObj.AddComponent<TerrainCollider>();
        Terrain _Terrain2 = TerrainObj.AddComponent<Terrain>();
        _TerrainCollider.terrainData = _TerrainData;
        _Terrain2.terrainData = _TerrainData;
        TerrainObj.transform.position = -mapPlane * 10 / 2 + Vector3.up * 100;
    }
}

我的地图纹理如下:

enter image description here

原始地图有7000x5000像素,我的高度图有4096个单位。所以,我必须通过计算每次迭代的步骤进行一些翻译(正如你在第25行中看到的那样)

我做的很简单,当有水时,我只放置0.25f的高度(600/4 = 150)和高度0.5f(600/2 = 300)。 (第31行)

但由于某种原因,我只能在地形上得到这条奇怪的线条:

enter image description here

我缺少什么?

这是Unitypackage

1 个答案:

答案 0 :(得分:2)

我并不打算分配纹理,我会让你这样做。

  • 制作新场景
  • 添加地形
  • 添加以下组件

<强>代码:

using UnityEngine;

namespace Assets
{
    public class Test : MonoBehaviour
    {
        public Texture2D Texture2D;

        private void OnEnable()
        {
            var terrain = GetComponent<Terrain>();
            var data = terrain.terrainData;
            var hw = data.heightmapWidth;
            var hh = data.heightmapHeight;
            var heights = data.GetHeights(0, 0, hw, hh);

            for (var y = 0; y < hh; y++)
            {
                for (var x = 0; x < hw; x++)
                {
                    // normalize coordinates
                    var x1 = 1.0f / hw * x * Texture2D.width;
                    var y1 = 1.0f / hh * y * Texture2D.height;

                    // get color height
                    var pixel = Texture2D.GetPixel((int) x1, (int) y1);
                    var f = pixel.grayscale; // defines height
                    var g = f * f * f; // some smoothing
                    var s = 0.025f; // some scaling

                    heights[x, y] = g * s;
                }
            }

            data.SetHeights(0, 0, heights);
        }
    }
}

enter image description here

enter image description here

最有趣的是平滑,它大大提高了输出。

此外,您可以从预定义的列表(例如水,草)中找到which color the pixel is close to并插入/平滑。

此外,您可能需要调整代码,因为我对TerrainData不是很熟悉。