3.12 地形 (Terrain)


文档摘要

3.12 地形 (Terrain) 三、Unity 核心模块父章节领域:3.12 地形 (Terrain) 详解 3.12.1 地形系统概述 地形系统在 Unity 中是一个强大的工具,它基于高度图 (Heightmap) 的概念来生成和渲染三维景观。高度图本质上是一个二维数组,每个像素的灰度值代表了该点的高度信息。Unity 地形系统读取高度图数据,将其转化为网格 (Mesh),并应用各种纹理、细节和植被,最终呈现出逼真的地形效果。 地形系统的核心优势: 高效的场景构建: 相比于手动建模,地形系统可以快速生成大面积的复杂地形,节省大量建模时间。 优化的渲染: Unity 地形系统针对大规模地形渲染进行了优化,能够有效地处理复杂的几何体和纹理,保持流畅的帧率。

3.12 地形 (Terrain)

三、Unity 核心模块父章节领域:3.12 地形 (Terrain) 详解

3.12.1 地形系统概述

地形系统在 Unity 中是一个强大的工具,它基于高度图 (Heightmap) 的概念来生成和渲染三维景观。高度图本质上是一个二维数组,每个像素的灰度值代表了该点的高度信息。Unity 地形系统读取高度图数据,将其转化为网格 (Mesh),并应用各种纹理、细节和植被,最终呈现出逼真的地形效果。

地形系统的核心优势:

  • 高效的场景构建: 相比于手动建模,地形系统可以快速生成大面积的复杂地形,节省大量建模时间。

  • 优化的渲染: Unity 地形系统针对大规模地形渲染进行了优化,能够有效地处理复杂的几何体和纹理,保持流畅的帧率。

  • 丰富的编辑工具: Unity 提供了强大的地形编辑工具,包括高度雕刻、纹理绘制、植被添加等,方便开发者直观地塑造地形。

  • 集成物理系统: 地形系统与 Unity 的物理引擎无缝集成,可以轻松实现角色在地形上的行走、碰撞等交互。

  • 可扩展性: 地形系统支持自定义材质、着色器和脚本扩展,满足高级用户的需求。

高度图概念可视化 (Mermaid Graph):

3.12.2 创建和配置地形

在 Unity 中创建地形非常简单。您可以通过以下步骤完成:

  1. 创建地形对象: 在 Unity 编辑器中,选择 "GameObject" -> "3D Object" -> "Terrain"。 这将在场景中创建一个默认的地形对象。

  2. 访问地形设置: 选中场景中的 Terrain 对象,在 Inspector 面板中可以看到 Terrain 组件。点击 "Terrain Settings" (齿轮图标) 可以打开地形设置面板。

关键地形设置参数详解:

  • Base Terrain Settings (基础地形设置):

    • Width (宽度), Length (长度), Height (高度): 定义地形在世界空间中的尺寸。宽度和长度决定了地形的水平范围,高度决定了地形的最大垂直高度。

    • Pixel Error (像素误差): 控制地形网格的细节级别。较低的值会生成更精细的网格,但会增加渲染开销。较高的值会降低网格细节,提高性能。平衡像素误差是优化地形性能的关键。

    • Basemap Distance (基础贴图距离): 定义从相机到地形多远距离时,地形开始使用较低分辨率的基础贴图 (Basemap)。这是一种距离衰减技术,用于优化远距离地形的渲染性能。

  • Draw Settings (绘制设置):

    • Pixel Error, Basemap Distance: 与基础地形设置中的参数作用相同,但应用于绘制阶段。

    • Detail Distance (细节距离): 控制细节物体 (如草、小石头) 的渲染距离。超过此距离的细节物体将不会被渲染,以提高性能。

    • Tree Distance (树木距离): 控制树木的渲染距离。与细节距离类似,超过此距离的树木将被剔除。

    • Billboard Start (广告牌起始距离): 对于树木,当距离相机超过此距离时,将使用广告牌 (Billboard) 技术进行渲染,即用简单的平面图像替代复杂的树木模型,以进一步优化性能。

  • Material Settings (材质设置):

    • Material Template (材质模板): 允许您选择预设的地形材质模板。Unity 提供了内置的 Standard Terrain Shader 模板。

    • Custom Material (自定义材质): 如果您需要更高级的材质效果,可以选择 "Custom Material" 并指定自定义的 Shader 和材质。

代码实践 - 创建并配置地形 (C#):

using UnityEngine; public class CreateTerrain : MonoBehaviour { void Start() { // 创建一个新的 Terrain GameObject GameObject terrainGameObject = Terrain.CreateTerrainGameObject(TerrainData.CreateDefaultTerrainData()); // 获取 Terrain 组件 Terrain terrain = terrainGameObject.GetComponent<Terrain>(); TerrainData terrainData = terrain.terrainData; // 配置 TerrainData (例如,修改尺寸) terrainData.size = new Vector3(500, 600, 500); // 宽度 500, 高度 600, 长度 500 // 应用修改后的 TerrainData terrain.terrainData = terrainData; Debug.Log("地形已创建并配置!"); } }

这段代码演示了如何使用 C# 脚本在运行时动态创建地形并修改其尺寸。 Terrain.CreateTerrainGameObject() 方法用于创建地形对象,TerrainData.CreateDefaultTerrainData() 创建默认的地形数据。通过修改 terrainData.size 可以调整地形的宽度、高度和长度。

3.12.3 地形雕刻与高度图编辑

地形雕刻是塑造地形外观的核心环节。Unity 提供了丰富的地形编辑工具,位于 Inspector 面板的 "Paint Terrain" 工具栏下。

常用的地形雕刻工具:

  • Raise/Lower Height (抬升/降低高度): 最基础的工具,用于抬高或降低地形的高度。按住 Shift 键可以降低高度。

  • Paint Height (绘制高度): 允许您将地形高度设置为一个特定的值。可以用于创建平坦的区域或精确控制高度。

  • Smooth Height (平滑高度): 用于平滑地形的表面,减少锯齿感,使地形过渡更加自然。

  • Flatten Height (展平高度): 将地形高度展平到一个指定的高度。

  • Stamp Height (印章高度): 使用预定义的笔刷纹理 (Stamp) 来在地形上印刻形状,例如山峰、陨石坑等。

笔刷设置:

  • Brush Size (笔刷大小): 控制笔刷的影响范围。

  • Opacity (不透明度): 控制笔刷效果的强度。较低的不透明度会产生更柔和的效果。

  • Brush (笔刷类型): Unity 提供了多种笔刷形状,您可以根据需要选择合适的笔刷。也可以导入自定义的笔刷纹理。

高度图的导入和导出:

  • 导入高度图: 在 Terrain Settings 面板中,可以找到 "Heightmap Import/Export" 部分。您可以导入 RAW 格式或 PNG 格式的高度图文件。RAW 格式文件通常用于存储原始的高度数据,而 PNG 格式则可以存储带有视觉预览的高度图。

  • 导出高度图: 同样在 "Heightmap Import/Export" 部分,您可以导出当前地形的高度图为 RAW 或 PNG 文件,以便在其他软件中使用或备份。

代码实践 - 程序化修改地形高度 (C#):

using UnityEngine; public class ModifyTerrainHeight : MonoBehaviour { public Terrain terrain; public float modificationStrength = 0.1f; public float radius = 10f; void Update() { if (Input.GetMouseButton(0)) // 当鼠标左键按下时 { Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition); RaycastHit hit; if (terrain.GetComponent<Collider>().Raycast(ray, out hit, Mathf.Infinity)) { Vector3 terrainLocalPos = terrain.transform.InverseTransformPoint(hit.point); float normalizedX = Mathf.InverseLerp(0, terrain.terrainData.size.x, terrainLocalPos.x); float normalizedZ = Mathf.InverseLerp(0, terrain.terrainData.size.z, terrainLocalPos.z); int heightmapWidth = terrain.terrainData.heightmapResolution; int heightmapHeight = terrain.terrainData.heightmapResolution; int xCoord = (int)(normalizedX * heightmapWidth); int zCoord = (int)(normalizedZ * heightmapHeight); float[,] heights = terrain.terrainData.GetHeights(0, 0, heightmapWidth, heightmapHeight); for (int x = Mathf.Max(0, xCoord - (int)radius); x < Mathf.Min(heightmapWidth, xCoord + (int)radius); x++) { for (int z = Mathf.Max(0, zCoord - (int)radius); z < Mathf.Min(heightmapHeight, zCoord + (int)radius); z++) { float distance = Vector2.Distance(new Vector2(x, z), new Vector2(xCoord, zCoord)); if (distance < radius) { heights[z, x] += modificationStrength * (1 - distance / radius); // 锥形衰减效果 } } } terrain.terrainData.SetHeights(0, 0, heights); } } } }

这段代码演示了如何通过鼠标点击来动态修改地形高度。它使用了 Raycast 来检测鼠标点击在地形上的位置,然后根据点击位置和半径,修改高度图数据 heights 数组,最后使用 terrain.terrainData.SetHeights() 方法更新地形。代码中使用了锥形衰减效果,使得修改效果在中心最强,边缘逐渐减弱。

高度图数据结构 (Mermaid Graph):

3.12.4 地形纹理与材质绘制

为地形添加纹理是使其看起来更真实和生动的关键步骤。Unity 地形系统使用 Terrain Layers (地形层) 来管理地形纹理。

Terrain Layers (地形层):

  • 创建 Terrain Layer: 在 Inspector 面板的 "Paint Terrain" 工具栏下,选择 "Paint Texture" 工具。点击 "Layers" 下方的 "+" 按钮,可以创建新的 Terrain Layer。

  • 配置 Terrain Layer: 每个 Terrain Layer 可以设置以下属性:

    • Texture (Albedo): 主纹理贴图。

    • Normal Map: 法线贴图,用于增加表面细节和光照效果。

    • Tile Size (平铺尺寸): 控制纹理在地形上的平铺大小。

    • Metallic, Smoothness: 用于 PBR (Physically Based Rendering) 材质的金属度和光滑度参数。

纹理绘制工具:

  • Paint Texture (绘制纹理): 选择一个 Terrain Layer,然后使用笔刷在地形上绘制该纹理。可以混合多种 Terrain Layer,创建丰富的纹理效果。

代码实践 - 添加 Terrain Layer (C#):

using UnityEngine; using UnityEditor; // 需要在编辑器环境下运行 public class AddTerrainLayer : MonoBehaviour { public Terrain terrain; public Texture2D albedoTexture; public Texture2D normalMapTexture; public Vector2 tileSize = Vector2.one * 10; void Start() { TerrainData terrainData = terrain.terrainData; TerrainLayer[] terrainLayers = terrainData.terrainLayers; // 创建新的 TerrainLayer TerrainLayer newLayer = new TerrainLayer(); newLayer.diffuseTexture = albedoTexture; newLayer.normalMapTexture = normalMapTexture; newLayer.tileSize = tileSize; // 将新的 TerrainLayer 添加到 TerrainData if (terrainLayers == null) { terrainData.terrainLayers = new TerrainLayer[] { newLayer }; } else { TerrainLayer[] newLayersArray = new TerrainLayer[terrainLayers.Length + 1]; terrainLayers.CopyTo(newLayersArray, 0); newLayersArray[terrainLayers.Length] = newLayer; terrainData.terrainLayers = newLayersArray; } // 刷新 Terrain Inspector (仅在编辑器环境下) if (Application.isEditor) { EditorUtility.SetDirty(terrainData); } Debug.Log("Terrain Layer 已添加!"); } }

这段代码演示了如何在运行时通过脚本添加新的 Terrain Layer。它创建了一个 TerrainLayer 对象,设置了纹理和参数,然后将其添加到 terrainData.terrainLayers 数组中。注意,在编辑器环境下需要使用 EditorUtility.SetDirty() 来刷新 Inspector 面板。

Terrain Layer 结构 (Mermaid Graph):

3.12.5 添加细节:树木、草和细节网格

为了进一步增强地形的真实感和细节,Unity 地形系统允许您添加树木、草地和其他细节网格。

添加树木:

  • Tree Prototypes (树木原型): 在 Inspector 面板的 "Paint Terrain" 工具栏下,选择 "Paint Trees" 工具。点击 "Edit Trees" -> "Add Tree" 来添加新的树木原型。您可以选择 3D 模型作为树木原型。

  • Painting Trees (绘制树木): 选择一个树木原型,然后使用笔刷在地形上绘制树木。

  • Tree Settings (树木设置): 包括树木密度 (Tree Density)、树木间距 (Tree Spacing)、树木高度和宽度缩放 (Tree Height/Width Scale) 等参数。

添加细节 (草地、石头等):

  • Detail Prototypes (细节原型): 在 Inspector 面板的 "Paint Terrain" 工具栏下,选择 "Paint Details" 工具。点击 "Edit Details" -> "Add Detail Mesh" 或 "Add Detail Texture" 来添加细节原型。您可以选择网格模型或纹理贴图作为细节原型。

  • Painting Details (绘制细节): 选择一个细节原型,然后使用笔刷在地形上绘制细节。

  • Detail Settings (细节设置): 包括细节密度 (Density)、细节放置模式 (Placement Mode)、颜色变化 (Color Variations) 等参数。

代码实践 - 添加树木原型 (C#):

using UnityEngine; using UnityEditor; // 需要在编辑器环境下运行 public class AddTreePrototype : MonoBehaviour { public Terrain terrain; public GameObject treePrefab; void Start() { TerrainData terrainData = terrain.terrainData; TreePrototype[] treePrototypes = terrainData.treePrototypes; // 创建新的 TreePrototype TreePrototype newPrototype = new TreePrototype(); newPrototype.prefab = treePrefab; // 将新的 TreePrototype 添加到 TerrainData if (treePrototypes == null) { terrainData.treePrototypes = new TreePrototype[] { newPrototype }; } else { TreePrototype[] newPrototypesArray = new TreePrototype[treePrototypes.Length + 1]; treePrototypes.CopyTo(newPrototypesArray, 0); newPrototypesArray[treePrototypes.Length] = newPrototype; terrainData.treePrototypes = newPrototypesArray; } // 刷新 Terrain Inspector (仅在编辑器环境下) if (Application.isEditor) { EditorUtility.SetDirty(terrainData); } Debug.Log("Tree Prototype 已添加!"); } }

这段代码演示了如何通过脚本添加新的树木原型。它创建了一个 TreePrototype 对象,指定了树木预制体,然后将其添加到 terrainData.treePrototypes 数组中。

细节物体放置流程 (Mermaid Graph):

3.12.6 地形优化与性能考量

大规模地形的渲染和处理会带来性能挑战。以下是一些地形优化的关键策略:

  • Pixel Error 调整: 合理设置 Pixel Error 值,避免过高的网格细节导致渲染开销过大。根据实际需求调整,远处的地形可以适当提高 Pixel Error 值。

  • Basemap Distance 设置: 有效利用 Basemap Distance,降低远距离地形的纹理分辨率,减少纹理采样开销。

  • Detail Distance 和 Tree Distance: 限制细节和树木的渲染距离,剔除远距离的细节物体,显著提高性能。

  • LOD Groups (层级细节组): 对于复杂的树木模型,可以使用 LOD Groups,在不同距离切换不同精度的模型,进一步优化树木渲染性能。

  • Heightmap Resolution: 选择合适的高度图分辨率。过高的分辨率会增加内存占用和计算开销,过低的分辨率会降低地形细节。根据地形的范围和所需细节程度选择合适的分辨率。

  • Detail Density: 控制细节物体的密度,避免过高的密度导致过度绘制。

  • Draw Distance for Details and Trees: 精细调整细节和树木的绘制距离,确保只渲染玩家可见范围内的细节物体。

  • Terrain Collider: 如果不需要物理交互,可以禁用 Terrain Collider,减少物理计算开销。如果需要物理交互,可以使用 Raycast 进行碰撞检测,而不是依赖 Terrain Collider 的持续碰撞检测。

  • 材质优化: 使用优化的地形 Shader,例如 Unity 提供的 Standard Terrain Shader,并合理配置材质参数,避免不必要的复杂计算。

  • 地形分割 (Terrain Splitting): 对于非常大的地形,可以将其分割成多个小的 Terrain 对象,使用 Terrain Tile 系统或手动分割,实现分块加载和渲染,提高性能。

性能优化流程 (Mermaid Graph):

3.12.7 高级地形特性 (可选)

  • Terrain Holes (地形洞穴): Unity 2019.3 及更高版本引入了 Terrain Holes 功能,允许在地形中创建洞穴或地下区域。通过在高度图中指定特殊区域,可以镂空地形网格,实现洞穴效果。

  • Custom Brushes (自定义笔刷): Unity 允许开发者创建自定义的地形笔刷,用于更精细的地形雕刻和纹理绘制。

  • Terrain API 扩展: Unity 提供了丰富的 Terrain API,开发者可以使用脚本进行程序化地形生成、地形编辑和高级功能扩展,例如动态地形变形、河流生成、道路铺设等。


发布者: 作者: 转发
评论区 (0)
U