Transparent - wlgys8/SRPLearn GitHub Wiki
半透明物体渲染(Transparent Object Render)
在之前的管线实现中,我们并没有考虑半透明物体。现在加入对半透明物体的渲染支持。
通常来说,在渲染场景时,一般:
- 先按照由近及远的方式渲染非透明物体(这样可以利用深度测试充分过滤掉被遮挡的像素,避开无用的计算)
- 再按照由远及近的顺序绘制半透明物体(因为半透明物体要显示其背后的像素,并与之混合)。在绘制半透明物体时,一般要关闭ZWrite.
效果图
SRP 实现
改造之前的XRenderPipeline
,将其中的物体渲染部分代码抽成一个单独的类RenderObjectPass
RenderObjectPass构造的时候,接受一个isTransparent作为参数,表示当前是透明Pass,还是非透明Pass。
public RenderObjectPass(bool transparent){
_isTransparent = transparent;
}
执行渲染:
public void Execute(ScriptableRenderContext context, Camera camera,ref CullingResults cullingResults){
var drawSetting = CreateDrawSettings(camera);
//根据_isTransparent,利用RenderQueueRange来过滤出透明物体,或者非透明物体
var filterSetting = new FilteringSettings(_isTransparent? RenderQueueRange.transparent:RenderQueueRange.opaque);
//绘制物体
context.DrawRenderers(cullingResults,ref drawSetting,ref filterSetting);
}
此处使用RenderQueueRange,来对渲染物体进行过滤。
CreateDrawSettings的时候,还要指定物体排序规则:
private DrawingSettings CreateDrawSettings(Camera camera){
var sortingSetting = new SortingSettings(camera);
//设置物体渲染排序标准
sortingSetting.criteria = _isTransparent?SortingCriteria.CommonTransparent:SortingCriteria.CommonOpaque;
var drawSetting = new DrawingSettings(_shaderTag,sortingSetting);
return drawSetting;
}
然后在XRenderPipeline中,构造两个Pass,分别代表非透明物体和透明物体渲染:
private RenderObjectPass _opaquePass = new RenderObjectPass(false);
private RenderObjectPass _transparentPass = new RenderObjectPass(true);
各自绘制:
//非透明物体渲染
_opaquePass.Execute(context,camera,ref cullingResults);
//透明物体渲染
_transparentPass.Execute(context,camera,ref cullingResults);
这样,我们的管线,就支持了透明物体的渲染。
但是,要真正渲染出透明物体,还需要写一个透明物体的渲染Shader。
Shader支持
在BlinnPongSpecular.shader的基础上,进行改造,得到BlinnPongSpecularTransparent.shader。其中针对阴影,有以下限制:
- 透明物体不支持投射阴影
- 透明物体可以受阴影影响
首先是将RenderType
和Queue
都修改为Transparent
Tags { "RenderType"="Transparent" "LightMode"="XForwardBase" "Queue" = "Transparent"}
关闭ZWrite:
ZWrite Off
设置Blend模式:
Blend SrcAlpha OneMinusSrcAlpha
我们增加一个Color属性,来控制透明物体的颜色和透明度:
fixed4 _Color;
在最后颜色输出阶段,将_Color.a作为透明度输出:
color = half4(color.rgb * _Color.rgb * shadowAtten,_Color.a);