4

Unity 有一个 Terrain.sampleHeight(point)很棒的功能,它可以立即为您提供脚下地形的高度,而无需投射。

然而,任何重要的项目都有不止一个地形。(事实上​​,任何物理上大的场景都不可避免地具有地形拼接,一种或另一种方式。)

Unity 有一个功能Terrain.activeTerrain——我不是编造的——给你:“第一个加载”

显然这是完全没用的。

事实上,有没有一种快速的方法可以让地形“在你之下”?然后可以使用快速功能.sampleHeight吗?

{请注意,当然,您可以... 施法以找到您下方的地形!但是你会有你的高度,所以没有必要担心.sampleHeight!}

简而言之,是否有一个匹配的函数sampleHeight可以让该函数知道对于给定的 xyz 使用哪个地形?

(或者实际上,sampleHeight只是一个相当无用的演示功能,只能在具有一个地形的演示中使用?)

4

5 回答 5

3

Terrain.GetPosition() = Terrain.transform.position = 在世界
工作方法中的位置:

Terrain[] _terrains = Terrain.activeTerrains;

int GetClosestCurrentTerrain(Vector3 playerPos)
{
    //Get the closest one to the player
    var center = new Vector3(_terrains[0].transform.position.x + _terrains[0].terrainData.size.x / 2, playerPos.y, _terrains[0].transform.position.z + _terrains[0].terrainData.size.z / 2);
    float lowDist = (center - playerPos).sqrMagnitude;
    var terrainIndex = 0;

    for (int i = 0; i < _terrains.Length; i++)
    {
        center = new Vector3(_terrains[i].transform.position.x + _terrains[i].terrainData.size.x / 2, playerPos.y, _terrains[i].transform.position.z + _terrains[i].terrainData.size.z / 2);

        //Find the distance and check if it is lower than the last one then store it
        var dist = (center - playerPos).sqrMagnitude;
        if (dist < lowDist)
        {
            lowDist = dist;
            terrainIndex = i;
        }
    }
    return terrainIndex;
}

于 2019-09-07T22:00:54.717 回答
3

实际上有没有一种快速的方法可以让地形“在你之下”——然后使用快速函数 .sampleHeight ?

是的,这是可以做到的。

(或者实际上,sampleHeight 只是一个相当无用的演示函数,只能在具有一个地形的演示中使用?)


Terrain.activeTerrain返回场景中的主要地形。还有Terrain.activeTerrains(注意末尾的“s”)返回场景中的活动地形

Terrain.activeTerrains获取返回Terrain数组的地形,然后使用Terrain.GetPosition函数获取其位置。通过查找距离玩家位置最近的地形来获取当前地形。Vector3.Distance您可以通过使用或Vector3.sqrMagnitude(更快)对地形位置进行排序来做到这一点。

Terrain GetClosestCurrentTerrain(Vector3 playerPos)
{
    //Get all terrain
    Terrain[] terrains = Terrain.activeTerrains;

    //Make sure that terrains length is ok
    if (terrains.Length == 0)
        return null;

    //If just one, return that one terrain
    if (terrains.Length == 1)
        return terrains[0];

    //Get the closest one to the player
    float lowDist = (terrains[0].GetPosition() - playerPos).sqrMagnitude;
    var terrainIndex = 0;

    for (int i = 1; i < terrains.Length; i++)
    {
        Terrain terrain = terrains[i];
        Vector3 terrainPos = terrain.GetPosition();

        //Find the distance and check if it is lower than the last one then store it
        var dist = (terrainPos - playerPos).sqrMagnitude;
        if (dist < lowDist)
        {
            lowDist = dist;
            terrainIndex = i;
        }
    }
    return terrains[terrainIndex];
}

用法:

假设玩家的位置是transform.position

//Get the current terrain
Terrain terrain = GetClosestCurrentTerrain(transform.position);
Vector3 point = new Vector3(0, 0, 0);
//Can now use SampleHeight
float yHeight = terrain.SampleHeight(point);

虽然可以使用 来做到这一点Terrain.SampleHeight,但这可以通过从玩家位置到地形的简单光线投射来简化。

Vector3 SampleHeightWithRaycast(Vector3 playerPos)
{
    float groundDistOffset = 2f;
    RaycastHit hit;
    //Raycast down to terrain
    if (Physics.Raycast(playerPos, -Vector3.up, out hit))
    {
        //Get y position
        playerPos.y = (hit.point + Vector3.up * groundDistOffset).y;
    }
    return playerPos;
}
于 2018-09-17T00:57:47.297 回答
1

事实证明答案是否定的,Unity 不提供这样的功能。

于 2018-12-15T19:36:59.620 回答
0

您可以使用此函数获取与当前位置最近的地形:

int GetClosestTerrain(Vector3 CheckPos)
{
    int terrainIndex = 0;
    float lowDist = float.MaxValue;

    for (int i = 0; i < _terrains.Length; i++)
    {
      var center = new Vector3(_terrains[i].transform.position.x + _terrains[i].terrainData.size.x / 2, CheckPos.y, _terrains[i].transform.position.z + _terrains[i].terrainData.size.z / 2);

      float dist = Vector3.Distance(center, CheckPos);

      if (dist < lowDist)
      {
        lowDist = dist;
        terrainIndex = i;
      }
    }
    return terrainIndex;
}

然后你可以使用这样的功能:

private Terrain[] _terrains;

void Start()
  {
    _terrains = Terrain.activeTerrains;

    Vector3 start_pos = Vector3.zero;

    start_pos.y = _terrains[GetClosestTerrain(start_pos)].SampleHeight(start_pos);

  }
于 2020-09-03T18:06:38.037 回答
0
public static Terrain GetClosestTerrain(Vector3 position)
{
    return Terrain.activeTerrains.OrderBy(x =>
    {
        var terrainPosition = x.transform.position;
        var terrainSize = x.terrainData.size * 0.5f;
        var terrainCenter = new Vector3(terrainPosition.x + terrainSize.x, position.y, terrainPosition.z + terrainSize.z);
        return Vector3.Distance(terrainCenter, position);
    }).First();
}
于 2021-06-08T07:46:45.903 回答