Dither抖动透明效果、Unity渲染路径对阴影的影响

本文探讨了在3D游戏中如何通过shader解决‘卡视角’问题,通过抖动消隐技术使遮挡人物的物体透明化。作者介绍了在Unity中使用clip函数和Dither阈值来实现这一效果,以及针对不同渲染路径下阴影接受问题的解决方案。
摘要由CSDN通过智能技术生成

制作3d人物控制时,经常遇见镜头撞墙缩到角色模型内的“卡视角”现象。但在部分场景中是突发的卡视角会破坏游戏体验,所以有种方案是将遮挡人物的物体透明化消隐掉。

最近看见碧蓝幻想relink中的场景抖动消隐方式比较感兴趣,所以试着实现一下shader

效果如右图,抖动

矩阵设置比较简单所以点阵比较规则

关键方法就是在片元着色器里使用clip函数弃置部分片元

screenPos是片元在屏幕空间的坐标

Properties {
    _Dither ("Dither",Range(0, 1)) = 0.5//抖动阈值
}

fixed4 frag(v2f i) : SV_Target {
    //抖动剔除像素
    float2 screenPos = (i.screenPos.xy / i.screenPos.w) * _ScreenParams.xy;//屏幕像素坐标
    float DITHER_THRESHOLDS[4][4] =
    {//抖动矩阵,就是不透明度矩阵
	    1.0 / 17.0,  9.0 / 17.0,  3.0 / 17.0, 11.0 / 17.0,
	    13.0 / 17.0,  5.0 / 17.0, 15.0 / 17.0,  7.0 / 17.0,
	    4.0 / 17.0, 12.0 / 17.0,  2.0 / 17.0, 10.0 / 17.0,
	    16.0 / 17.0,  8.0 / 17.0, 14.0 / 17.0,  6.0 / 17.0
    };
    clip(_Dither - DITHER_THRESHOLDS[floor(fmod(screenPos.x, 4))][floor(fmod(screenPos.y, 4))]);
    //……

消隐的实现比较简单,但加上阴影就有出现问题了

接受阴影是SHADOW_COORDS()TRANSFER_SHADOW(o);,UNITY_LIGHT_ATTENUATION(atten, i, worldPos);三剑客

投射阴影是自定pass

// 投射阴影
Pass {
	Name "Caster"
	Tags { "LightMode" = "ShadowCaster" }//阴影投射模式
	CGPROGRAM
	#pragma vertex vert
	#pragma fragment frag
	#pragma multi_compile_shadowcaster//支持阴影投射
	#include "UnityCG.cginc"

	//float _Dither;

	struct v2f {
		//float4 screenPos : TEXCOORD0;//屏幕坐标,[0,1]
		V2F_SHADOW_CASTER;//宏定义的结构体,包含阴影投射所需的顶点数据
	};

	v2f vert( appdata_base v )
	{
		v2f o;
		//o.screenPos = ComputeScreenPos(v.vertex);//齐次屏幕空间坐标,在[0,1]之间
		TRANSFER_SHADOW_CASTER_NORMALOFFSET(o)//是一个宏,它用于计算并设置o结构体中阴影投射所需的法线和偏移信息。
		return o;
	}

	float4 frag( v2f i ) : SV_Target
	{
		抖动剔除像素
		//float2 screenPos = (i.screenPos.xy / i.screenPos.w) * _ScreenParams.xy;//屏幕像素坐标
		//float DITHER_THRESHOLDS[4][4] =
		//{
		//	1.0 / 17.0,  9.0 / 17.0,  3.0 / 17.0, 11.0 / 17.0,
		//	13.0 / 17.0,  5.0 / 17.0, 15.0 / 17.0,  7.0 / 17.0,
		//	4.0 / 17.0, 12.0 / 17.0,  2.0 / 17.0, 10.0 / 17.0,
		//	16.0 / 17.0,  8.0 / 17.0, 14.0 / 17.0,  6.0 / 17.0
		//};//抖动阈值
		//clip(_Dither - DITHER_THRESHOLDS[floor(fmod(screenPos.x, 4))][floor(fmod(screenPos.y, 4))]);
		SHADOW_CASTER_FRAGMENT(i)
	}

	ENDCG
}

设定一,材质渲染路径<2500,有深度图,能接受阴影但看不见柱后的阴影,虽然柱子理应是“透明”的

设定二,渲染路径>2500,无深度图,不能接受阴影,但可以看见柱后阴影,当_Dither抖动阈值设为1时也没法接受阴影了

设定三,渲染路径<2500,把投射阴影pass里也添加抖动剔除,结果是符合想象但走样严重

最终的妥协方案是两个材质,

未遮挡人物不产生抖动消隐就是正常不透明物体的渲染路径能接受阴影;

遮挡人物产生消隐了切换渲染路径为Transparent的材质,虽不能接受阴影但无伤大雅,重要是透过这个物体看人物及其他物体的阴影是正常的

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值