
大家做Unity AR开发时八成都会碰到同一个问题功能代码网上搜得到但一上真机就各种翻车。拍照录像权限弹窗没反应、模型放置漂移、射线穿透了不该穿透的物体这些问题磨人得很。我这次借一个实际项目来复盘一下把Unity AR中的拍照与录像功能实现、基于射线检测的GLB文件真实世界放置与射线安全保障这套完整链路拆开讲透源码级的细节和真机调试经验都会覆盖到希望能帮正在做类似需求的读者少踩几个坑。这个项目最终交付的是一个AR应用相机画面中实时显示真实世界用户可以对当前画面进行拍照和录像同时支持将一个GLB格式的3D模型通过点击屏幕“放置”到真实环境里模型会吸附在地面或物体表面放置过程中如果射线检测到障碍物或不安全区域系统会主动拦截并提示。整个功能天然适配家装预览、展品展示、工业数字孪生等场景适合有Unity基础、正在做AR交互的开发者参考。1. 整体设计与技术选型1.1 三大核心需求的功能拆解先把这个项目拆成三条业务线来看便于理清开发的先后顺序和依赖关系。第一块是相机拍摄能力。这里不是指Unity里那个渲染用的Camera组件而是调用移动端原生相机硬件实时获取画面流。开发者要做的是在AR场景中叠加一个“快门按钮”和“录像按钮”点击后生成图片或视频文件并且能被系统相册识别。这里面的隐藏需求包括分辨率适配、横竖屏方向修正、文件命名规范、存储权限处理。第二块是GLB模型加载与真实世界放置。GLB是glTF的二进制封装格式优势在于一个文件搞定网格、材质、贴图、动画和Node层级关系非常适合移动端直接加载。用户在屏幕上点一个位置系统通过射线检测找到真实世界中的一个平面或特征点把模型“贴在”那个位置。第三块是射线安全保障。听起来像安全功能其实本质是防止误操作、穿透操作、以及模型嵌入墙体或地面以下。完整说法是发生射线检测后不仅要确定放置点还要检测这个点周围是否“安全”——即没有紧贴的障碍物、没有悬空、没有模型穿透真实物体等情况。这层机制在实际项目里特别重要尤其是AR测量和家具摆放应用射线一旦穿透墙面模型就会出现在墙后面体验非常糟糕。1.2 为什么选GLB而不是FBX或OBJ项目用的是GLB这是一个有明确理由的选型不是随意为之。FBX虽然有损导出时结构更丰富但移动端AR场景中需要运行时加载FBX的解析依赖Assimp等库包体和性能开销都不理想。OBJ则不带UV动画和材质压缩不利于保持真实感。GLB则直接受益于glTF 2.0标准二进制结构紧凑、加载速度快还能保留PBR材质参数比如金属度、粗糙度在AR场景的光照环境下还原度非常高。实际测试中一个包含2万面左右的家具模型FBX格式大约8~12MBGLB格式压缩后能够在3MB左右加载耗时在主流中端安卓机上约为300~500ms完全在可接受范围。另外GLB支持稀疏Accessor和Draco压缩这在数字孪生场景里能进一步减少带宽压力。1.3 整体架构拍摄模块与放置模块解耦架构上我强烈建议把拍照录像模块和模型放置模块解耦理由很直接你未来一定会单独升级其中一个模块。比如说要加滤镜、要加模型动画、要换AR引擎从ARFoundation切到ARCore/ARKit原生如果两个模块耦合在一起改动成本是双倍的。我的分层设计是底层设备能力层。封装相机权限、存储权限、相册写入、外置存储路径管理等系统级能力。中层AR会话层。基于ARFoundation封装会话管理、平面检测回调、射线命中数据。上层业务控制器层。负责拍照录像指令调度以及模型放置、方格网Grid显示、遮挡隐藏等交互反馈。模块之间通过C#事件和委托通信不直接互相持有引用。比如拍照按钮触发的是PhotoCaptureController.Capture()这个命令会由设备能力层去执行原生接口完成后通过事件回传图片保存路径UI层只负责监听事件并显示toast提示。这样每一层都可以单独替换实现不会破坏整体。2. 拍照功能的核心实现细节2.1 相机权限与存储权限的坑AR应用一开始就要面对权限问题。先说结论Android上我强烈建议申请相机权限、存储权限读写一并申请iOS上则需要NSCameraUsageDescription和NSPhotoLibraryAddUsageDescription否则App Store审核会被拒。这里有一个特别容易被新手踩的坑Android 6.0以上和Android 10以上的权限模型不一样。Android 10API 29开始如果targetSdkVersion 29应用默认无法直接读取外部存储需要使用MediaStore或者使用Scoped Storage的模式。很多人在真机上发现拍摄的照片“明明保存了但相册里看不到”就是这个原因。实际处理方式是Android 10以下沿用WRITE_EXTERNAL_STORAGEAndroid 10以上拍照录像写入公共目录时要通过MediaStore插入后再拿Uri路径或者直接写入应用专属外部存储目录再把文件复制到公共目录。代码如下#if UNITY_ANDROID var permission Permission.Camera; if (!Permission.HasUserAuthorizedPermission(permission)) { Permission.RequestUserPermission(permission); return; } #endif需要特别提醒的是权限回调不是即时生效的。调用RequestUserPermission之后不能立刻去打开相机必须等待回调结果这个异步逻辑处理不好就会出现首次点击拍照无反应的问题。正确做法是封装一个PermissionManager专门管理权限请求状态机的流转。2.2 调用原生相机还是ARGB纹理截屏项目里拍照功能有两个路线我分别说一下取舍路线一调用系统原生相机应用。优点是可以直接利用原生的相机UI和照片算法拍出来画质好、有HDR和后处理缺点是用户在AR体验中会被“踢出”应用回来后AR会话会中断需要重新初始化。这种方式在纯App里没问题但在AR场景里基本不可用。路线二对AR背景画面进行实时纹理截取。思路是ARFoundation通过摄像头纹理Camera Image Texture实时渲染背景只要在渲染管线末端对当前画面进行一次像素拷贝就能得到一帧图片。缺点是没有原生相机的降噪和HDR但优点是对AR体验零干扰。项目最终采用的是路线二的增强版截取当帧画面时除了读取背景纹理同时也把已经放置在场景中的AR模型一并渲染到一张离屏RTRender Texture中这样才能拍到“真实世界虚拟模型”合成的照片。单纯只截背景纹理拍出来的照片里就会没有AR模型这个错我很早前犯过写下来提醒大家。核心实现代码大致如下public void CaptureScreenshot() { StartCoroutine(CaptureScreenshotCoroutine()); } private IEnumerator CaptureScreenshotCoroutine() { yield return new WaitForEndOfFrame(); var rt RenderTexture.GetTemporary(Screen.width, Screen.height, 24); camera.targetTexture rt; camera.Render(); RenderTexture.active rt; var screenshot new Texture2D(Screen.width, Screen.height, TextureFormat.RGB24, false); screenshot.ReadPixels(new Rect(0, 0, Screen.width, Screen.height), 0, 0); screenshot.Apply(); camera.targetTexture null; RenderTexture.active null; RenderTexture.ReleaseTemporary(rt); SaveImageToGallery(screenshot); Destroy(screenshot); }这里有个性能隐患WaitForEndOfFrame再camera.Render()相当于对同一帧做了两次渲染。在我实测的设备上小米11、iPhone 13会掉帧5~8ms可接受但不算理想。进一步优化方案是直接利用ARFoundation背景纹理做RT拷贝把虚拟模型单独渲染到同一张RT能省一多半开销。篇幅有限优化细节就不展开了。3. 录像功能与音画同步问题3.1 基于Unity Recorder还是自定义录制录像的实现路线跟拍照不太一样。如果只依赖Unity的帧截取那是在做“视频流编码”需要有视频编码器支持。这里有两个选择方案一Unity Recorder插件。官方出品的录制工具优点是开箱即用能录制Game视图窗口内容并保存为MP4。但它是编辑器工具在移动端运行时使用受限尤其是想要在真机上点击一个按钮就“开始录”和“停止录”并且保存到相册Unity Recorder做不到。方案二iOS/Android原生Camera API同时启动原生录像并叠加AR画面。这个最复杂但也是生产级AR应用该走的路线因为它能同时获得硬件编码能力和原生麦克风录音权限。方案三Unity侧渲染每一帧并实时喂给原生编码器。这种做法的代表是UnityNativeGallery、AVProMovieCapture这类插件。它们在Unity中用Texture数据推给底层编码器视频和音频从麦克风采集流混流输出。项目最终选用的是方案三的变体录制时每一帧从AR背景纹理采集图像将虚拟模型画面通过Graphics.Blit合成再把合成后的GPU像素数据交给底层编码器。这样录音通道走原生麦克风避免Unity侧采集音频延迟和权限问题。3.2 音画不同步的排查记录真机测试中我最头疼的问题是音画不同步录出来的视频画面正常但声音滞后约0.3~0.5秒。排查后发现根因是Unity渲染帧率与音频捕获频率错位。Unity的帧率不恒定尤其是AR场景由于GPU负载高掉帧是很常见的。原生编码器是按音频时间戳和视频时间戳来对轨的一旦视频帧时间戳是“按帧序推算”比如每帧固定33ms而非“按真实时间戳”错位就会出现。解决方式是给每一帧视频数据打上真实的时间戳单位毫秒并且基于Time.realtimeSinceStartup计算而不是基于Time.timeTime.time在暂停时不会走。另外确保底层的音视频同步模式使用相对时间戳不要用绝对时间。long videoTimestamp (long)(Time.realtimeSinceStartup * 1000); // 将该时间戳随GPU纹理指针一起传入底层编码器这个改动虽然只有几行但直接把同步误差从半秒级降到了肉眼不可见。再提一嘴录音权限要单独申请iOS还需拿到麦克风权限描述字符串否则视频文件只有画面没有声音此坑在审核阶段很容易被拒。3.3 录像文件的体积控制与分段策略录像文件尺寸失控是AR应用的另坑。原生相机录一分钟1080P大约150MB这个大小对用户来说非常不友好。可以通过控制两种参数来解决码率和分辨率。实际采用的参数组合是分辨率1440x720720p的2x宽屏变体码率6~8Mbps。在保证画面清晰的前提下一分钟视频体积控制在45~60MB左右。更低码率的画面在马赛克边缘会出现模糊影响AR效果展示不建议再低于6Mbps。分段策略则是应对长时录制AR模型放置过程往往需要讲解可能录到十几分钟。此时应该在代码中设定最大录制时长比如单段5分钟达到上限自动切割并开始下一段。分段的好处还在于单段文件损坏的风险更低后续剪辑或上传也更可控。4. GLB模型加载与真实世界放置4.1 GLB运行时加载的工程化实践GLB在Unity里加载我优先推荐glTFast这个开源库而不是Unity官方推荐但已经有些沉睡的UnityGLTF。glTFast对GLB2.0的支持完善加载速度快材质转换到URPUniversal Render Pipeline管线时效果很好。接入glTFast之后核心接口就是一个异步加载方法var gltf gameObject.AddComponentGltfAsset(); await gltf.Load(url); // 或传入byte[]数组要说加载踩过的坑第一个是材质Shader丢失。默认情况下glTFast会把PBR材质转换成标准着色器但如果你项目用的是URP渲染管线部分版本会转换成Lit/Simple Lit金属度和粗糙度参数在URP下的表现会与原版有差异。解决的方案是手动注入一个MaterialGenerator自定义着色器映射让金属度、法线贴图、自发光等属性一一对应。第二个坑是模型在安卓上出现拉伸或扭曲变形。这个问题多数是因为模型内部的法线数据用的是双精度double格式在部分安卓机型上会被截断成半精度导致。处理方式是把GLB文件在导出时切换为单精度浮点比如Blender导出glTF时把精度调成Float。4.2 射线检测放置模型的工作原理模型能够“放到真实世界”核心是射线检测命中某个平面或特征点并把模型的根节点设置到命中点处。在ARFoundation中的完整流程是监听触摸事件获取屏幕坐标。构建一条从主摄像机出发的射线方向指向屏幕点。进入AR会话的检测层TrackableManager对平面Plane和点云特征点进行命中检测。如果有命中结果取出Pose位置和方向把模型的transform.SetPose。如果没有命中要么忽略要么可以启动平面猜测逻辑。其中射线检测有两个细节非常关键第一个细节是射线命中的判断依据。ARFoundation里有两种射线TrackableType.PlaneWithinInfinity和TrackableType.FeaturePoint。PlaneWithinInfinity会把射线直接落在平面无限延伸的虚拟平面上即使你的点击位置其实位于平面有效范围之外。这会导致一种恶劣现象你明明点了一面墙模型却出现在墙后方的某个“看不见的平面”上。所以线上应用一般都同时检测PlaneWithinPolygon也就是只在平面多边形有效范围内才接受命中。var hitResults new ListARRaycastHit(); if (arRaycastManager.Raycast(screenPos, hitResults, TrackableType.PlaneWithinPolygon | TrackableType.Planes)) { var pose hitResults[0].pose; }第二个细节是模型的落地姿态。直接使用命中点的Pose作为模型transform的position和rotation会导致模型的方向与平面法线方向不匹配。比如一个家具模型它的“前”方向可能与平面法线垂直结果模型横着插入地面。必须调整模型前向轴与平面法线对齐var modelTransform model.transform; modelTransform.position pose.position; modelTransform.rotation Quaternion.LookRotation(pose.rotation * Vector3.forward, pose.up);在此基础上再加一个高度偏移offsetY让模型的底部基座正好贴在地面上这个偏移值可以读模型Mesh的Bounds得到。4.3 放置后的模型范围修正与模型轴心调整很多GLB模型的轴心不在底部中心点有的在几何中心有的甚至在世界原点。如果直接用模型根节点的位置去对齐平面模型会悬浮或者陷进地面。我通常用两步解决第一步在模型加载完成后用GetComponentInChildrenRenderer()获取包围盒计算出模型的中心点bounds.center第二步用中心点与底部的差值做修正即offsetY bounds.min.y - transform.position.y。然后将模型整体再包一层空物体用外层空物体来对齐平面内部模型偏移到合适位置。这层“外包裹的Anchor”的思路也方便后续做旋转、缩放把旋转的中心固定在模型底部中心而不是轴心上用户操作体验会好很多。操作代码示意float modelHeight renderer.bounds.size.y; anchor.transform.position hitPose.position new Vector3(0, modelHeight * 0.5f, 0);如果你希望模型在放置时能紧贴地面这步不能省。5. 射线安全保障机制的设计与实现5.1 为什么要单独做“安全保障”射线检测本身给出的只是一个“命中点”它不是安全信息。所谓安全保障我的定义是在射线命中后对命中点周围的碰撞体、语义标签、物理规则进行综合校验确保模型的放置位置在空间上是合理且物理上不过分违和的。如果不做这层校验会发生什么你把一个体积较大的柜子模型放到一个很小的桌面上桌面虽然被射线命中了但柜子的边缘悬空视觉上像漂浮的轻功。更糟的情况是柜子中心点刚好在墙面上结果整个柜子一半嵌入墙里用户从侧面看会直接穿透看到后面非常出戏。此外AR射线检测本身还有一种风险射线可能会穿透某些不应该被穿透的物体比如靠近真实用户的障碍物。这样模型就会被放置到障碍物后面这既不符合交互预期还存在用户忽略危险物体的安全隐患。5.2 安全校验三维度碰撞、遮挡、平面完整度我的安全检测机制包含三层第一层碰撞检测。在模型放置前用Physics.OverlapSphere检测模型目标位置周围是否存在真实物体的碰撞体。如果是桌面Collider体积较小模型体积大于桌面支撑范围则放置的时候给出“空间不足”的提示并拒绝放置或者执行缩放适配。var colliders Physics.OverlapSphere(placePosition, modelRadius, layerMask); if (colliders.Length 0) { // 检测是否命中障碍物提示空间不足 }第二层遮挡检测。有一种危险场景是射线命中了远处的地面但被中间的柱子挡住。Unity的AR射线通常返回的都是最近命中点但如果模型体积较大模型的其他部分可能会被中间的柱子穿模。这时需要额外做一条从模型中心到摄像机的回溯检测确认模型的包围盒是否与场景中的遮挡Collider相交。如果相交就调小模型或提示调整视角。第三层平面完整度检查。如果命中点是某个平面边缘的一小块区域模型的底面面积大于平面面积放置后模型边缘悬空这就是平面完整度不足。简化做法是检查模型底面的四个角点是否都位于命中平面多边形范围内。如果三个角点在外说明平面不够大必须拒绝放置或触发适配缩放。这些校验逻辑建议全部封装在PlacementSafetyGuard这个类里对外只暴露一个bool IsSafeToPlace()的方法。这样可以方便做单元测试和后续的多端适配。5.3 极端情况模型插入墙体与地面以下模型插入地面和墙体是最常见的两大“安全事故”。对于地面插入原因通常是ARFoundation的平面检测使用的是特征点拼合的大平面实际地板的物理表面与检测平面存在毫米级误差当重力让模型下沉时就会出现穿地。独特解法是在模型放置后开启一个常驻的“吸附修正”协程持续检测模型底部与射线命中的平面在Y轴上的差值一旦超过阈值就给模型施加一个位置修正。对于墙体插入处理上要复杂一些。常用的策略是在放置模型后立即对模型周围进行一圈“膨胀射线检测”——以模型中心为圆心每45度发射一条射线总长等于模型半径再乘以1.2倍。如果某个方向射线击中了墙那就认为模型与墙过近自动把模型外移直到检测安全为止。这里需要特别设置Physics.Raycast的LayerMask不能把AR平面的DetectionLayer也当成墙来检测否则模型会一直被外推无法放置。5.4 射线分组与LayerMask配置的实战经验这里提一个高频出错点Layermask用错安全防护形同虚设。AR场景中往往存在多类物体可放置的真实平面、不可穿透的墙体、半透明的玻璃、全息辅助线等。如果统一用一个Layer那么射线会命中错误目标。我的分配建议是Layer 8AR Plane只用于平面识别不参与物理碰撞Layer 9Occluder真实场景中的障碍墙、柱子参与物理碰撞和安全检测Layer 10Virtual Model虚拟模型自身的Collider可相互穿透或碰撞根据需要Layer 11PlacementPlane专门为了放置而生成的透明辅助平面配置好LayerMask之后不安全检测的射线只扫Layer 9和Layer 11其他一律不看。Layer 11的存在意义是当模型已经放置在真实世界时再点击模型表面想去拖拽它射线命中Layer 11的辅助平面而非真实物体拖拽的位移才是顺滑的。Use LayerMask的优先级记为碰撞检测 放置平面 真实背景。int occlusionLayerMask (1 9) | (1 11); if (Physics.Raycast(ray, out hitInfo, 50f, occlusionLayerMask)) { // 安全检查逻辑 }这块配置代码在macOS模拟器中无法完整验证因为模拟器没有真机传感器数据必须连真机测试。建议开发时写一个Debug视图把Layer和关键射线绘制出来排查效率会成倍提升。6. 工具选型解析与渲染管线适配6.1 ARFoundation、ARCore XR Plugin、ARKit XR Plugin的配合关系项目的基础框架我选择的是ARFoundation这是Unity官方跨平台AR抽象层。它支持Android ARCore、iOS ARKit以及部分HoloLens功能。操作ARFoundation时需要同时安装两个插件ARCore XR PluginAndroid端的底层驱动。ARKit XR PluginiOS端的底层驱动。当前推荐使用ARCore 5.x以上版本因为它在平面检测稳定性上有明显提升尤其是弱纹理环境白墙、纯色地板下特征点识别成功率更高。若还需要Face跟踪或者Depth API再按需引入OpenXR或ARCore Depth的扩展。注意ARFoundation、ARCore XR Plugin、ARKit XR Plugin、Unity版本四者之间是有匹配矩阵的。用较新的Unity 2022.3 LTS版本加上ARF 5.1.1是我实测中相对平稳的组合。如果强行把新版ARF装到老版本Unity上轻则编译报错重则运行时原生库崩溃。6.2 URP适配与双面材质问题项目在渲染管线选择上用了Universal Render Pipeline。URP能够统一管理多平台效果也可以在移动端获得更好性能。但与AR结合时URP里有一个坑背景纹理材质球Shader写法不对画面会全黑。ARFoundation在URP下自动使用ARDebugMenu等组件提供的Shader渲染背景如果你要自定义背景材质比如给背景加滤镜就需要针对URP的UnlitShader结构编写。参考写法struct Varyings { float4 positionCS : SV_POSITION; float2 uv : TEXCOORD0; }; Varyings vert(Attributes input) { Varyings output; VertexPositionInputs vertexInput GetVertexPositionInputs(input.positionOS.xyz); output.positionCS vertexInput.positionCS; output.uv input.uv; return output; } half4 frag(Varyings input) : SV_Target { return tex2D(_MainTex, input.uv); }然后要提一个搜索热词里反复出现的“Unity双面材质Shader”。AR场景里模型背面经常会被看到比如你把一个柜子转过来看背面但许多GLB模型默认是单面的背面会直接消失用户看到的是一个“空心”网格这是非常破坏真实感的体验。解决方法是在URP Shader中开启Cull Off把法线翻转逻辑处理好。glTFast的默认材质默认是单面的所以遇到透明或镂空模型时要特别注意我就是在这个问题上调试了一整天最后是自己改写材质生成器才解决。6.3 模型遮挡剔除的必要性AR场景的遮挡剔除Occlusion往往被忽视但它是沉浸感的关键。当真实世界中有一堵墙挡在模型前面AR渲染的模型应该被墙体遮挡而不是浮在墙上。ARFoundation的遮挡有两种实现方式Environment Depth ImageARCore/ARKit通过深度摄像头实时生成环境深度图Unity端Shader采样深度信息把模型被遮挡像素剔除掉。真碰撞体遮挡把真实物体比如手工扫描的Mesh导入为带有遮挡Shader的Collider利用深度缓冲形成遮挡。前者目前仅支持部分设备和平台后者则普适。我最终采用“真碰撞体遮挡AR深度图备用”的组合方案在有深度能力的中高端手机上开启深度遮挡在其他设备上用真实Mesh遮挡。这个方案直接提高了模型放置的安全感你放置的柜子在穿墙时会自动被墙体遮挡而不是出现“透视模型”深度的真实感立刻上升一个台阶。7. 真机调试与常见问题排查7.1 AR功能无法在Editor模拟器中验证这里必须强调AR功能在Unity编辑器中只能验证UI逻辑不能验证真实世界交互。模拟器没有环境光没有6DOF姿态传感器也没有平面检测的有效输入。所有射线检测、安全通行判断、遮拦效果都必须依靠真机调试。实操过程中我的真机调试发布流程是安卓机选择Build App BundleGoogle Play格式或用APK直接安装到测试机。iOS平台必须用Xcode导出工程后再通过Xcode安装到测试机。开启AR Debug Visualization模式可以在屏幕上画出平面检测到的网格线。这个开关对排查“模型放不上”或“模型漂移”极其有效。保持Unity Profiler连接状态尤其要关注“Render Loop”和“Main Thread”的耗时曲线AR掉帧往往来自加载模型或压缩图片主线程卡顿。7.2 常见问题与排查速查表我把这个项目里遇到的高频问题和对应排查方案整理成一张表方便大家现场查阅问题现象可能原因排查与解决拍照保存后相册找不到Android 10未适配Scoped Storage改用MediaStore插入检查存储权限回调时序录像没有声音iOS/Android麦克风权限未配置或拒绝检查Permission设置测试时手动确认麦克风权限是否开启录像声音滞后约0.3sUnity视频帧时间戳未使用实时时间戳以Time.realtimeSinceStartup为基准修正视频帧时间戳模型加载后颜色发灰材质Shader未适配URP或丢失PBR参数自定义MaterialGenerator映射URP Lit参数模型放置后悬浮模型轴心不在底部或包围盒中心计算偏差包裹Anchor层用Bounds.center修正高度偏移模型穿透墙面未对模型四周做安全膨胀检测添加45度方向射线检测检测到墙面时调整外移放置后稍微移动手机模型就抖动平面检测特征点不稳定启用PlaneWithinPolygon检测在真机上重新初始化AR会话射线点了但模型不出现平面未识别或射线类型设置错误开启AR Debug Visualization观察平面网格改用更宽松的TrackableType组合编译iOS时报linker errorUnity版本与ARKit XR Plugin版本不匹配检查版本匹配表清理工程重新导出Xcode工程Android真机闪退原生库缺失或ABI架构不匹配检查ARM64与ARMv7的选择确认GLB模型贴图是否过大7.3 性能优化与内存控制心得AR应用最大的损耗来自于模型加载和渲染管线的开销。模型放得越多DrawCall越高帧率自然下降。几轮测试下来我的优化手段按优先级排序是限制同时渲染的模型数量同一场景建议不超过5~8个活跃模型超出则执行“隐藏最近未交互模型”策略。GLB模型LOD化每个模型准备两个LOD Level远距离显示低模近距离才切换高模。纹理压缩GLB文件内的贴图建议用ASTC格式安卓或PVRTCiOS。若不压缩大多数中端机跑不满30帧。禁用阴影或限制阴影距离阴影是移动端最大的性能杀手之一。在AR场景中我默认关闭实时阴影改用手绘的接触阴影decale。实测数据参考在iPhone 12上开启2个带PBR材质的中模并采用ASTC压缩贴图帧率稳定在60FPS同时渲染6个模型时约40FPS。若不加处理渲染4个模型就会降到30FPS以下所以这块优化不能省。8. 从功能实现到产品落地的一点体会写到最后说几点真实的项目感受。这个项目的核心难点从来都不是“拍照哪个API”“射线怎么发生”而是所有功能叠加在一起时的系统稳定性。拍照传输出错、模型穿墙、音画不同步单独拿出来都能解决但当它们同时出现在一个真机上排查顺序往往是一团乱麻。我的建议是把项目拆成“拍摄能力”“放置能力”“安全保障”三个里程碑每完成一个里程碑就单独拉出来跑至少半天真机。不要急着把所有功能拼装在一起联调否则出问题了根本定位不了是哪层代码的锅。如果后续想继续扩展可以考虑在安全保障里加入语义理解——用AI识别画面中的桌子、墙、玻璃然后让模型自动选择最合适的平面放置。另外对录制保存的视频做一键GIF转换或者3D预览回放也已经在行业里见到不少应用。希望对正在做Unity AR的你有帮助。