十年匠心定制 · 商业建站与技术教学双线并行 咨询热线:400-886-1026 service@lmnt.cn
ARTICLE DETAIL

资讯详情

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

UE4场景采集2D实现地面反射:从RenderTarget到材质全流程解析

UE4场景采集2D实现地面反射:从RenderTarget到材质全流程解析 1. 反射方案那么多为什么偏偏要碰场景采集2D做UE4项目但凡涉及到地面要像镜面一样能倒映出角色和建筑这类需求大家第一反应通常是开屏幕空间反射SSR或者直接放几个反射捕获Reflection Capture。这两个方案确实是干活的主力但碰上特定场景就露怯了。大概一年前我做一个室内展示项目甲方要求一层大厅的抛光大理石地面必须清晰地倒映出吊灯、墙面装饰和走动的人影。当时我先是开了SSR结果发现屏幕边缘的反射会断角度一斜就消失人物稍微离屏反射立马没了上反射捕获出来的倒影糊得像毛玻璃甲方一句看不出这是吊灯直接给我堵死。最后被逼着去研究平时不怎么碰的SceneCapture2D也就是UE4里的场景采集2D。这个工具的思路特别直接在场景里摆一个相机把它的画面渲染到一张纹理上再把这纹理当材质贴图用。用这个思路做反射本质上就是假反射——不是实时算光线的物理反射而是把另一台相机看到的内容贴到表面上。但效果好起来比SSR稳定比Reflection Capture清楚尤其是平面地面、墙面、桌面这一类规则表面的倒影能做到以假乱真的程度。当然代价是性能开销比前两者大得多配置过程也细碎得多。这文章就从零开始把场景采集2D做反射这整条链路里的关键步骤、参数逻辑和踩坑点捋一遍适合已经会用UE4基础材质工作流、但没深入碰过SceneCapture的人看。2. 摆放计算和位置逻辑相机的对称不是你随手拖出来的2.1 为什么相机不能对着镜子拍先说一个最常见的误解。很多人第一次用SceneCapture2D做镜面反射会直接把相机摆在反射面比如地面的正前方镜头正对着地面拍。出来的结果基本是废的——你拍到的是地面材质本身而不是倒影。这里的关键在于场景采集2D本质上是换个视角看世界它模拟的是眼睛在反射面另一侧的镜像位置。也就是说如果你的角色站在地面以上高度180cm的位置那么倒影里的视角就应该在地面以下180cm的位置上下完全对称方向也要跟着翻转这个位置相机才能真正采集到那些需要出现在倒影里的物体吊灯、墙壁、角色全都在这个镜像视角的视锥范围内。这个逻辑等同于照镜子你把手机举到眼前手机摄像头对着镜子拍到的其实是你身后而不是屏幕里的你。想拍出镜子里的你手机得摆在你和镜子中间、背对着镜子拍不对得让镜头的朝向和你看向镜子的方向形成一个对称关系SceneCapture2D的摆放逻辑同理。2.2 精确摆放的两种办法手动镜像和相对偏移在蓝图里手动算镜像位置也不难。最简单的思路拿到反射面的轴心位置把Capture组件的位置相对反射面做镜像。打个比方地面高度Z0角色站的位置Z180。你需要让SceneCapture2D的Root组件位置放在Z-180。方向也做镜像——角色的相机朝向如果是(0, 0, -1)朝下看地面那Capture相机的朝向就应该是(0, 0, 1)朝上看。这样Capture拍到的是地面的下方空间映射回地面材质上时相当于以地面为对称轴翻转了一整个世界。实际项目里我更推荐的做法不手动填死数字而是在蓝图里动态绑一个偏移。做法是放一个场景采集2D再放一个可参考的目标点用来代表反射面的中心然后在EventTick或EventBeginPlay里用简单的向量计算// 伪代码逻辑在蓝图里等同实现 FVector mirroredLocation 2.0f * ReflectPlaneLocation - RealCameraLocation; CaptureComponent-SetWorldLocation(mirroredLocation); // 旋转也需要对称处理本质是把相机的旋转按反射面法线做镜像这种方法在静态漫游项目里很稳但如果项目里有可移动的角色需要实时反射那Capture就得跟着角色位置每帧更新开销会明显变大。多数项目里场景采集2D适合做固定机位反射比如大厅地面、桌面、展示柜玻璃而不是跟着第一人称视角满世界跑。2.3 Near Clip Plane和反射面厚度的关系摆放完位置还有一个特别容易忽略的坑NearClipPlane近裁剪面的默认值。Capture组件如果放在反射面内侧近裁剪面很容易把反射面本身或者地面下的小物件裁进画面导致倒影里出现奇怪的横截面。我的经验是将Near Clip Plane调大比如设成10~20让相机忽略掉贴近裁剪面的杂讯如果做的是薄桌面反射还要注意反射面背后的物体比如桌子下面的椅子腿会不会被采集进来这时候需要通过ShowFlags或者Actor隐藏列表来过滤这在后面专门讲。3. 渲染目标与资源设置给第二视角配好画布再谈效果3.1 RenderTarget的创建和Size选择场景采集2D本身不直接输出画面它需要一张RenderTarget2D作为画布来接收渲染结果。这里的选择直接影响性能和画质。在内容浏览器里右键 - 材质与纹理 - Render Target新建一张RenderTarget2D。名字建议带RT_前缀比如RT_FloorReflection方便后期在材质里找。关键参数是Size X和Size Y。这个值设多少决定了你反射纹理的清晰度。512x512是最低能看的档位勉强能认出轮廓1024x1024是室内地面反射的常用档位如果反射面特别大、或者要表现精细的灯罩轮廓需要上2048x2048。但这不是越大越好RenderTarget的GPU显存占用是Size X * Size Y * 4字节RGBA82048就占了16MB显存而且Capture每一帧渲染的成本也和分辨率直接相关。实际项目里我倾向于动态权衡如果一个小大厅地面1024x512这种矩形比例更合适——地面的反射画面天然是宽扁的形状方形RT浪费了上下的采样空间。还要注意一个细节RT默认的ClearColor也就是没渲染东西时填充的颜色。做反射时建议把这个颜色设为接近地面的暗色而不是默认的灰色这样反射画面中采集不到的边缘部分过渡到地面材质时会自然一些不会出现一条明显的灰边。3.2 TextureRenderTarget2D的格式选择RT的像素格式也值得抠一下。默认的RTF_RGBA8能满足多数反射需求但如果你希望反射里有更平滑的渐变过渡比如大理石地面高光带可以考虑RTF_R16F或RTF_RGBA16F的半浮点格式。半浮点格式在亮部细节保留上更好代价是显存翻倍。做镜面反射这种本身要亮的效果我推荐RTF_RGBA16F后期在材质里调节反射亮度时数据也更友好。3.3 CaptureComponent的TextureTarget绑定在场景里放一个SceneCapture2D Actor后细节面板里找到Texture Target把刚才建好的RT拖进去这一步是让这台相机知道往哪张纸上画画。绑定后你会发现视口里什么都不显示这是正常的——Capture不会像普通相机那样输出到屏幕它输出到RT。想看采集结果可以临时建一个材质把RT作为贴图连到自发光上随便贴到一张平面上看效果方便调试。这里强烈建议在项目设置里打开支持渲染目标相关选项同时确认场景里有所需的光照。注意一点默认情况下场景采集2D的相机不接收半透明物体的完整反射半透明材质在Capture里的表现经常和主相机不一致如果反射面要倒映玻璃或透明罩子这套方案的效果会打折扣必要时得改成不透明渲染。4. 材质端链接把镜像画面正确贴回表面4.1 基础UV连接RT准备好之后在反射材质的BaseColor或Emissive看你的材质路线里连上Texture Sample节点贴图选择RT_FloorReflection。这时候直接连上去的结果一般是变形、错位甚至黑屏的——因为RT的UV坐标系是0~1的方形区域但你的地面可能是几十米长的平面UV拉伸会把图像扯得完全认不出来。正确做法是控制UV的Tile平铺。如果你地面是10米x10米RT是1024x1024希望整个反射图案铺满整个地面那UV的Tiling值要做一个换算把世界空间尺寸映射到0~1的UV区间。但更常用的是通过World Position做映射参考这个方法用WorldPosition节点取出X和Y或者Y和Z取决于地面朝向除以反射面的实际尺寸比如除以1000把厘米变成米量级的比例取小数部分作为UV坐标连到Texture Sample的UVs上。这样地面的倒影就跟着真实地面走不管摄像机怎么动都不会穿帮。4.2 最关键的一步Y轴翻转当你看到倒影是反的或者上下颠倒的恭喜你遇到场景采集2D最常见的坑了。场景采集相机朝上和朝下的画面对应到地面材质时UV的V方向要反一下。原因很简单Capture相机相当于在地面下方朝上看它拍到画面的上对应于真实世界的下直接贴到材质上就会变成倒影上下颠倒。解决办法有两个在材质里对UV做翻转UV.y 1 - UV.y用Append节点把翻转后的V和原来的U组合回去在蓝图里修改CaptureComponent的旋转让相机方向带一个翻转角度但这个方法容易和上面算镜像位置时的角度逻辑打架不如材质里翻转省心。我强烈建议用材质方案因为你可以在材质参数里方便地加一个开关比如反射方向修正想调试就拉一下参数不用重新编译数据。实战中这个翻转判断还要结合地面法线的朝向有些墙面反射需要翻转的是U轴这个看情况调先在材质里把Texture Coordinate的U和V分别做取反选择了测试很快就能确定正确的方向。4.3 反射强度、模糊和颜色混合画面链接成功后你会发现反射太完整了像一面纯镜子完全没有大理石的磨砂质感。实际的地面反射不会是100%清晰它通常混合了地面的本底颜色和高光反射。推荐的材质结构FinalColor BaseColor * (1 - ReflectIntensity) RT_SampleColor * ReflectIntensity * SpecularFactor其中ReflectIntensity是反射强度参数介于0~1SpecularFactor可以用Fresnel节点生成——视线垂直的地方反射弱、掠射角度反射强比如走廊远端的地面反射更强这个效果用Fresnel乘一下出来的地面质感立刻就不一样了和真实的物理直觉完全对得上。反射模糊这里虽然可以在PS里给RT做Blur但在材质里直接做会灵活很多。用纹理坐标偏移多次采样然后取平均是最廉价的办法float3 finalColor 0; for (int i 0; i 5; i) { float scale 0.01 * i; finalColor Texture2DSample(Tex, TexSampler, UV float2(scale, 0)).rgb; finalColor Texture2DSample(Tex, TexSampler, UV - float2(scale, 0)).rgb; } finalColor / 10.0;如果不想写HLSL可以用多个TextureSample加到不同UV偏移再除次数效果接近。这种手段比单纯调RT分辨率再去模糊成本低实时性也更好。4.4 隐藏不需要反射的物体场景采集2D会把范围内所有可见物体都录进去。这时问题就来了如果反射面旁边有个不该出现在倒影里的道具、或者角色自己如果你的Capture设在角色身下角色本身会被拍到导致倒影里出现一个顶在脑袋上的脚底板怎么剔除方案有三个从简单到严格Hidden Actors列表在CaptureComponent细节的Hidden Actors数组里手动把不想反射的Actor拖进去。适合静态摆放且确定不动的道具。Primitive Render Mode把模式从默认渲染所有可见物体改成只渲染指定的Actor列表这样只把你拖进去的物体渲染到RT里。这个方法最精准适合那种只要求倒映特定几件家具的场景性能还更省。自定义深度通道Custom Depth给需要参与反射的物体启用CustomDepth渲染然后在Capture的后期处理里用SceneTexture节点做Mask过滤。这个方法最灵活允许动态添加物体但配置复杂度也最高。如果不在隐藏列表里把反射相机自身所在的地面以下空间处理好你会看到RT画面里地面下方的网格/碰撞体都会出来影响倒影纯净度。所以先把Capture的位置拉高一点让它近裁剪面只覆盖所需空间再配合隐藏列表来做精确控制。5. ShowFlags与视野裁剪别让反射世界泄露天机5.1 ShowFlags全家桶哪些要关、哪些要开CaptureComponent的细节面板里有个ShowFlags选项树这里控制着Capture渲染时是否开启各类渲染特性。很多人不知道这里等于一个独立的小渲染管线开关用好了能大幅优化性能、规避脏画面。做反射时我的常用ShowFlags配置关闭不必要的后期处理PostProcessingBloom、Vignette、MotionBlur这些如果开着反射画面里会叠一层和主视角不同的模糊效果非常怪。Capture的反射应该追求干净准确后期交给主相机统一处理就够了。关闭Fog雾效如果场景有指数高度雾反射画面里也会带一层雾感。有时这层雾会让反射看起来更融合但多数情况下会让倒影发白、变淡建议关掉观察对比。关闭Decals贴花地面上如果没有血迹、污渍类贴花这一项无所谓如果有而你又不想让贴花出现在倒影里就关掉它。一个典型的问题场景地面上有项目中期加的一个禁止通行贴花结果倒影里一清二楚主视角看不到但反射里特别跳戏。关闭Decals是最直接的解法。保持与主相机一致的动态阴影设置如果你关了Capture的动态阴影反射里的物体会浮起来没有落地的实在感如果开着性能翻倍地掉。权衡下来中小型项目里建议保留Capture的动态阴影但关掉高精度阴影贴图把阴影分辨率调低。5.2 视野范围FOV与裁剪Capture相机默认FOV是90度但做地面反射时90度视角拍到的画面范围偏大、边缘变形也明显。实际调的时候建议把FOV降到60~75度之间然后用Near Clip Far Clip去控制采集距离。Far Clip Plane设成多少很讲究。如果设的太大Capture会把场景最远处的天空盒也渲染进去。天空盒这东西放到反射里经常是灾难——RT会显示出一片天光反射面像是开了天窗。我通常把Far Clip限制在反射面周围50米内让Capture只采集主要参与构建倒影的中近景物体。还有一种常见的需求只想让反射出现在玩家附近远处的地面不做反射。这个用材质端距离Fade来控制不依赖Capture的渲染距离。做法是在材质里用WorldPosition算出像素点到角色的距离超过阈值就逐步把ReflectIntensity衰减到0。这样做的好处是Capture一直持续渲染但材质端做了淡出视觉上不会有突然消失的爆闪感。6. 性能瓶颈与优化这么贵的反射到底怎么省着用6.1 Capture的渲染开销为什么这么高场景采集2D等于在场景里多渲染了一次相机视角的画面——几何体多算一遍、光照多算一遍、阴影多算一遍如果你开了的话。如果你主相机跑60帧要花8ms那一台Capture大概会额外吃掉3~5ms这根据不同场景复杂度浮动很大。这就是为什么不能把Capture当作全局反射方案来用它适合的是高档位精品反射面这类局部场景。讲个真实的项目参数对比一个室内大厅主相机跑起来GPU耗时约7ms叠了一个分辨率1024、带动态阴影的SceneCapture2D后GPU耗时跳到11ms多。对于目标30ms帧预算的Demo来说还能扛但如果帧率要求高就得做取舍了。这张表是我在项目里记录的典型数据基于GTX 1660S配置项GPU耗时增量画质感受512x512 RT无阴影约1.2ms能看出轮廓细节一般1024x1024 RT无阴影约2.6ms细节清楚适合地面1024x1024 RT开阴影约4.0ms倒影更立体但开销翻倍2048x2048 RT开阴影接近6ms很清晰但显存/带宽压力大6.2 降开销的几个实用策略策略一降低Capture更新频率只更新关键帧。如果场景里没有快速移动的物体倒影变化其实很慢。CaptureComponent有个属性叫CaptureEveryFrame默认是true也就是每帧都渲染。做静态大厅项目时完全可以在Actor的EventBeginPlay里设成false然后定时手动触发CaptureScene()比如每3帧或者每0.1秒采集一次。像地板反射这种对实时性要求不高的应用场景肉眼几乎感觉不到延迟。策略二关阴影、用低分辨率。把动态阴影关掉之后省下的GPU时间相当可观。如果你的倒影主要表现吊灯轮廓、墙面装饰的颜色而不是物体和地面的相对位置因阴影产生的空间感关阴影是性价比最高的一刀。本质上是牺牲一点立体感换性能但对反射画面来说色彩和轮廓通常比阴影重要。策略三用多个小Capture代替一个大Capture。如果大厅里有好几块反射面每块的视线范围不同有的人第一反应是放一个很大的Capture把整层楼采集一遍。这个做法会让RT内容很杂而且每个反射面材质里还要做不同区域的裁剪。更好的方案是每块反射面一个Capture各绑定自己的小RT分辨率可以开小一点每个Capture负责一小块区域。这样虽然Capture数量变多了但每个的渲染内容范围小、裁剪距离近、实际总开销反而可能比一个全场景大Capture更低。策略四用LOD和剔除。给CaptureComponent设置一个合理的MaxViewDistanceOverride最大可视距离这能控制它只渲染近距离物体。对地面反射来说远处的东西在倒影里本来就小到看不清不如直接剔除掉省下的开销用来提高近处物体的反射分辨率性价比更好。6.3 多反射面的推流顺序和显存水位如果项目里用了多个Capture注意所有RT的显存总和。光一个2048x1024的RT就是8MB三个反射面就是24MB再加上场景主RT、各类Buffer显存水位会明显抬高。在PS4/Xbox或者低显存PC平台上这一块一定要提前列入预算表。我的原则是宁可分辨率下调一档也不要把Capture开得很宽。低分辨率但频繁更新的反射观感上往往优于高分辨率但只能隔一两秒才更新一次的反射。7. 几个容易被忽视的细节坑这块是从多次实操里攒下来的单个问题看起来小但足以让整体效果崩掉值得单独记录。坑一Capture Actor自身在场景里的可视性。场景采集2D这个Actor在关卡中如果被放置在地面以下它的网格体Capture的可视化线框有时会被主相机拍到但更麻烦的是它本身在RT渲染时会不会算进去。绝大多数情况下把Capture的Actor Hidden In Game打开就行避免自己的网格污染采集画面。坑二RT在LDR/HDR下的颜色偏差问题。Capture渲染出来的RT颜色值和主相机看到的颜色存在微小的曝光差异特别是在使用自动曝光Auto Exposure的时候。Capture组件可以单独设置PostProcess Settings里的曝光补偿比如设成1.0~1.2去匹配主相机的观感。我一般做反射时直接把Capture的自动曝光关掉用固定曝光值这样反射面的亮度稳定不会跟着视角变来变去。坑三反射面材质不能是纯Metallic1的金属表面。如果你把材质做成金属度1、粗糙度0的纯镜面SceneCapture做反射的思路反而不适用——因为金属表面直接靠反射捕获Reflection Capture和SSR更好看而且金属的高光颜色来自BaseColor你贴一张RT进去要让BaseColor的逻辑也让位这个混合非常绕。真需要精细的镜面反射直接用Planar Reflection更省心。场景采集2D的最佳使用区间是粗糙度0.3~0.7的半光泽表面比如大理石、木地板、釉面砖。坑四Capture的旋转不能跟着角色自由转动。有朋友想把Capture挂在角色身上做随身反射结果一转视角RT里的世界跟着转反射面像旋转木马一样观感极其诡异。做角色周围的地面反射时Capture的yaw方向应该固定在朝向反射面的方向或者跟随角色位置但保持水平朝向稳定绝不能让Yaw任意旋转。每次做场景采集2D我最后都会把材质参数面板整理好便于随时调反射强度、模糊量和远近淡出距离。这类反射是被性能逼出来的折中方案参数调对了完全可以接近真实反射的质感。如果你项目里也有类似大理石地面、镜面柜台这类必须清楚但又不值得上PlanarReflection的反射需求直接按这套链路走半天时间应该就能看到可用的效果。
返回列表