这次用能量罩继续Shader效果的练习。
分析能量罩的结构:
能量罩本身其实应该是个半透明光球,但为了能够展示内部的角色或者物体,正对摄像机的部分要变全透明让内部被清晰的看到,直接用RIM边缘光渲染就可以。因为是透明的,所以要两面都渲染,将视向量和法线的点积结果取绝对值来保证背面的正确渲染。
Tags{ "RenderType"="Transparent" "Queue" = "Transparent" "IgnoreProjector" = "True"}在游戏中看到的能量罩可以发现,在和地面、物体相交的部分也是会高亮显示的,也算是能量罩的边缘。所以需要正确得到相交的信息,可以通过当前片元能量罩的深度和场景中的深度做对比,如果两个深度是相等,那么就说明能量罩和物体是相交的。
主相机的深度图可以获取场景中的深度信息。但是能量罩因为是透明渲染,没有影子的部分,所以也就没有ShadowCaster的Pass,也就不会出现在主相机的深度图中。但是通过Clip空间获取到能量罩当前片元的深度值,使用ComputeScreenPos函数可以将Clip空间的坐标转换为屏幕坐标,函数内对xy分量做了转换处理,zw分量直接使用了原值。Clip空间的z分量是从-Near到Far的,而深度图中的LinearEyeDepth后的范围是Near到Far,所以通过COMPUTE_EYEDEPTH函数将深度转化到Near到Far。
那么我已经通过相机深度图获取到了场景深度信息,Clip空间z分量获取到了能量球的深度信息,接着通过比较计算得到相交的信息。
float diff = pow(1-saturate((sceneZ - partZ)), _EdgePow);像RIM一样,通过_EdgePow来控制相交高亮的范围。
直接给一个纹理贴图就可以展示出想要的纹理效果,如果加上一个时间偏移就可以做出动画的效果。
fixed4 frag(...) : SV_Target我的主纹理是一张噪波图,所以只取了一个通道并做了处理。
基本的效果都完成了,但是看着有点暗淡,能量罩显得有点能量不足,所以做个简单的处理。
col = lerp(col, mainColor, rim) * 4;这样看起来就好多了,但是还是感觉少了点什么,作为一个带能量的发光球体有点Bloom的效果会更好一点。
能量罩开启其实就是一个定向消融效果,还是使用了我之前的消融效果文章里的方法。
然后就可以从各个方向来实现能量罩的开启和关闭:
下一步会尝试加上能量罩被击中后的能量涟漪效果,做完之后再做文章的更新。
参考: