Unity Shader 能量罩效果
admin
2023-06-20 04:21:02
0

这次用能量罩继续Shader效果的练习。

分析能量罩的结构:

  1. 能量罩球体边缘高光
  2. 和物体相交的边缘高光
  3. 能量罩的纹理

能量罩球体边缘高光

能量罩本身其实应该是个半透明光球,但为了能够展示内部的角色或者物体,正对摄像机的部分要变全透明让内部被清晰的看到,直接用RIM边缘光渲染就可以。因为是透明的,所以要两面都渲染,将视向量和法线的点积结果取绝对值来保证背面的正确渲染。

Tags{ "RenderType"="Transparent" "Queue" = "Transparent" "IgnoreProjector" = "True"}
Blend One One
ZWrite Off
Cull Off

fixed4 frag(...) : SV_Target
{
...
half rim = pow(1 - abs(dot(normalDir,viewDir)) , _RimNum);
...
}

和物体相交的边缘高光

在游戏中看到的能量罩可以发现,在和地面、物体相交的部分也是会高亮显示的,也算是能量罩的边缘。所以需要正确得到相交的信息,可以通过当前片元能量罩的深度和场景中的深度做对比,如果两个深度是相等,那么就说明能量罩和物体是相交的。

主相机的深度图可以获取场景中的深度信息。但是能量罩因为是透明渲染,没有影子的部分,所以也就没有ShadowCaster的Pass,也就不会出现在主相机的深度图中。但是通过Clip空间获取到能量罩当前片元的深度值,使用ComputeScreenPos函数可以将Clip空间的坐标转换为屏幕坐标,函数内对xy分量做了转换处理,zw分量直接使用了原值。Clip空间的z分量是从-Near到Far的,而深度图中的LinearEyeDepth后的范围是Near到Far,所以通过COMPUTE_EYEDEPTH函数将深度转化到Near到Far。




Unity ComputeScreenPos函数源码

那么我已经通过相机深度图获取到了场景深度信息,Clip空间z分量获取到了能量球的深度信息,接着通过比较计算得到相交的信息。

float diff = pow(1-saturate((sceneZ - partZ)), _EdgePow);

像RIM一样,通过_EdgePow来控制相交高亮的范围。




能量罩一个一个Cube相交

能量罩的纹理

直接给一个纹理贴图就可以展示出想要的纹理效果,如果加上一个时间偏移就可以做出动画的效果。

fixed4 frag(...) : SV_Target
{
fixed4 col = fixed4(0,0,0,0);
...
fixed main = tex2D(_MainTex, i.uv + _Time.y * 0.02).r;
fixed4 mainColor = _TintColor * pow(1 - main, 3);
...
col = lerp(col, _TintColor, diff);
col = lerp(col, mainColor, rim);
}

我的主纹理是一张噪波图,所以只取了一个通道并做了处理。





基本的效果都完成了,但是看着有点暗淡,能量罩显得有点能量不足,所以做个简单的处理。

col = lerp(col, mainColor, rim) * 4;

这样看起来就好多了,但是还是感觉少了点什么,作为一个带能量的发光球体有点Bloom的效果会更好一点。



能量罩的展开

能量罩开启其实就是一个定向消融效果,还是使用了我之前的消融效果文章里的方法。

然后就可以从各个方向来实现能量罩的开启和关闭:


下一步会尝试加上能量罩被击中后的能量涟漪效果,做完之后再做文章的更新。

参考:

相关内容