to be more regular on forbidden content, but carry on. Unity 场景道路制作,是很多开发者从“摆放几个 Cube 做测试”走向正式游戏场景时绕不开的一步。道路不只是玩家脚下的一条贴图带,它承担引导路线、划分区域、承载车辆或角色移动逻辑、影响寻路数据和关卡视觉节奏等多重任务。这次我们直接围绕 Unity 场景道路制作讲一套可落地的流程,从路面模型、贴图与 UV 处理,到导航寻路、路网拼接和性能优化,全部放在一个工程里讲完。文章会给出关键组件参数、材质节点逻辑、脚本核心代码和排查思路,适合 U3D 初学者、独立开发者,以及需要快速搭场景原型但不想在路面上反复返工的人。
先说结论:Unity 场景道路制作没有唯一标准做法,但有一组稳定可靠的组合方式。地面道路可以用 Terrain 刷、可以用 Plane 拼、可以用 ProBuilder 建模,也可以用 Spline 工具自动生成;城市道路和野外山路的处理逻辑完全不同。本文不会只讲一种方案,而是把道路制作的通用决策链路拆开:什么时候自己做模型,什么时候交给工具生成,贴图和 UV 怎么处理,导航网格怎么匹配,最后怎么验证实际效果。
1. 核心能力速览
| 能力项 | 说明 |
|---|---|
| 适用引擎版本 | Unity 2021 / 2022 LTS 为主,ProBuilder、Spline 工具需按版本匹配 |
| 道路制作方式 | 手工建模、ProBuilder 绘制、Spline 自动生成、Terrain 绘制 |
| 核心组件 | MeshRenderer、Terrain、NavMeshSurface、LineRenderer、Spline |
| 贴图要求 | 支持 PBR 材质,需处理 UV 方向和道路标线纹理 |
| 寻路支持 | 基于 NavMeshSurface 或旧版 NavMesh 烘焙 |
| 车辆/角色通行 | 需配合 Collider、物理材质或动画路径 |
| 性能重点 | 合并网格、控制材质球数量、减少重复 Draw Call |
| 适合场景 | 游戏原型、开放世界场景、城市道路、野外山路、导航测试 |
从材料看,Unity 道路制作最常用的几种方式分别是:ProBuilder 快速拉路面、Spline 工具做弯曲道路、Terrain 直接刷地形路径、以及纯模型拼接。每一种都有适用边界,下面按实战优先级展开。
2. 适用场景与使用边界
道路制作方案不能只看“哪个教程多”,要看你的场景对道路的依赖程度。
如果场景只是需要一条从起点到终点的平面引导路线,用带 Collider 的 Plane 或者一个拉伸出来的 Cube 就够,不需要额外工具。如果场景需要车辆沿道路行驶,道路必须有合理的宽度、摩擦系数和高度贴合,简单 Plane 会显得很假。如果场景是开放世界或大型地图,道路要反复拼接并保持一致风格,建议使用 Spline 工具生成,同时做网格合并。如果场景是山坡地形路,Terrain 绘制配合道路贴花或纹理混合更合适。
使用边界也要提前想清楚。道路模型和导航网格是两套系统,道路好看不代表角色能顺着走。NavMesh 的烘焙区域要覆盖实际可通行路面,不能只覆盖模型表面。道路如果是静态物体,可以做静态合批和光照贴图;如果道路需要被破坏、改变形状或动态加载,就不能盲目合并网格。另外,从公开热词可以看到,很多开发者关心 Unity 阴影、模型遮挡剔除、摄像机跟随和性能优化,这些在道路场景里同样重要:道路过长时 Shadow Distance 要控制,遮挡剔除要正确设置以阻挡不必要的绘制,摄像机跟随算法要避免在弯曲道路上插值过猛。
版权方面,如果道路贴图、标线纹理来自外部素材包,需要确认商用授权范围。涉及交通标识、品牌元素、真实城市地标的贴图不要直接使用。自己做纯色路面加程序化标线是最稳妥的合规方案。
3. Unity 场景道路环境准备
在开始道路制作之前,先确认工程状态,避免做到一半才发现单位制、光照和物理设置不对。
3.1 工程基础设置检查
Unity 的默认单位为 1 Unity Unit = 1 米。道路宽度如果是 8 米,那么场景里就是 8 个单位。确认方法:菜单 Edit -> Project Settings -> General,查看 Unity Units 相关设置。如果是从其他建模软件导入的道路模型,要注意 FBX 导入时的缩放系数,否则道路会突然变成原来的 100 倍或 0.01 倍。
3.2 包依赖
根据道路制作方案,按需安装以下包:
- ProBuilder:适用于快速建模、路面拉伸出弯道、交叉口拼接。
- Splines:Unity 官方 Spline 工具,能够沿路径生成道路网格和动画路径。
- Terrain Tools:编辑地形高度、纹理刷道路路径。
- AI Navigation:新版 Unity 中 NavMesh 烘焙的主要模块。
安装方式:Window -> Package Manager,在 Unity Registry 搜索包名并 Install。ProBuilder 和 Splines 都可以在包管理器直接安装。
3.3 场景结构规划
道路制作要避免所有物体堆在同一层级。建议如下结构:
SceneRoot ├── RoadNetwork │ ├── Road_Main │ ├── Road_Bridge │ ├── Crossroad_A │ └── Road_Detail ├── Navigation │ └── NavMeshSurface ├── Props └── TerrainRoadNetwork 下面只放道路模型相关物体,Navigation 单独保存导航烘焙组件,Terrain 独立一层,方便后续做遮挡剔除和 Load 卸载。
4. 道路制作方式详解
4.1 方式一:ProBuilder 快速建模道路
ProBuilder 适合做城市道路和道路拼接。它的特点是能直接在编辑器里创建 Mesh、拉伸面、切分边,不需要外部建模软件。
基础操作流程:
- 打开 ProBuilder 窗口:Tools -> ProBuilder -> ProBuilder Window。
- 新建一个 Cube,放在地面高度。
- 切换到 Edge 或 Face 编辑模式,选中顶面,按 Shift + D 复制面并拉伸。
- 拉出道路宽度和走向。
- 使用 Cut Tool 在交叉口位置切割出路口转折。
- 给物体赋材质。
顶点数量少、面数可控,适合做原型。缺点是不适合做超长连续道路,因为手动拉面很容易出现重叠顶点和 UV 方向混乱。
4.2 方式二:Spline 工具生成弯曲道路
Spline 工具适合山路、高速路、河流旁道路等需要平滑转弯的场景。Unity 官方 Splines 包可以直接把道路路径可视化成贝塞尔曲线。
使用步骤:
- 安装 Splines 包。
- 创建一个 GameObject,添加 Spline 组件。
- 在 Scene 视图里编辑路径点。
- 创建道路 Mesh:可以添加 Spline Extrude 组件,把 Extrude 的 Profile 设置成道路截面。
- 调整截面宽度和高度。
如果希望路面完全贴合地形,Spline 的每个控制点都要手动调整 Y 轴高度。更自动化的方案是写一个编辑器脚本,读取 Terrain 的采样高度,把 Spline 控制点 Y 值自动贴合地面:
using UnityEditor; using UnityEngine; using UnityEngine.Splines; public static class RoadTerrainFitter { [MenuItem("Tools/Road/Fit Spline To Terrain")] public static void FitSplineToTerrain() { Terrain terrain = Object.FindFirstObjectByType<Terrain>(); SplineContainer spline = Object.FindFirstObjectByType<SplineContainer>(); if (terrain == null || spline == null) return; for (int i = 0; i < spline.Spline.Count; i++) { BezierKnot knot = spline.Spline[i]; Vector3 pos = knot.Position; pos.y = terrain.SampleHeight(spline.transform.TransformPoint(pos)) + knot.Position.y; knot.Position = pos; spline.Spline.SetKnot(i, knot); } } }这段脚本没有使用 UnityEngine 中未来版本才有的旧 API,能够在当前常用 LTS 版本里运行。注意FindFirstObjectByType在 2022.3 以上版本可用,旧版请改成FindObjectOfType。
4.3 方式三:Terrain 刷出道路路径
Terrain 方式适合野外、乡村、山区道路。它不产生独立道路 Mesh,而是通过地形纹理混合显示路径。
操作流程:
- 添加 Terrain:GameObject -> 3D Object -> Terrain。
- 在 Terrain Settings 里创建多个 Terrain Layer。
- 把草地、泥土、碎石、沥青分别配置成不同 Layer。
- 使用 Paint Texture 工具,把沥青纹理沿路径方向刷出来。
- 用 Set Height 工具把地形压平,生成道路路基。
这种方式的优点是道路和地形自然融合,不会有悬浮感。缺点是很难做出笔直的边缘和复杂的道路标线。如果要标线,就需要额外的透明贴花作为子物体叠加。
4.4 方式四:外部建模软件导入
如果项目里有美术资源管线,用 Blender、3ds Max 或 Maya 制作道路模型最可控。尤其是城市道路、十字路口、匝道这种需要精确对齐的结构,外部建模再导入 Unity 的效率远高于在 Unity 里一点点拉面。
导入时注意这些设置:
- Model Scale 保持 1,不要随意改。
- UV 方向要一致,避免纹理拉伸。
- Read/Write 在不需要动态修改时关闭。
- 碰撞体建议在 Unity 中添加,而不是依赖 FBX 自带的 Collider。
5. 道路材质与贴图处理
道路材质不需要复杂到写一堆 Shader,但 UV 和纹理方向必须正确,否则会出现明显的拉伸和标线变形。
5.1 基础 PBR 材质设置
创建一个标准材质,Shader 选择 URP/Lit 或 Built-in 的 Standard,根据项目的渲染管线选择。把 Albedo 贴图设置为沥青路面纹理,粗糙度调到 0.7 到 0.9,金属度保持 0。道路贴图如果是平铺模式,注意 Tiling 参数要匹配道路长度,不能整套场景用同一个 Tiling 导致所有道路看起来一样密。
5.2 UV 方向对齐
道路是一条长条形 Mesh,如果模型是手工拉的,UV 可能没有统一方向。Scene 视图里开启 UV 编辑,确保道路贴图沿着路径方向拉伸,而不是横向扭曲。对于 Spline Extrude 生成的 Mesh,截面 UV 和路径 UV 通常由工具自动生成,但容易出现不同控制点间距不同导致的纹理密度不一致,需要手动调整 Extrude 的 UV Scale 参数。
5.3 道路标线制作
道路标线不建议直接画在 Albedo 贴图上。因为标线需要对齐道路中心线和车道位置,直接画在基础纹理上会随着道路弯曲变形。
推荐方案:标线使用单独的透明贴花,放置在道路表面上方 0.01 到 0.02 单位。这样标线独立于路面纹理,可以精确对齐转弯和路口。可以在贴花上直接放一个简单的 Material:
Shader: URP/Lit Surface Type: Transparent Base Map: 白色标线纹理,中间透明 Surface: 使用 Alpha Clipping 或者 Blend如果不想用贴花,也可以用 LineRenderer 直接在道路表面绘制标线。LineRenderer 支持沿路径连续绘制,适合虚线、实线、双黄线。
5.4 避免纹理拉伸
纹理拉伸在弯曲道路中最明显。控制 Spline 控制点距离,不要在两个距离差异很大的点之间强制连接。更稳妥的做法是在 Spline 上增加中间点,让每个分段长度接近,这样纹理密度会更均匀。
6. 道路寻路与导航设置
道路做好看,角色能不能走是另一回事。Unity 的 NavMesh 不会自动贴合道路模型,需要单独烘焙导航网格。
6.1 新版 NavMesh 烘焙
安装 AI Navigation 包后,在道路物体上添加 NavMeshSurface 组件。Surface 的烘焙范围要覆盖道路,而不是整个地形。
参数建议:
| 参数 | 建议值 | 说明 |
|---|---|---|
| Agent Radius | 0.5 到 0.8 | 匹配角色实际半径 |
| Agent Height | 1.5 到 2.0 | 匹配角色身高 |
| Max Slope | 30 到 45 | 道路坡度过大时路径会断 |
| Step Height | 0.3 到 0.5 | 路缘石高度边界 |
| Generate Links | 开启 | 处理道路连接处跳跃 |
烘焙后,Scene 视图会显示蓝色区域。角色 NavMeshAgent 的 Radius 和 Height 设置必须和 Surface 参数相近,否则会出现“路看起来可以走,但寻路失败”的情况。
6.2 寻路掩码处理
如果场景里有桥梁、隧道或多层道路,需要区分不同高度的 NavMesh。使用 NavMeshSurface 的 Object Layer 和 NavMesh Area Mask 组合,让不同层道路属于不同 Area,然后在 NavMeshAgent 的 Area Mask 中勾选允许通行的层。
Layer 0: Road_Default Layer 1: Road_Bridge Layer 2: Road_UnderGround这种设计能避免角色在路面高度判断上出问题。
6.3 道路碰撞体
道路如果使用 MeshCollider 或 Terrain Collider,角色物理表现要额外测试。MeshCollider 在复杂弯道路上容易产生碰撞体遍历的性能开销,可以考虑用 BoxCollider 组合模拟。车辆沿道路行驶时,要检查轮胎的摩擦材质,PhysicMaterial 的 Dynamic Friction 和 Static Friction 不要直接保持默认值,否则道路表面会像冰面。
7. 道路拼接与批量场景搭建
场景道路不是单条线,通常由主路、支路、交叉口和连接段组成。零散摆放的 Model 会在运行时产生大量 Draw Call,必须做好合并。
7.1 合并同材质网格
使用 Unity 的 Mesh.CombineMeshes 或第三方合并工具,把所有使用相同道路材质的 Mesh 合并成一个。合并前注意:
- 物体必须是静态的。
- 材质列表必须完全一致。
- UV 不能重叠冲突。
- 合并后如果需要独立碰撞,保留原始 Collider 或统一使用 MeshCollider。
合并后的道路物体适合参与 Static Batching 和遮挡剔除。
7.2 交叉口对齐
交叉口最容易出现缝隙。推荐用 ProBuilder 的 Boolean 或手动顶点对齐来处理。先用一个主路模型穿过交叉口,再用另一个连接模型切割,保证衔接处没有悬空和重叠。
7.3 使用预制体管理道路段
把一条 50 米或 100 米的道路段做成 Prefab,场景里重复摆放。每种道路类型只保留有限的几个 Prefab 变体,避免每个路口都重新建模浪费时间。预制体里的道路段可以包含:Mesh、Collider、标线贴花、路口信号灯基座等。预制体修改一次,场景里所有引用同步更新,批量搭建场景时效率提升明显。
8. 道路相关动画与车辆行驶路径
道路制作还包括车辆、行人沿道路运动的逻辑。Unity 里最常用的两种实现是 NavMeshAgent 和 Spline Animate。
8.1 车辆沿路行驶
如果车辆需要遵守道路方向、变道和路口停让,使用 NavMeshAgent 更合适。给车辆挂 NavMeshAgent,设置 Radius、Speed、Angular Speed,然后调用 SetDestination。路口停让逻辑可以通过脚本检测前方 3 到 5 米的障碍物,在距离小于安全值时减速或停止。
8.2 固定路径动画
如果是一段固定循环的展示动画,比如过场动画中的车辆行驶,使用 Spline Animate 组件更简单。把车辆放在 Spline 上,Spline Animate 的 Object Up 和 Object Forward 配置好,车辆就会自动沿着道路运动。这种方式适合做宣传片、登录背景、NPC 循环遛弯,不需要寻路逻辑。
8.3 摄像机跟随与道路观察
道路弯曲时,摄像机跟随容易出现抖动或拉近远跳。最直接的处理是使用 Cinemachine 的 Virtual Camera,增加 Smoothing 参数,并限制 Y 轴旋转。如果道路是下山路,摄像机要限制最低高度,防止穿模到地形下方。
9. 资源占用与常见问题排查
9.1 显存和渲染开销
道路 Mesh 本身占用不算高,但纹理数量、阴影投射和 Draw Call 会迅速拉高开销。一般要关注的数据有:三角形数量、材质球数量、纹理分辨率、阴影距离。长直道路这样的大型地面物体,建议关闭动态阴影或只投射近距离阴影。
Shader 如果使用过大面积的 Tiling 纹理,纹理会因为 mipmap 层级过低而闪烁。解决办法是给道路纹理开启 Generate Mip Maps,并配合 Streaming Mipmap。如果场景需要在低端设备运行,可以把路面纹理控制在 1024 x 1024 甚至更低。
9.2 常见问题排查表
| 问题现象 | 可能原因 | 排查方式 | 解决方案 |
|---|---|---|---|
| 道路纹理会拉伸 | UV 方向不一致 | Scene 视图开启 UV 编辑 | 调整 UV 或重新生成道路网格 |
| 标线转弯处断裂 | 贴花跟随曲面变形 | 检查贴花覆盖范围 | 使用多个贴花分段贴合 |
| 角色走上路面却寻路失败 | NavMeshSurface 未覆盖道路 | Scene 视图查看蓝色区域 | 扩大 Surface 范围或重建烘焙 |
| 道路悬浮在地形上方 | 控制点 Y 轴未贴合地面 | 检查 Spline 点位置 | 运行地形贴合脚本 |
| 道路显示黑色或偏暗 | 法线方向错误 | 检查 Mesh 法线 | 翻转法线或重置法线 |
| 大量道路段掉帧 | Draw Call 过多 | 查看 Profiler | 合并同材质网格并开启 Static Batching |
| 阴影闪烁 | Shadow Distance 过大 | 调整 Quality 设置 | 降低阴影距离或使用阴影级联裁剪 |
| 角色穿模 | Collider 未覆盖路面 | 检查物理模拟 | 统一添加 BoxCollider 或 MeshCollider |
9.3 性能调试方法
不要凭感觉判断性能。Unity 里使用 Window -> Analysis -> Profiler,重点看 Rendering 和 Physics 两项。Rendering 里的 Batches 数量如果很高,说明合批策略有问题。Physics 里的 MeshCollider 数量如果很高,考虑换成简单碰撞体。另外,RoadNetwork 下的物体数量也要控制,场景加载时若大量 GameObject 同时激活,CPU 峰值会非常明显。
10. 最佳实践与合规建议
道路制作虽然不是高风险功能,但有一些容易被忽视的工程化原则。
第一,道路和地形不要互相穿插。很多新手在 Terrain 起伏较大的地方放道路模型,结果出现道路悬空或者地形穿出路面的现象。最简单的方法是让道路贴合地形后再调整标高,或者在地形上压出道路区域。
第二,道路贴图尽量使用自己的纹理,不要直接使用外部项目里的贴图。如果要用素材包,先看 License。商用项目尤其注意。
第三,每个道路段都要有独立命名规则。不要用 Cube (1)、Cube (2) 这种方式命名。建议命名格式为Road_Type_Length_Index,例如Road_Main_100_A_01,场景大了之后能快速定位和批量修改。
第四,批量搭建场景时,优先使用 Prefab 和网格合并,不要用复制粘贴后手动改位置的原始方式。检查 Primitive Collider 是否多余,默认 Cube 自带的 Collider 会造成不必要的物理开销。道路段如果不需要物理碰撞,直接删除 Collider。
第五,涉及车辆、NPC、人物在道路上运动时,测试寻路和物理的时间不要少于道路建模时间。道路建模可能只需要一小时,寻路障碍和碰撞体问题可能消耗一整天。
11. 总结与下一步
这次关于 Unity 场景道路制作,核心不是选一个“最强”方案,而是根据场景类型选择正确的组合:城市道路用 ProBuilder 加预制体,弯曲山路用 Spline 加地形贴合,自然地形用 Terrain 刷纹理,高精度商用场景用外部建模软件。道路完成后,别急着开始摆道具,先把 NavMesh 烘焙、碰撞体、阴影距离和素材授权这几件事过一遍。先用一小段 50 米道路做全流程测试,确认材质、寻路、物理都没问题,再大规模铺开。
最容易踩的坑是道路和寻路脱节:模型好看但 NavMesh 没覆盖,或者覆盖了但角色过不去。记住一个判断标准:路能走,不是“看起来像路”,而是角色或车辆能实际从起点到终点。建议后续再试一下 Spline 自动生成加动态拆分的方案,做一个包含立交桥或隧道的复杂路网,验证多层 NavMesh 的可行性和 Draw Call 表现。