Unity投射阴影--V2F_SHADOW_CASTER,TRANSFER_SHADOW_CASTER_NORMALOFFSET(o),SHADOW_CASTER_FRAGMENT(i)三部分

作用:让物体能够投射阴影

原理:返回裁剪空间的坐标,写入depth buff,让摄像机在光源空间渲染出深度图,再进一步渲染出屏幕阴影纹理(某些平台并没有这一步骤https://blog.csdn.net/zengjunjie59/article/details/111356636),最后在光照pass里面对纹理进行采样。

例子:

Pass 
{
Tags 
{
    "LightMode" = "ShadowCaster"
}

CGPROGRAM
    #pragma target 3.0
    
    // 定义相关key,具体看https://blog.csdn.net/zengjunjie59/article/details/111404824
    #pragma multi_compile_shadowcaster
    

    #include "CustomShadows.cginc"
    #pragma vertex MyShadowVertexProgram
    #pragma fragment MyShadowFragmentProgram
ENDCG
}
#if !defined(CUSTOM_SHADOWS_INCLUDE)
#define CUSTOM_SHADOWS_INCLUDE

#include "UnityCG.cginc"


//如果直接调用unity自带的宏,则可以这样写
struct Interpolators{
	V2F_SHADOW_CASTER;
};

Interpolators MyShadowVertexProgram(appdata_base v){
	Interpolators i;
	TRANSFER_SHADOW_CASTER_NORMALOFFSET(i);
	return i;
}

float4 MyShadowFragmentProgram(Interpolators i): SV_TARGET {
	SHADOW_CASTER_FRAGMENT(i);
}

#endif

 

 

首先看第一个宏:V2F_SHADOW_CASTER

源码:

// On D3D reading screen space coordinates from fragment shader requires SM3.0
#define UNITY_POSITION(pos) float4 pos : SV_POSITION

#if defined(SHADOWS_CUBE) && !defined(SHADOWS_CUBE_IN_DEPTH_TEX)
    // Rendering into point light (cubemap) shadows
    #define V2F_SHADOW_CASTER_NOPOS float3 vec : TEXCOORD0;
#else
    // Rendering into directional or spot light shadows
    #define V2F_SHADOW_CASTER_NOPOS
    // Let embedding code know that V2F_SHADOW_CASTER_NOPOS is empty; so that it can workaround
    // empty structs that could possibly be produced.
    #define V2F_SHADOW_CASTER_NOPOS_IS_EMPTY
#endif


// Declare all data needed for shadow caster pass output (any shadow directions/depths/distances as needed),
// plus clip space position.
#define V2F_SHADOW_CASTER V2F_SHADOW_CASTER_NOPOS UNITY_POSITION(pos)

其实就相当于:

#if defined(SHADOWS_CUBE) && !defined(SHADOWS_CUBE_IN_DEPTH_TEX)
    float4 pos : SV_POSITION   // 用于储存裁剪坐标
    float3 vec : TEXCOORD0     // 用于储存光源到顶点的世界空间方向向量
#else
    float4 pos : SV_POSITION
#endif

 

顶点着色器里用的宏:TRANSFER_SHADOW_CASTER_NORMALOFFSET(o)

源码:

#if defined(SHADOWS_CUBE) && !defined(SHADOWS_CUBE_IN_DEPTH_TEX)
    // 计算世界空间光源到顶点的向量
    // 计算顶点裁剪坐标
    #define TRANSFER_SHADOW_CASTER_NOPOS(o,opos) o.vec = mul(unity_ObjectToWorld, v.vertex).xyz - _LightPositionRange.xyz; opos = UnityObjectToClipPos(v.vertex);
#else
    // 转换到才裁剪空间齐次坐标,并执行顶点法向偏差
    // 便宜裁剪齐次坐标的z值,并返回顶点裁剪坐标点
    #define TRANSFER_SHADOW_CASTER_NOPOS(o,opos) \
        opos = UnityClipSpaceShadowCasterPos(v.vertex, v.normal); \
        opos = UnityApplyLinearShadowBias(opos);
#endif


// Vertex shader part, with support for normal offset shadows. Requires
// position and normal to be present in the vertex input.
#define TRANSFER_SHADOW_CASTER_NORMALOFFSET(o) TRANSFER_SHADOW_CASTER_NOPOS(o,o.pos)

 

片元着色器里用的宏:SHADOW_CASTER_FRAGMENT(i)

源码:


#if defined(SHADOWS_CUBE) && !defined(SHADOWS_CUBE_IN_DEPTH_TEX)
    // _LightPositionRange.w是1/Range, Range是光照范围
    // UnityEncodeCubeShadowDepth是如果检测到不能用浮点数则把float值的不同位存到rgba各个分量中
    // 整段算的就是光源空间下顶点的深度,值域[0, 1], 期间也用了z值偏差(+unity_LightShadowBias.x)
    #define SHADOW_CASTER_FRAGMENT(i) return UnityEncodeCubeShadowDepth ((length(i.vec) + unity_LightShadowBias.x) * _LightPositionRange.w);
#else
    #define SHADOW_CASTER_FRAGMENT(i) return 0;
#endif

 

最后:

有个小疑问:点光源,定义SHADOWS_CUBE之后,在SHADOW_CASTER_FRAGMENT宏里的第一个if分支下直接返回0效果并没有什么区别,猜测是某些平台会有用。有知道的人,还望指教指教

 

 

  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值