软件:Unity 2022.3.51f1c1、vscode、Meta XR All in One SDK V72
硬件:Meta Quest3
仅针对urp管线
参考了YY老师这篇,可以先看他的再看这个可能更好理解一些:Unity Meta Quest MR 开发(七):使用 Stencil Test 模板测试制作可以在虚拟与现实之间穿梭的 MR 传送门_unitymr-CSDN博客
他这篇只讲了怎么在现实开虚拟世界的门,我的游戏需要有透视“裂缝”,所以研究了一下怎么在虚拟世界打开能被虚拟物体遮挡的透视窗口(building block里面已有的surface projected passthrough并没有遮挡关系)
我的大概思路就是把他的逻辑不完全地反过来吧,要在虚拟世界开透视世界的洞,又不能像surface projected passthrough一样让它浮在最前方,那么只能让透视世界作为最底层的背景层,只让指定物体(下文称为crack)可以显示出最底层,并让指定物体正常参与深度测试。
博主对渲染完全不熟,胡乱尝试中摸出了想要的结果,我尽可能去理解解释原理,可能有误,不要完全相信我讲的,希望渲染大佬指正。
一、使用BuildingBlock配置全局透视
删除原有场景的mainCamera将以下两个模块拖入场景
原理解释:打开passthrough物体找到下面这个组件,可以看到设置的placement是underlay,表明该透视图层会放置在虚拟下方
那么这种情况下,如果场景中还有天空盒的话,透视图层则无法显示(因为透视图层在最下层)
而meta在自动配置中给出的办法则是让摄像机忽略天空盒
点开BackGround可以看到它将背景颜色设为了透明
二、设置虚拟世界天空盒
要知道,我们现在可是想在虚拟世界开一个透视世界的洞,虚拟世界怎么能没有天空呢
建一个巨大球体给上需要的天空盒材质即可
将该球体的Layer设置为Background层级(很关键)
三、新建一个模板Shader和材质并将其赋给需要透视的物体crack
先解释一下模板测试
每个像素都有一个“模板值”(存在Stencil Buffer模板缓冲区里,默认保存的值是 0)。
你设置一个测试条件(比如:只有模板值 != 1 的地方才画)。
Unity 会检查每个像素的模板值是否满足这个条件。
满足 → 可以渲染。
不满足 → 这个像素就被“挡住”,不渲染。
而下面这个shader的作用是更新它自身的模板值为我们手动设定的StencilID
Shader "Examples/Stencil"
{Properties{[IntRange] _StencilID ("Stencil ID", Range(0, 255)) = 0}SubShader{Tags { "RenderType" = "Opaque"//告诉Unity这个是“不透明”物体"Queue" = "Geometry"//设置渲染队列(在透明物体之前渲染)"RenderPipeline" = "UniversalPipeline"//指定这个 Shader 适用于 URP}Pass{Blend Zero One//不画任何东西(颜色乘以0),因为只想用这个 Pass 来设置模板值,不是真的画图。//ZWrite Off //不写入深度,不参与深度测试,一定要画上去Stencil{Ref [_StencilID]// 要写入的模板值Comp Always// 总是通过测试Pass Replace// 测试通过时把模板值替换为 _StencilIDFail Keep//如果测试失败 → 保持原值(虽然这里总是通过)}}}
}
这就是YY老师给的Shader代码,我唯一改的是注释掉了不写入深度,因为我们需要让挂有此材质的crack物体与背景以外的其他物体有正常的遮挡关系。
创建一个材质,shader选择为Stencil,模板值设置为1,将材质赋给需要透视的物体
给上去以后发现是这种不可见的效果
因为我们还没有在管线里打开模板测试,现在这个shader所做的只是更改了自身的模板值,然后什么也不画。
四、配置URP管线
1.在quality里找到自己正在使用的渲染管线
2.找到Render Pipeline Asset里正在使用的Renderer,复制一份后修改名字替换给它(也可以不复制直接改,我这里为了备份一下才复制了个新的)
3.配置Renderer Data
Unity - Manual: Universal Renderer asset reference for URP
Filtering里移除天空盒所在的Background层级,即在主渲染流程中不渲染该层
在此Renderer Data中添加一个RendererFeature(渲染器功能),配置如下
Unity - Manual: Render Objects Renderer Feature reference for URP
Unity - Manual: Stencil command in ShaderLab reference
各个配置的意思大家翻unity文档吧,这里只解释作用还有一个比较容易误会的点
作用:它相当于为此渲染器添加了一个功能,在渲染完不透明物体以后,再渲染Background层级的物体,并针对该层级开启模板测试,只让该层级下模板值!=1的物体通过模板测试,也就是说,有crack在的屏幕像素点都无法通过模板测试就会形成下面的效果。
易错点:pass keep和fail keep的意思是有没有通过模板测试都会保留该位置模板值,不是保留像素点颜色
这时候应该会有同学和我有一样的疑惑吧,为什么在crack前面的物体就正常渲染出来了,而天空盒就这样被抠了一个洞呢?
因为crack的层级不是Background,所以,它自身并没有参与模板测试,它所做的只是为需要模板测试的Background层级提供了一个模板值。它自己是位于正常的层级关系里,当然会和其他物体一样具有遮挡关系
好了这就完成啦,串流上头盔就能看见透视场景咯。
我不知道没学过渲染的同学是不是觉得我说得很有道理。希望大家可以照着步骤做但是不要全信我讲的原理,因为我是根据现象推的结论,而这一切结论都被我将管线设置为对所有层级进行模板测试,只让不等于1的模板值通过测试后出现的效果推翻了哈哈哈。按理来说应该会和之前的效果一致啊,怎么会无效呢,到底为什么呢,是顺序出错了吗,有没有大佬跟我讲一下为什么
2025.4.17
测试发现这种配置方法和Lit材质里开了alpha clipping的材质不兼容,会出现诡异的透视效果,目前没找到解决办法,直接解决问题的来源了哈(不用alpha clipping)