欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  移动技术

如何使得Unity Terrain(地形)的高度匹配道路模型的高度

程序员文章站 2022-07-08 10:12:23
文章目录0.参考1.Unity Terrain2.如何使用代码 get/set Terrain某一点的高度3.如何获取道路模型的高度,以及需要修改的heightmap区域4.如何Smooth地形,使得高度变化不那么突兀?0.参考Unity官方文档:关于Terrain的介绍与API参考Unity Assets Store资源:Road Maker Optimized:这个项目提供了一个API文档,可以查看每个函数的含义,比起自己去看源码寻找,方便很多。此外,由于这个项目不提供源码,所以需要使用ILSp...

0.参考

1.Unity Terrain

Unity Terrain是什么呢?它在窗口中看起来像一个Mesh,有很多的网格。

如何使得Unity Terrain(地形)的高度匹配道路模型的高度
但是它并没有Mesh Filter和Mesh Renderer组件,取而代之的是Terrain组件。

如何使得Unity Terrain(地形)的高度匹配道路模型的高度
Mesh好理解,但是这个Texture是什么呢?

Terrain tools that affect height, such as Raise or Lower Terrain and Set Height, use a grayscale texture called a heightmap. Unity represents the height of each point on the Terrain as a value in a rectangular array. It represents this array using a grayscale heightmap. Heightmaps are built into the Terrain, and the values stored in a heightmap define the height of each point or vertex on the Terrain.

根据官方文档的以上描述,我们可以知道,Unity内部是用一个二维数组(rectangular array)来存储Terrain每个点的高度的。而每个点的高度又是从一张灰度图(heightmap)里采样的。

这张灰度图可以在Terrain组件的Texture Resolutions选项卡里Import或者Export,选择导出后我得到了个名为“terrain.raw”的文件。使用PhotoShop打开,可以看到该图片的属性如下:宽度和高度都为513像素,和Terrain组件中的“Heightmap Resolution”的值一致。通道数量为2,深度为8位。

如何使得Unity Terrain(地形)的高度匹配道路模型的高度
这张heightmap长这样:

如何使得Unity Terrain(地形)的高度匹配道路模型的高度
对比Untiy窗口的Terrain渲染图,我们可以观察到黑色代表高度为0,白色代表高度为最大值(由Mesh Resolution中的Terrain Height定义),灰色则代表(0~maxHeight)中的一个值。

2.如何使用代码 get/set Terrain某一点的高度

(1)heightmap的坐标系

以左下角为原点,向右向上为正。如下图,白色正方体所在的位置为世界坐标系的原点。选中的Terrain在世界坐标系中,坐标和原点重合,position=(0,0,0)。可以看到,虽然移动工具在Terrain的中心,但是Terrain的左下角和position重合。

如何使得Unity Terrain(地形)的高度匹配道路模型的高度
(2)将Terrain左下角的五分之一面积的高度设置为0

  • terrain.terrainData.heightmapResolution
  • terrain.terrainData.GetHeights()
  • terrain.terrainData.SetHeights()
public class TestTerrain : MonoBehaviour
{
    Terrain terrain;
    // Start is called before the first frame update
    void Start()
    {
        terrain = GetComponent<Terrain>();
        int resolution = terrain.terrainData.heightmapResolution;
        //GetHeights函数:获取从(xbase,ybase)开始的resolution的点的height。
        //即hts存储了heightmap上所有点的高度值。
        float[,] hts = terrain.terrainData.GetHeights(0, 0, resolution, resolution);
        for(int i = 0; i < resolution / 5; i++)
        {
            for(int j = 0; j < resolution / 5; j++)
            {
                hts[i,j] = 0;
            }
        }
        terrain.terrainData.SetHeights(0, 0, hts);
    }
}

效果如图:

修改前 修改后
如何使得Unity Terrain(地形)的高度匹配道路模型的高度 如何使得Unity Terrain(地形)的高度匹配道路模型的高度

需要注意的是,即使是在运行时修改了Terrain的height,效果也是永久的,因为这里修改的实际上heightmap,图像已经改变。

3.如何获取道路模型的高度,以及需要修改的heightmap区域

答案就是使用Raycast!我们可以从heightmap上的每一个点发射一条射线,如果这条射线和road模型相交了,就可以得到交点处的坐标值。我们就可以将heightmap上的该点的高度设置为交点的y值了。

public class TestTerrain : MonoBehaviour
{
    Terrain terrain;
    // Start is called before the first frame update
    void Start()
    {
        //【Terrain Data】
        terrain = GetComponent<Terrain>();
        int resolution = terrain.terrainData.heightmapResolution;
        Debug.Log("resolution:" + resolution);
        float sizeX = terrain.terrainData.size.x;
        float sizeY = terrain.terrainData.size.y;
        float sizeZ = terrain.terrainData.size.z;
        Debug.Log("size x:" + sizeX+" size y:"+sizeY + " size z:" + sizeZ);
        float posX = terrain.transform.position.x;
        float posY = terrain.transform.position.y;
        float posZ = terrain.transform.position.z;

        //【Process】
        //获取从(xbase,ybase)开始的resolution的点的height。即hts存储了heightmap上所有点的高度值。
        float[,] hts = terrain.terrainData.GetHeights(0, 0, resolution, resolution);
        RaycastHit hit;
        for (int y = 0; y < resolution; y++)
        {
            for (int x = 0; x < resolution; x++) { 
                Vector3 origin = new Vector3(
                    (float)x / (float)(resolution - 1) * sizeX + posX,
                    posY+terrain.terrainData.GetHeight(x,y),
                    (float)y/(float)(resolution-1)*sizeZ+posZ
                );
                if(Physics.Raycast(new Vector3(origin.x,origin.y-sizeY,origin.z), Vector3.up, out hit, sizeY * 2)){
                    hts[y, x] = (hit.point.y - posY) / sizeY;
                }
            }
        }
        terrain.terrainData.SetHeights(0, 0, hts);
    }

效果如图:

如何使得Unity Terrain(地形)的高度匹配道路模型的高度

4.如何Smooth地形,使得高度变化不那么突兀?

研究ing……

如何使得Unity Terrain(地形)的高度匹配道路模型的高度

本文地址:https://blog.csdn.net/qq_36622009/article/details/107883221

相关标签: 自动驾驶仿真