简介一份基于Unity 2021打造的期末作业——第三人称漫游精美场景模型面向游戏开发初学者、在校学生可用于完成大作业或系统学习Unity项目开发全流程。资源内含山谷、房屋、桌椅等精细3D场景模型实现鼠标控制小狐狸移动、血条、菜单与按钮等交互覆盖角色控制器、场景搭建、UI布局等多模块。压缩包文件总数两千个包含一千五百九十六个脚本、一百五十四个模型、一百一十九个预制体、八百一十二个贴图、四十七个场景文件及动画、音频等资产整体约一百一十三兆目录结构清晰便于按模块检索与复用。已有两千九百九十人学习或下载。通过该工程可掌握第三人称视角实现、移动控制、界面与材质渲染等技能为独立游戏开发积累实战经验。1. 用 Unity2021 做第三人称精美场景这个期末作业到底在考什么第三人称漫游是 Unity 期末作品里最稳的“大综合题”它强制你同时处理角色控制器、镜头跟随、场景布局、光照和碰撞任何一个环节断了交上去的演示视频都会露怯。很多同学做这个题目的翻车点不在代码而在“角色走了两步就穿模”“场景模型摆得像仓库”“灯光一开画面惨白”。这篇笔记就按 Unity2021 版本的固定路径来讲先在空场景里把第三人称控制器跑通再往里面做地形和视觉最后把曝光、阴影、碰撞这些细节收干净。适合准备期末作业的同学照着复现更适合已经装了 Unity2021 但不知道从哪下手的从业者顺一遍思路。2. 先让“能走的角色”活起来第三人称控制器的搭建顺序2.1 为什么我推荐直接用 CharacterController而不是 Rigidbody第三人称角色移动Unity 里无非两条路Rigidbody 物理驱动或者 CharacterController 参数驱动。期末作品我一般建议直接用 CharacterController。Rigidbody 要处理摩擦力、质心、碰撞材质调起来很玄学角色一受外力就原地转圈。CharacterController 本质是“胶囊体 简化物理”它自己处理坡度、台阶、碰撞你只需要给速度向量。下面是最小可用的第三人称移动脚本基于相机朝向计算移动方向角色自动转向using UnityEngine; public class ThirdPersonMovement : MonoBehaviour { public float moveSpeed 4f; public float rotateSpeed 8f; public float jumpHeight 1.2f; public Transform cameraTransform; private CharacterController controller; private float verticalVelocity; private const float GRAVITY -9.81f; void Start() { controller GetComponentCharacterController(); Cursor.lockState CursorLockMode.Locked; } void Update() { float h Input.GetAxis(Horizontal); float v Input.GetAxis(Vertical); // 关键一行把镜头朝向投影到地面再把输入映射成世界方向 Vector3 forward cameraTransform.forward; Vector3 right cameraTransform.right; forward.y 0f; right.y 0f; forward.Normalize(); right.Normalize(); Vector3 moveDir (forward * v right * h).normalized; // 角色朝向缓动避免原地甩头 if (moveDir.magnitude 0.1f) { Quaternion targetRot Quaternion.LookRotation(moveDir); transform.rotation Quaternion.Slerp(transform.rotation, targetRot, rotateSpeed * Time.deltaTime); } // 重力与跳跃 if (controller.isGrounded verticalVelocity 0f) { verticalVelocity -2f; // 轻微负值防止贴地抖动 } if (Input.GetButtonDown(Jump) controller.isGrounded) { verticalVelocity Mathf.Sqrt(jumpHeight * -2f * GRAVITY); } verticalVelocity GRAVITY * Time.deltaTime; Vector3 finalMove moveDir * moveSpeed; finalMove.y verticalVelocity; controller.Move(finalMove * Time.deltaTime); } }这个脚本的逻辑顺序要讲清楚。先取相机 forward 和 right 并去掉 y 分量是为了让“按 W 往前走”永远朝着镜头看的方向而不是世界坐标的死方向。这是第三人称漫游和第一人称最大的区别玩家在旋转视角时操控角色的移动方向会跟着变。如果漏了forward.y 0f角色在上下坡时会往天空方向飘这是我见过最多的第三人称翻车现场。参数上moveSpeed在校园场景里建议 3 到 5太快镜头跟不上太慢画面显得拖沓。rotateSpeed是 Slerp 的插值速度8 到 12 比较跟手低于 3 角色会像按了减速带。跳跃高度看场景有没有平台设计没有就保持在 1.0 到 1.2太高会破坏地面碰撞的信任感。2.2 Cinemachine 免费相机为什么漫游体验一半靠镜头角色能走了镜头如果还挂在 Update 里手动写会出现一个典型的“拖尾感”角色停住镜头还在晃或者角色转弯镜头甩过头。Unity2021 版本里Cinemachine 已经是成熟的官方式包光标跟随用 FreeLook 相机几乎不需要写代码。操作顺序我习惯这样走。先给角色加一个空物体做为“头部锚点”位置在角色头顶上方 0.5 米然后从菜单Cinemachine - Create FreeLook Camera创建相机把Follow拖到角色根节点把Look At拖到这个锚点。接下来要改三个关键参数Orbitals里的三个轨道半径建议是 4 / 6 / 8分别控制近距离、中距离、远距离的环绕半径半径越小越容易穿过墙壁。Orbital Y的角速度默认 3现场候会感觉到迟钝改成 4 到 5追角色更直接。Lookahead Time设成 0.3 到 0.5镜头会预测角色的运动方向显得平滑。FreeLook 相机不写成代码有三个实打实的好处它自动处理角色转身时的镜头插值它内置了“避免遮挡”逻辑角色靠近 May 起来时会自动回拉它支持不同高度轨道切换方便展示场景的高低差。期末演示里你用鼠标右键拖动镜头环绕角色一瞬间就能让评审意识到场景模型的立体感。这个“环绕感”是手动 Camera 脚本很难做出来的。2.3 输入系统Unity2021 用旧的 Input Manager 足够应付作业Unity2021 同时支持老版 Input Manager 和新版 Input System 包。新版功能更全支持手柄震动、组合键、Action 资产但它有一个显著代价你需要在 Inspector 里配置 Input Action 资产然后再写一个 PlayerInput 组件来激活它。对期末作品来说这个学习曲线不值当。我的建议是项目创建时选择Input System Package (Active)会造成麻烦就直接在Edit - Project Settings - Player - Active Input Handling里选择Both或Input Manager (Old)。上面脚本里出现的Input.GetAxis和Input.GetButtonDown都是旧输入接口默认情况下它们在 Unity2021 中是可用的不用做任何额外配置。如果在Project Creation Wizard里选了“URP 新输入系统”的模板新建工程后去Window - Package Manager里确认安装的是哪个输入包。如果已经装了Input System且冲突就把Active Input Handling切到Both新旧接口可以共存。这是很多同学工程崩的起点角色脚本没错但 API 被新输入系统屏蔽了Move 方法完全不响应。3. 从素材堆到场景模型精美场景的铺设与光照全流程3.1 先画漫游动线再放模型场景设计的唯一原则拿到一堆精美场景模型后最容易犯的错是“哪里好看往哪放”。结果角色一出生就卡在树桩里或者要穿过一条毫无引导的暗巷。我的习惯是先在纸上画一条 L 形或 U 形动线明确玩家从出生点走到终点时视线会被哪些物体引导。动线决定了场景骨架。以“森林小径 废墟遗迹”这个经典题材为例我会规划三段式出生点是一个开阔的草地引导玩家看向远处的高塔中段是一条两侧有高墙或树木的窄路玩家必须转弯才能看到下一个目标终点是一个有高低差的废墟台阶让镜头能从上往下俯拍全景。这条动线直接决定了场景模型的摆放密度。靠近动线的模型要控制数量留出视线通透区远离动线的背景模型可以密集摆放用来填充视野边缘。判断标准很简单在 Game 视图里用 Cinemachine 拉一圈如果视线任何角度都能看到 3 个以上的视觉锚点场景就不显得空。3.2 用 Unity2021 地形工具打底再用手工模型做细节Unity 自带地形工具在GameObject - 3D Object - Terrain创建。地形有两个主要用途第一是提供大范围的高度起伏第二是刷纹理让地面材质过渡自然。地形建模时我会把分辨率控制在Terrain Settings - Resolution下Map Size 用 200x200Detail Resolution 不用拉满保持默认 1024不然地形烘焙会慢到吃午饭。刷地形纹理要遵循“明暗分区”。先刷一层大面积的草地作为基底然后选一张泥土或碎石纹理用Brush Size在路径边缘和树根附近刷第二层。不推荐做第五层、第六层纹理叠加那是给大团队做的精细地表期末场景时间不够而且多层纹理在低端显卡上可能会出现明显的spread闪烁。地形的坑在树和草。Unity 地形树用Paint Trees刷草用Paint Details刷这两项对性能的消耗远大于手工摆放。我的建议漫游路线两侧的树用手工Prefab摆放并且给每一棵树套一个LOD Group远处的树群才用 Terrain 的批量刷写。手工模型负责“记忆点”。买来的场景模型包里通常有巨石、断柱、栅栏这些物体不要随机旋转摆放要按“三角形构图”放三个主要物体成 L 形布局中间夹一条可走的路模型之间互相遮挡一部分。核心 ComfyObject 于营造层次感这些手动放置的模型才是期末评分时让画面有质感的来源。3.3 URP 管线选择为什么画面发灰先查渲染管线Unity2021 项目创建模板里有一项3D Sample Scene (URP)这个顺手选的选项决定了后续所有场景模型看起来什么样。URP通用渲染管线对光照和后期效果的表现比内置渲染管线的默认效果更好色调偏写实。但如果你是从网上下载的老模型包材质多半是Standard Shader写的在 URP 下会变成粉红色或紫色。检查方法很直观选中角色或场景物体如果材质显示为洋红色说明模型材质不兼容 URP。解决办法有两个。第一个是不要切换管线新建项目时选3D Sample Scene (Built-in)模板继续用内置渲染管线老材质完全兼容只是画面质感要靠自己调。第二个是坚持用 URP把所有模型的 Shader 手动换成Universal Render Pipeline/Lit并重新配置Albedo、Metallic、Smoothness贴图。我的实际建议如果是买的精品场景模型优先用内置管线。这些模型的贴图、法线、粗糙度都是为 Built-in 调好的换到 URP 后皮肤发灰、树叶透光需要大量手工校正。如果是从头开始新建场景素材再考虑 URP。因为 URP 的全局雾、环境光、后处理管线更顺手问题是重新配置材质的成本。期末时间紧不要临阵换管线。3.4 光照三步走方向光、补光、烘焙第一步是方向光。GameObject - Light - Directional Light创建太阳Rotation 大概设置在 X 轴 45 度、Y 轴 -30 度左右这个角度会在地面拉出长阴影物体立体感最强。阴影选项里Shadow Type选 Soft ShadowsStrength保持 0.9 左右不要拉满否则阴影会死黑。第二步是补漫反射。一个方向光会让背光面全黑更像夜晚而不是白天。在场景反方向加一个Directional Light当作天光强度设成 0.3 到 0.5颜色偏淡蓝或淡紫Shadow Type设No Shadows。这层补光的存在感很弱但能保住暗部细节。这个补光在烘焙时要开着否则完全体烘焙后暗部全是黑的。第三步是选择烘焙还是实时光照。Unity2021 的Window - Rendering - Lighting窗口里如果选Mixed Lighting静态物体可以烘焙出高精度的阴影动态角色保留实时阴影。我建议先尝试这个模式。具体步骤所有地形、树、建筑、石头的Static勾选把灯光 Mode 设为Mixed关闭窗口里的Auto Generate手动点Generate Lightning。烘焙完成后光照贴图会替代实时阴影运行时有明显的性能提升。光照贴图的常用参数Lightmapper选Progressive GPU如果你的显卡是近五年产出的Direct Samples和Indirect Samples默认即可关键是把Backface Tolerance调低到 0。如果场景出现大面积漏光大部分原因是模型不是封闭体给墙体底部加一个平面MeshCollider漏光现象会显著减少。这一部分特别看耐心多试几次烘焙你是不会亏的。4. 把散步变成漫游动画、交互与碰撞的整合4.1 角色动画状态机一个 BlendTree 搞定走路和跑步第三人称漫游的角色动画不需要炫技因为焦点在“漫游”场景。一个功能完整的 Locomotion 状态机只需要一个BlendTree结合一个 speed 参数在 0 和 1 之间混合 Idle、Walk、Run 三个动作剪辑。创建步骤导入角色模型在Models文件夹选中角色进Animation页签设置好 Rig 的 Animation Type 为 Humanoid。然后在 Characters 目录下创建一个Animator Controller双击打开后右键创建Blend Tree双击进入这个树。树的参数表这样配Idle 动作Motion是Idle动画Threshold设为 0Walk 动作Motion是Walk动画Threshold设为 0.6Run 动作Motion是Run动画Threshold设为 1最后在运动脚本里把实际速度映射成参数。代码改动很小Animator animator; float speedParameter; void Update() { float currentSpeed new Vector3(controller.velocity.x, 0f, controller.velocity.z).magnitude; float targetSpeed currentSpeed / 4f; // 4 对应 moveSpeed speedParameter Mathf.Lerp(speedParameter, targetSpeed, Time.deltaTime * 6f); animator.SetFloat(speed, speedParameter); }这段逻辑的节奏是controller.velocity已经包含了重力所以一定要单独提取水平分量的速度/ 4f是为了把 4 米每秒对应成参数 1让 blend 阈值能对上。Lerp是给动画一个过渡缓冲否则参数跳变时角色会从走瞬间切到跑。动画不出这个动作先检查 Animator Controller 引用是否挂在了角色模型的根骨骼上。很多人把 Animator 组件挂在角色的空物体上动画能播但角色位置与动画偏移。正确做法是 Animator 挂在带 SkinnedMeshRenderer 的模型节点不要和 CharacterController 挂在同一个根节点。4.2 场景碰撞MeshCollider 的正确打开方式场景里一堆精美场景模型如果角色走过去直接穿模再好看的画面也白费。碰撞体方案优先级是这样排的地形自带碰撞石头、断墙、平地用BoxCollider或CapsuleCollider形状复杂且需要精确碰撞的古树、雕像用MeshCollider但一定要等 XML 注释。原因很简单MeshCollider 的Convex凸体选项只有勾选 Convex 才能参与物理碰撞但凸体要求网格必须是凸的。你对一棵树勾 Convex树的树冠部分会被暴力压缩成一个凸包角色会被空气墙挡住。不勾 ConvexMeshCollider 只能做静态碰撞动态物体穿过去。正确做法是树和复杂装饰物用若干个球形碰撞体围柱形包裹树冠不需要碰撞角色碰到树干不会穿透就够了。碰撞体的一个细节坑MeshCollider 属于静态碰撞它不能挂在带刚体的动态物体上。如果你的场景模型只要有群铺在地板上手动摆放就全部设为Static不要让它们的 Transform 在运行时报 Cody 移动。否则MeshCollider会一直报non-convex MeshCollider with non-kinematic Rigidbody的错误日志。4.3 触发器小事件让漫游不只是走路期末作品要体现“交互维度”在漫游路线上加两三个触发事件很有必要。最常见的是触发对话、开门、播一段过场。我用过一个很轻量的方案在特定位置放一个TriggerZone玩家进入后播放一个动画和一段音频让场景“活”起来。using UnityEngine; public class StoryTrigger : MonoBehaviour { public GameObject door; public AudioClip openSound; private bool triggered false; void OnTriggerEnter(Collider other) { if (!triggered other.CompareTag(Player)) { triggered true; door.GetComponentAnimator().SetTrigger(Open); AudioSource.PlayClipAtPoint(openSound, transform.position); } } }这个脚本的要点triggered布尔锁保证触发只发生一次CompareTag判断是否是玩家避免敌人或杂物触发AudioSource.PlayClipAtPoint是临时播放不需要在场景里预制 AudioSource。触发器区域用BoxCollider设成Is Trigger尺寸在漫游路径宽度的一半不要太大会让玩家还没靠近就提前触发。5. 避坑手册Unity2021 第三人称场景的六个常见问题5.1 角色从坡顶滑下来或者卡在台阶边现象上坡时角色速度很慢或者完全推不动停在坡沿下坡时角色突然加速滑落。原因CharacterController 的Slope Limit默认 45 度。坡度超过这个值控制器会认为那是墙不让你走。下坡加速则是Step Offset太小角色的小腿没有跨过台阶的能力时物理引擎就直接降速。解决把Slope Limit加到 60 度Step Offset调到 0.3 到 0.5 米。这能解决绝大多数地形台阶问题。如果是美术精心做的台阶模型可以故意把 Step Offset 调大让角色“自动踩上去”。5.2 镜头穿墙或镜头怼到角色脸上现象在狭窄通道里FreeLook 相机穿过墙壁画面一半是墙体角色贴墙后镜头被压到角色正面 10 厘米处。原因Cinemachine FreeLook 的Camera Collider参数没调。它虽然自带防遮挡但默认的Radius太短墙壁太薄的话判定容易失败。解决选中 FreeLook 相机找到Body一节里的Camera Collider把Radius从 0.1 加到 0.3 以上把Collide Against只勾选场景的Ignore Raycast层。注意把墙和地形的 Layer 设置成Default否则 collider 连地形都检测不到。5.3 烘焙后场景全黑阴影死黑一片现象点完 Generate Lighting场景变成一团黑只有角色周围亮一点。原因光照贴图烘焙时场景的 Ambient Occlusion 和间接光强度设得太低。默认的AO强度是 0 到 1但你真的调到 1阴影里就完全没细节了。另一个原因是方向光Intensity设得太低低于 0.5 时烘焙光照几乎全黑。解决为烘焙准备三个阶段方向光强度至少 1.0Lighting 窗口里Environment Lighting - Ambient Intensity设为 1Lightmapping Settings - Ambient Occlusion勾选后Indirect Contributions保持默认Direct Contributions调成 0.6。这三项配合后烘焙出来的阴影是深灰色而不是死黑。5.4 模型加载后是紫红色现象从网上下载的场景模型拖进场景整个模型变成亮紫色。原因材质 Shader 不兼容。项目用了 URP模型 Shader 是 Built-in StandardCRP 在 2021 下不支持直接映射到 URP/Lit。解决要么按前文说的回退到内置渲染管线要么在 URP 下挨个换 Shader。一个省事的中间方案用Window - Rendering - Render Pipeline Converter选Built-in to URP然后勾选Material Upgrade批量把材质升级。注意升级后再看贴图里的Normal Map是否丢失URP 升级经常把法线贴图弄丢。5.5 动画和移动方向不一致现象角色模型向前走动画却在原地踩四五个步或角色转向有个明显的“闪腰”动作。原因角色模型在导入时的朝向前方forward没校正。Unity 的内置Humanoid期望模型面向 Z 轴正方向如果你的模型是面向 X 轴建模它的 Animator 会把 90 度偏转算进去旋转时就会先转 90 度让你看到侧面。解决选中角色模型进Models页签里的Rig在Avatar Definition用Humanoid然后改Model Importer的Rotation把X、Y、Z的三轴偏移调好让模型在预览里正对 Z 正方向。这个需要每个模型单独检查建议所有角色模型统一在导入器里校正到正前方向不要在设计游戏中手动补。5.6 角色掉出地图现象角色走着走着直接穿过地形站在地形下方镜头拍出一个剖面视角。原因地形 Collider 没开启或者地形高度图生成时有问题。地形默认带TerrainCollider但如果你是从外部导入的.obj模型它的碰撞体可能没有生成。解决针对手工导入的模型进入编辑器检查 Inspector 里是否有MeshCollider组件。如果没有手动添加并勾选Convex地形模型一般是一个整体大网格勾选 Convex 会得到正确的凹陷避让效果。不推荐用地形替代外部模型地形的 Collider 在复杂交叉面上经常出现漏缝。6. 期末展示前花两小时做的三件事性能、视角与演示动线第一件给每个大模型挂 LOD Group。Unity2021 的LOD Group支持在场景里右键添加但手动给每个石头、树挂一个太累。更高效的办法是选中所有同类模型在Model Importer的LOD Group页签里生成 3 级 LOD100%、60%、20%。运行时角色远离模型引擎自动切换低模帧率立刻上来。期末演示最怕画面卡顿卡顿一两次评审对“精美”的判断会直接降档。第二件做一次遮挡剔除和遮挡区域烘焙。在Windows - Rendering - Occlusion Culling里把场景中静态物体的Static勾选后手动给主要建筑和地形生成Occlusion Areas。然后在 Game 视图里跑全路线可以看到渲染SetPass calls掉一半。这一步不需要写代码只需要勾选和点按钮但收益非常明显。第三件录制一段有动线的演示路径。我的习惯是在游戏编辑器中用Time.timeScale 0暂停运行手动调整 Cinemachine FreeLook 的角度找到两个能展示场景全景的角度然后用快捷键CtrlShiftF10打开 Game View 面板播放一段角色自动沿导航路径行走的NavMeshAgent路径。设置方法给地面加 NavMeshSurface角色加 NavMeshAgent指定一个终点坐标。这样在答辩现场角色会自动走完全程你只需要在旁边拖动视角展示场景细节。这段自动漫游的路径能在导播演示时极大提升“场景模型”的观赏性。做这个项目的完整体验总结起来就一句话人物和场景的配合、碰撞和相机的配合才是第三人称漫游真正的门槛。我每做一个期末场景都会在提交前拿第三人称视角完整跑一遍动线看着看着就会发现哪面墙反了、哪个树挡住视线了。这个习惯帮我避免过至少三次在评审现场翻车。希望这篇笔记能帮你在 Unity2021 里少走这几段弯路顺利交出你自己的精美场景作品。本文还有配套的精品资源点击获取