You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Unity中实现炸弹爆炸地形凹陷变形的问题求助

解决Unity地形炸弹凹陷变形的代码问题

原代码存在的核心问题及修复方案

  • 编译错误:泛型缺失
    原代码Terrain terrain = GetComponent();缺少泛型参数,会直接编译失败,需修正为:

    Terrain terrain = GetComponent<Terrain>();
    
  • 坐标转换错误
    直接使用世界坐标计算高度图索引是错误的,需要先将世界坐标转为地形本地坐标,再进行比例计算:

    Vector3 localPos = terrain.transform.InverseTransformPoint(pos);
    
  • 高度图索引越界
    高度图的索引范围是0 ~ heightmapResolution-1,计算时需用heightmapResolution-1避免越界,同时通过Clamp限制合法范围:

    int posXInTerrain = Mathf.Clamp((int)((localPos.x / terrain.terrainData.size.x) * (heightmapRes - 1)), 0, heightmapRes - 1);
    int posZInTerrain = Mathf.Clamp((int)((localPos.z / terrain.terrainData.size.z) * (heightmapRes - 1)), 0, heightmapRes - 1);
    
  • 变形量单位不匹配
    地形高度图的数值是0~1的相对比例(对应地形总高度),而非世界单位。需将世界空间的deformationAmount转换为相对比例:

    float relativeDeformation = deformationAmount / terrain.terrainData.size.y;
    
  • 遍历范围过大导致性能浪费
    原代码遍历整个高度图,效率极低。应仅遍历变形半径覆盖的区域,减少不必要的计算:

    int startX = Mathf.Max(0, posXInTerrain - (int)deformationRadius);
    int endX = Mathf.Min(heightmapRes - 1, posXInTerrain + (int)deformationRadius);
    int startZ = Mathf.Max(0, posZInTerrain - (int)deformationRadius);
    int endZ = Mathf.Min(heightmapRes - 1, posZInTerrain + (int)deformationRadius);
    

修正后的完整代码

using UnityEngine;

public class TerrainDeformer : MonoBehaviour
{
    public void DeformTerrain(Vector3 pos, float deformationAmount, float deformationRadius)
    {
        Terrain terrain = GetComponent<Terrain>();
        if (terrain == null)
        {
            Debug.LogError("当前物体上未挂载Terrain组件!");
            return;
        }

        // 世界坐标转地形本地坐标
        Vector3 localPos = terrain.transform.InverseTransformPoint(pos);
        int heightmapRes = terrain.terrainData.heightmapResolution;

        // 计算爆炸点在高度图中的合法索引
        int posXInTerrain = Mathf.Clamp((int)((localPos.x / terrain.terrainData.size.x) * (heightmapRes - 1)), 0, heightmapRes - 1);
        int posZInTerrain = Mathf.Clamp((int)((localPos.z / terrain.terrainData.size.z) * (heightmapRes - 1)), 0, heightmapRes - 1);

        // 转换变形量为高度图相对比例
        float relativeDeformation = deformationAmount / terrain.terrainData.size.y;

        // 确定需要修改的高度图区域
        int startX = Mathf.Max(0, posXInTerrain - (int)deformationRadius);
        int endX = Mathf.Min(heightmapRes - 1, posXInTerrain + (int)deformationRadius);
        int startZ = Mathf.Max(0, posZInTerrain - (int)deformationRadius);
        int endZ = Mathf.Min(heightmapRes - 1, posZInTerrain + (int)deformationRadius);
        int width = endX - startX + 1;
        int depth = endZ - startZ + 1;

        // 获取目标区域的高度图数据
        float[,] heights = terrain.terrainData.GetHeights(startX, startZ, width, depth);

        // 遍历生成凹陷
        for (int x = 0; x < width; x++)
        {
            for (int z = 0; z < depth; z++)
            {
                float dist = Vector2.Distance(new Vector2(startX + x, startZ + z), new Vector2(posXInTerrain, posZInTerrain));
                if (dist < deformationRadius)
                {
                    // 平方衰减让凹陷边缘更自然,可调整幂次改变陡峭程度
                    float falloff = Mathf.Pow((deformationRadius - dist) / deformationRadius, 2);
                    float delta = falloff * relativeDeformation;
                    // 确保高度不低于0
                    heights[x, z] = Mathf.Max(0, heights[x, z] - delta);
                }
            }
        }

        // 将修改后的高度图写回地形
        terrain.terrainData.SetHeights(startX, startZ, heights);
    }
}

额外优化建议

  • 若频繁触发地形变形,可使用TerrainData.SetHeightsDelayLOD替代SetHeights,延迟LOD更新提升性能;或放入协程分帧处理,避免卡顿。
  • 可调整衰减公式的幂次,比如Mathf.Pow(falloff, 3)让凹陷更陡峭,Mathf.Sqrt(falloff)让边缘更平缓,适配不同爆炸效果需求。

内容的提问来源于stack exchange,提问作者SOOBATON

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.26 01:52:10