ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

基于Unity的瓯绣虚拟展馆:3D建模、C#交互与性能优化

基于Unity的瓯绣虚拟展馆:3D建模、C#交互与性能优化 1. 从一块绣片到可漫游的数字空间这个项目到底在做什么瓯绣是温州地区流传下来的传统刺绣工艺针法细密、配色雅致一幅好的绣片拿在手里光线扫过丝线会有明显的明暗转折这种质感照片很难拍出来实物展柜隔着玻璃更看不真切。我做的这个项目就是用 Unity 引擎配合 3D 建模和 C# 脚本搭一个可以在里面自由走动、近距离端详展品、点击查看讲解的虚拟展馆。用户戴上耳机、握着鼠标或者在手机上滑动屏幕就能像逛真实展厅一样从大门走到展墙前凑近看一幅《百鸟图》的羽毛是怎么用套针一层层叠出来的。说清楚它是什么之后还得说清楚它解决了什么。传统实物展馆有几个绕不开的限制展品怕光怕潮长期陈列对绣品损伤大所以灯光必须压得很暗观众反而看不清针脚换展周期长一次布展动辄几周场地固定外地观众想看只能专程跑一趟。虚拟展馆把这些限制反过来变成优势——光照可以随便打我可以给每幅绣品单独配一盏补光灯把丝线的高光打出来展品数据放在配置表里改一行字就能换展打包出来的程序放到任意一台机器上都能跑手机也能装。这个内容适合谁看如果你正在做文化遗产数字化、虚拟展厅、VR 看房这类需要空间漫游 展品交互的项目这篇记录基本可以直接抄作业如果你是 Unity 新手想找一个有完整业务闭环的练手项目瓯绣展馆这种规模十几个展区、几十件展品刚好合适不会大到劝退也不会小到没东西可写如果你只关心 C# 脚本层面的事件系统、数据驱动设计第四部分可以直接跳过去看。我前后花了大概两个月中间返工了三次踩过的坑主要集中在资产规范和性能上这些后面会一个个说清楚。1.1 三条技术路线我为什么最后选了 Unity做虚拟展馆摆在面前的路其实有三条我最初是冲着网页方案去的因为打开浏览器就能看这件事对传播太友好了。实际跑下来才发现没那么简单。技术路线开发效率画面表现分发难度移动端表现我的结论Three.js / WebGL 自研低交互要手写中等PBR 支持有限最低一个链接中低端机卡顿明显适合轻量展示Unity 导出 WebGL中复用编辑器好光照材质完整中包体大加载慢发热、内存吃紧适合桌面浏览器Unity 原生打包PC/安卓高一次开发多端最好可上高质量光照中需下载安装旗舰机流畅最终选它我最终选的是 Unity 原生打包为主、WebGL 版本作为轻量入口的双轨方案。理由很实在瓯绣的核心看点是丝线的质感和针法的层次这个东西对光照和材质精度要求高Unity 的 PBR基于物理的渲染管线配合烘焙光照能把丝绸那种半哑光带方向性高光的感觉做出来网页端在低端设备上很难稳定跑到这个效果。而且 C# 的生态成熟数据配置、事件系统、异步加载这些都有现成轮子不用自己造。代价也得认原生包体起步就是几百兆用户得下载。我的处理是把贴图压缩和资源分包做扎实主包控制在 300MB 以内其余展区资源按需下载第一屏能在 10 秒内进得去。1.2 系统功能模块怎么切分一个能跑起来的展馆拆开看其实是六个互不干扰的模块我用一张清单把它列清楚后面每一部分都会展开资源加载模块负责场景、贴图、音频、配置表的异步加载和内存释放是性能的地基。漫游控制模块第一人称自由行走 固定机位轨道漫游两套控制器切换由 UI 按钮触发。展品交互模块射线检测选中展品弹出信息面板支持旋转、缩放、局部高亮。导览解说模块预设参观路径相机沿样条曲线移动配合语音讲解。UI 与适配模块分辨率自适应、字体、多语言预留。数据配置模块所有展品信息走 ScriptableObject策划改内容不用碰代码。这样切的目的是让每个人只关心自己那一层。比如美术只管往资源目录里丢模型命名规范对了就能自动挂载文案只管改配置表里的文本字段改完重新打包即可生效。模块之间通过事件总线通信互不直接引用后期想加一个线上答题或者收藏夹功能挂一个新的监听者就行。2. 瓯绣资产从实物到 3D 的完整生产链这是整个项目最耗时间、也最能体现质量差距的部分。虚拟展馆好不好看八成取决于资产做得好不好跟引擎关系不大。瓯绣的资产和普通道具不一样它的核心信息全在表面丝线的走向、针脚的疏密、颜色的过渡、绣面的起伏。如果只拿一张照片贴到一个平面上凑近一看就是一张画完全没有立体感那这个虚拟展馆就白做了。我的生产链是这样走的实物高清采集 → 纹样矢量化与修图 → 建模与拓扑 → 展平 UV 与贴图烘焙 → 材质参数调校 → 导入引擎做规范检查。整套流程走下来一幅中等复杂度的绣片大概要 6 到 8 个小时其中一半时间花在修图和烘焙上。2.1 纹样采集与矢量化处理采集环节我会用两种方式配合。整体画面用高分辨率翻拍光源用两侧 45 度柔光箱避免正打导致高光溢出。局部细节用微距镜头分块拍尤其是针脚走向复杂的地方比如鱼鳞、羽毛、花瓣边缘这些地方后期建模要参考。翻拍时一定放色卡不然后期校色没有基准蓝色绣线很容易偏成紫。矢量化不是为了做矢量图而是为了提取轮廓。我把翻拍图丢进图像处理工具做边缘检测把绣片的整体外形、内部分区比如花瓣和花蕊的边界转成路径导出后在建模软件里当底图参考。这样做的好处是模型轮廓能严格贴合真实绣片不会出现绣片是圆的、模型是椭圆的这种尴尬。注意翻拍时相机的白平衡一定要手动锁定别用自动。自动白平衡在不同光源下会漂移同一批图色调不一致后期统一调色会非常痛苦。纹理贴图方面我最终用的是高清翻拍图 手工修补的组合。翻拍图直接做基础色贴图但绣品通常有布面褶皱、反光不均、边缘磨损这些要手工修平否则烘焙进材质里会变成脏斑。修图的时候保留适度的布料纹理完全磨平反而假。2.2 建模从高模到低模的烘焙流程瓯绣展品的模型分两类处理方式完全不同。第一类是平面绣片类比如挂屏、绣画。这类东西真实形态是一块布但布不是完全平的它有轻微的起伏和边缘卷曲。我的做法是用细分曲面做一个带轻微凹凸的薄板边缘根据实物照片修出自然的弧度和磨损感。高模大概 5 万面用来烘焙法线低模拓扑到 800 到 1500 面保证在展墙前贴近看也不会露出多边形棱角。第二类是立体绣品和绣具比如绣球、绣鞋、绣绷、针线篓。这类要完整建出体积高模 20 万面左右低模压到 3000 到 5000 面。绣绷这种有细长杆件的杆件部分单独拆开避免和主体挤在一个网格里导致拓扑困难。烘焙是关键一步。我在 Blender 里把高模和低模叠好用 Cycles 烘焙法线贴图和环境光遮蔽AO贴图分辨率 2048×2048 起步重点展品上到 4096。这里有个细节瓯绣表面的起伏非常浅法线强度如果按默认设置出来的效果会过分夸张像浮雕一样。我把法线强度调到 0.4 到 0.6 之间试了好几次才找到既有立体感又不假的程度。资产类型高模面数低模面数贴图分辨率法线强度参考平面绣片约 5 万800–150020480.4–0.5立体绣品约 20 万3000–500020480.5–0.6绣具小件约 8 万1500–250010240.5展馆建筑构件约 10 万2000–400020480.32.3 绣线光泽的材质参数怎么调这是最能拉开质感差距的一环。丝绸的光学特性是各向异性高光也就是说高光的形状会随着丝线方向拉伸而不是一个圆点。Unity 的标准着色器不支持各向异性我用了两种替代方案一是用URP 的 Lit 着色器配合高光滑面贴图把丝线的方向信息编码进高光贴图强行做出方向性高光。这个方案兼容性好缺点是效果有限需要靠光照配合。二是自定义着色器用切线空间做各向异性计算效果最好但开发成本高我只在几件重点展品上用了。基础参数上我把金属度统一设为 0因为丝绸不是金属光滑度Smoothness控制在 0.35 到 0.55 之间太低没有丝光太高就变成塑料了。这个值我是拿实物在同样光照下对比着调的第一次设了 0.8渲染出来整幅绣片跟镀了膜一样惨不忍睹。提示调材质别在纯色背景里调。把模型放到最终场景的实际光照环境下看尤其是带方向光的展区。同一个材质参数在不同的环境光下观感差别很大。2.4 资产命名与导入规范资产规范这件事前期偷懒后期加倍还。我第一版没定规范美术交上来的文件叫新建文件夹 (2)/final_final.fbx这种脚本按名字找资源全找不到返工了整整一周。后来定了强制规范模型MOD_展区编号_展品编号_名称例如MOD_A01_003_BainiaoTu贴图TEX_展品编号_类型类型用 BaseColor / Normal / Mask 区分配置表CFG_展区编号一张展区一个文件导入设置也统一了贴图按平台压缩桌面端 BC7安卓端 ASTC关闭 Read/Write Enabled 省内存模型关闭自动生成的碰撞体改用自定义简化碰撞。这些设置我写了一份导入预设Preset美术直接套用避免逐个手改。3. 展馆场景搭建与漫游控制的落地细节场景搭建这部分很多人以为就是摆模型实际做起来坑不少。展馆是一种特殊的空间它有明确的参观动线有大量重复的墙面构件有严格的光照需求还要保证帧率稳定。我按结构先行、光照其次、交互最后的顺序做每一步都有验证节点不然后期改结构会连带推翻光照和碰撞。3.1 场景组织与光照烘焙策略展馆结构我拆成三层外壳层地面、墙体、天花、固定立柱、陈设层展柜、展墙、屏风、灯具模型、展品层所有绣品和绣具。三层分别放在不同的父节点下各自用静态标记区分。这样做是为了烘焙光照时能精细控制哪些物体参与。光照上我走了弯路。第一版用了全实时光照加实时阴影画面确实漂亮但高端机也跑不满 40 帧因为展馆里有十几盏灯实时阴影的开销直接爆炸。后来改成混合方案主光方向光模拟天窗进来的自然光保留实时阴影但降低阴影距离展柜内的射灯全部改成烘焙光照用光照贴图Lightmap烘死。烘焙分辨率我设的是每单位 40 到 60 texel重点展区上到 80。烘焙的时候有个参数一定要盯光照贴图缩放Scale In Lightmap。默认值经常不合适大墙面会给太多 texel 浪费小展品又给太少出现噪点。我一般是场景整体烘一次看效果然后逐个物体调缩放值重点物体加大大平板减小。注意烘焙前一定要把场景里所有需要烘的物体标记为 Static否则它不会进烘焙。我第一版漏标记了三面展墙烘出来的墙上全是漏光的黑斑查了半天才发现是这个问题。3.2 第一人称与轨道双模式漫游实现漫游我用的是CharacterController组件做第一人称行走配合一个相机子物体。为什么不直接用刚体加力因为展馆里有很多窄门、台阶、展柜边缘用物理移动容易被卡住或者被弹开CharacterController的Move方法可以精确控制滑动踩台阶也更稳。关键的移动脚本大致长这样using UnityEngine; [RequireComponent(typeof(CharacterController))] public class FirstPersonWalker : MonoBehaviour { public float walkSpeed 2.5f; public float runSpeed 5.0f; public float gravity -9.81f; public float mouseSensitivity 2.0f; public Transform cameraPivot; private CharacterController controller; private Vector3 velocity; private float pitch 0f; void Awake() controller GetComponentCharacterController(); void Update() { // 视角旋转 float mx Input.GetAxis(Mouse X) * mouseSensitivity; float my Input.GetAxis(Mouse Y) * mouseSensitivity; transform.Rotate(0f, mx, 0f); pitch Mathf.Clamp(pitch - my, -80f, 80f); cameraPivot.localEulerAngles new Vector3(pitch, 0f, 0f); // 位移 float h Input.GetAxis(Horizontal); float v Input.GetAxis(Vertical); float speed Input.GetKey(KeyCode.LeftShift) ? runSpeed : walkSpeed; Vector3 move transform.right * h transform.forward * v; controller.Move(move * speed * Time.deltaTime); // 重力贴地时给一个小的向下保持力防止漂浮 if (controller.isGrounded velocity.y 0f) velocity.y -2f; velocity.y gravity * Time.deltaTime; controller.Move(velocity * Time.deltaTime); } }速度值的设定有讲究。真实展馆里人正常步速大概 1.2 米每秒但游戏里如果按这个速度做用户会觉得像在爬。我实测下来 2.5 米每秒是逛展的舒适值按住 Shift 加速到 5 米每秒用于快速穿过过渡走廊。移动端再加一个虚拟摇杆速度降到 2.0因为触屏操控本身就有抖动。轨道漫游模式是为导览设计的相机沿一条Spline样条曲线移动曲线节点在场景里用空物体摆好。相机朝向用LookAt锁定展品到点停留 5 秒播放讲解然后继续。这个模式特别适合做一键参观用户什么都不用管跟着镜头走一遍就能看懂整个展馆的叙事逻辑。3.3 碰撞体与包围盒的实际使用碰撞体是虚拟展馆里最容易被忽视、出问题又最难查的一环。我的原则是视觉模型和碰撞体分离。展品的显示模型可能几千面但碰撞体用一个简单的盒体展柜的碰撞体用几个长方体拼出来不用网格碰撞体。这里就涉及一个概念Renderer的包围盒。Unity 里每个渲染器都有一个bounds属性描述这个物体在世界空间中的轴对齐包围盒剔除、射线检测、可见性判断都会用到它。我做展品选中时踩过一个坑早期我用渲染器的包围盒来判断鼠标是否悬停在展品上结果发现一件细长的绣轴鼠标离它还有一段距离就触发了高亮原因是这个模型的包围盒把轴两端的装饰件也算进去了盒子比实际物体大一圈。解决办法是给每件交互展品单独挂一个BoxCollider尺寸按主体手动调射线检测只认碰撞体不认渲染器包围盒。同时把所有展品的碰撞体放在独立的层Layer射线只检测这个层效率高也不会误触墙面。// 只对展品层做射线检测 int exhibitLayer LayerMask.GetMask(Exhibit); Ray ray Camera.main.ScreenPointToRay(Input.mousePosition); if (Physics.Raycast(ray, out RaycastHit hit, 8f, exhibitLayer)) { var exhibit hit.collider.GetComponentExhibitItem(); if (exhibit ! null) hoverPanel.Show(exhibit.DisplayName); }检测距离我限制在 8 米因为再远用户也看不清展品细节弹面板反而干扰。这个距离是按展馆实际尺寸定的我们的展墙离参观通道大概 3 到 5 米8 米留了余量。3.4 展馆动线与参观节奏设计这点是我做完第一版被人吐槽后才重视的。展馆不是越大越好是节奏要对。我最初把所有展品均匀分布在一条直线上用户走进去五分钟就腻了因为没有变化。改版后我按起承转合来排布入口区是一幅大型迎宾绣屏建立第一印象第一展区讲瓯绣的历史和工具节奏舒缓第二展区是针法展示用可旋转的局部放大模型互动性强节奏加快第三展区是精品陈列灯光暗下来用射灯聚焦单件展品节奏重新慢下来出口区设一个互动绣台用户可以在屏幕上模拟挑针作为收尾。每个展区之间用一段过渡走廊隔开走廊墙上放文字和图片介绍既做了知识补充也给了用户视觉休息的间隙。这个设计思路其实来自实体博物馆的策展逻辑直接搬到虚拟空间里一样成立。4. C# 脚本系统数据驱动与交互事件的设计脚本层面我给自己的要求是策划改内容不碰代码。做到这一点核心是把所有可变内容外置到配置资产里代码只负责读配置、驱动表现。这样做的直接好处是展品从 20 件增加到 60 件我一行代码都不用改只是多填几张表。4.1 用 ScriptableObject 管理展品数据每件展品都对应一个ScriptableObject资产字段包括名称、年代、工艺说明、音频讲解、缩略图、模型引用等。用它的好处是可以在编辑器里可视化编辑支持引用拖拽打包时也能被正确序列化。using UnityEngine; [CreateAssetMenu(fileName ExhibitData, menuName 瓯绣展馆/展品数据)] public class ExhibitData : ScriptableObject { [Header(基础信息)] public string exhibitId; // 唯一编号用于存档和埋点 public string displayName; public string dynasty; public string craftDescription; // 工艺说明支持富文本 [Header(资源引用)] public GameObject modelPrefab; public Sprite thumbnail; public AudioClip narration; [Header(展示参数)] public Vector3 spawnRotation; public float modelScale 1f; public bool allowRotate true; public bool allowZoom false; }这里有个细节值得说exhibitId我用的是展区号 三位序号的格式比如A01003。这个编号在整个项目里保证唯一用于存档记录用户看过哪些展品、用于数据统计、也用于资源命名。编号生成我写了个编辑器小工具自动递增避免手工填错导致重复。4.2 交互事件与信息面板交互的核心是一个轻量的事件总线。展品被点击时发一个事件信息面板、音效系统、埋点系统各自监听互相不知道对方存在。这样后期加功能不用改已有代码。using System; using UnityEngine; public static class EventBus { public static event ActionExhibitData OnExhibitSelected; public static event Action OnPanelClosed; public static void SelectExhibit(ExhibitData data) OnExhibitSelected?.Invoke(data); public static void ClosePanel() OnPanelClosed?.Invoke(); }面板弹出的时候要注意几点。第一弹面板的同时要锁住漫游输入否则用户一边看说明一边还在往前走直接穿墙。第二面板要有一个淡入动画0.2 秒左右硬切会显得很生硬。第三移动端面板要占满屏幕桌面端占右侧三分之一这个差异通过一个LayoutGroup加条件判断来处理。提示事件总线用静态事件要注意反注册。如果监听的物体被销毁了但没取消订阅下次事件触发会报空引用或者更隐蔽的内存泄漏。我在OnEnable订阅、OnDisable取消订阅形成固定习惯。4.3 异步加载与资源释放展馆的资源量大必须异步加载。我用的是 Unity 的Addressables系统把每个展区打成一个资源组用户走到展区入口时才加载对应组离开一定距离后卸载。这样首屏加载时间从原来的 40 秒压到 8 秒左右。加载策略上有个取舍是按展区整组加载还是按单件展品加载整组加载速度快、逻辑简单但内存占用高单件加载省内存但用户快速移动时会频繁触发加载出现卡顿。我最终取了个折中以展区为单位预加载展区内的高精度模型再按距离做细节层级LOD切换。卸载时机也很关键。不能用户刚离开就卸载因为人常常会来回走。我设了一个 30 秒的延迟卸载配合场景内最多保留两个展区的资源内存峰值能稳定控制在 1.5GB 以内。加载策略首屏时间内存峰值移动中卡顿适用场景全部预加载40s3GB无小场景按展区加载8s1.5GB偶发本项目采用按单件加载5s800MB频繁极大场景4.4 导览相机与时间轴控制导览模式我用的是 Unity 的Timeline配合Cinemachine虚拟相机。Cinemachine的好处是可以定义多条相机轨道用优先级切换还自带平滑和噪声效果做手持晃动感很方便。具体做法是在Timeline里排好每个镜头的时长、目标展品、讲解音频起止点相机轨道用Dolly Track沿着参观动线铺。用户点击开始导览后Timeline播放期间可以随时点击退出打断。打断的时候注意要把玩家控制器重新启用并且把相机从虚拟相机切回主相机不然会出现两个相机打架、画面闪烁的问题。讲解音频和镜头时长要对齐。我的做法是先录好音频量出每段时长再按这个时长去排Timeline的片段。如果反过来先排镜头再配音很容易出现话没说完镜头就走了或者镜头停着等音频的尴尬。5. 性能优化与实机调试的踩坑记录开发机跑得流畅不代表真机流畅。我是在一台中端安卓机上测的时候才发现问题的帧率掉到 20 出头展品旋转卡顿阴影边缘还出现了明显的锯齿和闪烁。后面花了大概一周做优化把帧率拉回到 55 帧以上中间的过程值得记录下来。5.1 Draw Call 与批处理优化性能瓶颈第一刀砍在 Draw Call 上。第一版场景里每件绣具、每根立柱、每个灯罩都是独立物体Draw Call 峰值到 800 多手机直接跪。优化的思路是合并所有静态的建筑构件墙体、立柱、地面标记 Static让 Unity 自动做静态批处理。大量重复的小物件比如展柜上的标签牌、地面的引导灯用 GPU 实例化一个材质一次绘制。材质数量从 40 多个压到 12 个把能共用的贴图合并成图集用同一张图集的不同区域做不同物体的贴图。优化后 Draw Call 降到 120 左右帧率提升非常明显。这里有个经验先看材质数量再看物体数量。很多时候物体不多但材质碎一样会拉高开销。优化项优化前优化后帧率变化Draw Call82012520 → 42材质数量461242 → 48贴图总量1.8GB620MB48 → 55实时光源数14355 → 585.2 阴影问题的排查与解决阴影是虚拟展馆里很敏感的东西做得好氛围立刻就出来了做不好就是一片脏。我遇到过三种典型问题第一种是阴影边缘闪烁也叫阴影粉刺。原因是阴影偏移Shadow Bias设得太小物体表面自己和自己产生阴影冲突。解决办法是适当提高 Bias或者改用 Normal Bias 配合。我调了两次才找到不闪又能贴地的值。第二种是阴影距离过远导致精度下降。方向光的阴影距离如果设得太大离相机远的地方阴影会糊成一块。我把阴影距离从 150 收到 60超出了就用烘焙阴影补视觉上反而更干净。第三种是移动端高分辨率阴影开销大。我把阴影贴图分辨率从 4096 降到 2048重点区域单独用一个近距离的高质量阴影远距离用低质量整体开销降了四成。注意改阴影参数一定要在真机上看。编辑器里看着没问题的阴影在手机上因为精度和平台差异经常会出现编辑器里看不到的噪点和闪烁。5.3 常见问题速查表整理了一份我实际遇到并解决的问题表按现象、可能原因、解决方向列出来方便快速定位现象可能原因解决方向展品点击无反应射线层设置错误 / 碰撞体缺失检查 LayerMask确认碰撞体存在弹窗后人物继续移动输入未锁定弹窗时禁用控制器并释放光标移动端发热严重实时光源多 / 帧率未限制减少实时光设置目标帧率 60展品边缘有黑边贴图 Alpha 通道问题检查透明通道改用 Alpha 裁剪加载后模型变白材质丢失引用检查 Addressables 打包是否包含材质音频和口型不同步加载延迟预加载音频用加载完成回调触发播放场景切换时闪黑相机切换冲突统一相机管理切换时禁用旧相机存档丢失写入时机不对改为退出时和关键节点双写5.4 帧率与设备适配策略不同设备的性能差距可以到十倍一套参数打天下不现实。我做了一档自动降级机制游戏启动时读一次设备信息按 GPU 型号和内存给一个性能档位高、中、低然后据此调整阴影质量、贴图精度、后处理开关和分辨率缩放。高档位开满中档位关掉屏幕空间环境光遮蔽和抗锯齿改用快速近似抗锯齿低档位把分辨率缩放降到 0.8 并关掉所有后处理。这样同一份包在旗舰机和中端机上都能跑得比较体面。资源包本身只打一份靠运行时参数区分避免维护多套包。6. 发布部署的几种路径和适配要点做完之后总得分发出去不同平台的处理差异挺大这里把几条主要路径说清楚。6.1 桌面端与移动端的打包差异桌面端打包相对简单注意两点一是分辨率适配用户可能用 2K 甚至 4K 屏UI 要用锚点和 Canvas Scaler 做自适应别用绝对坐标二是退出逻辑全屏模式下要有明确的退出按钮和快捷键。移动端要麻烦一些。触摸操作没有悬停状态所以移动端要改成点击选中而不是悬停高亮。虚拟摇杆要处理多点触控防止右手转视角时误触摇杆。另外移动端要处理返回键用户按返回时要能关闭弹窗、退出导览、最后退出应用层层递进。6.2 网页版的取舍网页版我保留了作为点开就能看的入口但只放精简版展品数量减半贴图精度降一档去掉实时阴影光全部烘焙。这样做是为了控制加载体积让用户能在 15 秒内看到第一屏。网页版的价值在于传播不适合当主力体验版本。6.3 与展馆硬件设备的联动可能这个项目后续我还在做一个扩展方向和实体展馆的硬件联动。比如在实体展馆里放一个触摸大屏用户在屏幕上操作虚拟展馆同时通过串口或网络协议控制旁边的一盏实物射灯灯打在真实的绣品上虚拟和现实对应起来参观体验会很特别。技术上串口通信这部分 Unity 原生没有现成支持需要引入第三方库或者用 C# 的System.IO.Ports加上合适的运行时环境。我之前做过类似的传感器数据读取思路是通的Unity 负责渲染和逻辑外部设备通过一个中间层通信中间层把设备状态转成 Unity 能接收的消息。这件事的技术门槛主要在环境配置和数据稳定性上等做出来再单独写一篇。7. 一些做完之后才想明白的事写到最后想把几个月下来最有感触的几点记下来都是踩过坑才明白的。资产规范要第一天就定不要想着先做起来后面再整理。我第一版资产乱成一团后面花在改名和整理上的时间比重新做一遍还多。规范不难难的是坚持执行最好写成一个检查脚本打包前自动跑一遍不合格直接报错。数据一定要外置。凡是内容相关的东西展品名称、说明、年代、音频路径全部放配置表。代码里硬编码字符串是给自己埋雷改一次文案要重新编译打包效率极低。性能优化别等最后做。我一开始想着功能做完再优化结果优化的时候发现很多结构要动牵一发动全身。正确做法是定一个性能预算比如 Draw Call 不超过 150、同屏三角面不超过 80 万开发过程中随手看 Profiler超了就当场处理。多去真机上看多找人试。开发机上的完美效果在真机上可能完全是另一回事。我请了几个完全不懂技术的朋友来试他们找不
返回列表