(提示:只看代码请跳过这里) 情况是这样的。。。在学习一位大佬的全息shader时出了意外 大佬文章链接,作者:晨蓝fk 就算是将代码全部复制过来,也无法复原大佬原文图里的效果。 查了一下资料,可能是因为没有对ComputeScreenPos()函数返回值的结果做齐次除法运算?(该函数返回的结果是屏幕空间下顶点的齐次坐标,需要除以w分量或用tex2Dproj函数来采样纹理) 尝试的结果要么扫描线不动要么扫描线移动方式很奇怪(如图) 因为扫描线的原理主要依靠采样纹理后的结果做一次片元剔除,再加上没有原博主的纹理图我无法确定原文的纹理采样结果,就会剔除掉不应该剔除的片元。 同时,扫描线的流向和粗细也不好控制,以飞机模型为例,虽然都是y轴上从低到高,但从头看和从飞机顶上向下看扫描线流向是不一样的(因为原文是计算模型顶点在屏幕空间的位置,流向会随着视角的改变而发生改变,尽管代码上都是uv.y值升高)
就这样改了半天,最后发觉直接放弃在屏幕空间计算顶点的思路,改用模型UV来实现的效果。。。居然还可以?
正文开始
OK,将思路改为用模型UV采样动画纹理 上代码!
Shader "Unlit/HolographicShader"
{
Properties
{
_MainTex ("Texture", 2D) = "white" {}
_LightTex ("全息贴图",2D) = "white"{}
_NoiseTex ("噪音贴图",2D) = "white"{}
[HDR]_Color ("主颜色",Color) = (1,1,1,1)
[HDR]_RimColor ("边缘光",Color) = (1,1,1,1)
_Alpha ("透明度",Range(0,1)) = 0
_Speed ("扫描线速度",Range(0,15)) = 1
_RandomSpeed("闪一闪的速度",float) = 1
_CutOut ("阙值",Range(0,1.1)) = 0.1
}
SubShader
{
Tags { "RenderType"="Transparent" "Queue" = "Transparent" "IgnoreProjector" = "true"}
Pass
{
ZWrite on
ColorMask 0
}
Pass
{
ZWrite off
Blend SrcAlpha OneMinusSrcAlpha
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "UnityCG.cginc"
struct a2v
{
float4 vertex : POSITION;
float3 normal : NORMAL;
float2 uv : TEXCOORD0;
};
struct v2f
{
float2 uv : TEXCOORD0;
float3 worldPos : TEXCOORD1;
float3 worldNormal : TEXCOORD2;
float4 vertex : SV_POSITION;
};
sampler2D _MainTex;
float4 _MainTex_ST;
sampler2D _LightTex;
float4 _LightTex_ST;
sampler2D _NoiseTex;
float4 _NoiseTex_ST;
fixed4 _Color;
fixed4 _RimColor;
half _Alpha;
half _Speed;
half _RandomSpeed;
half _CutOut;
v2f vert (a2v v)
{
v2f o;
o.vertex = UnityObjectToClipPos(v.vertex);
o.uv = TRANSFORM_TEX(v.uv, _MainTex);
o.worldNormal = UnityObjectToWorldNormal(v.vertex);
o.worldPos = mul(unity_ObjectToWorld,v.vertex).xyz;
return o;
}
fixed4 frag (v2f i) : SV_Target
{
float3 normalDir = normalize(i.worldNormal);
float3 viewDir = normalize(UnityWorldSpaceViewDir(i.worldPos));
float3 rimLight = 1.0 - saturate(dot(normalDir,viewDir));
rimLight *= _RimColor;
float2 scrPos = TRANSFORM_TEX(i.uv.xy,_LightTex);
scrPos.y += _Time.w * _Speed;
float4 scrcol = tex2D(_LightTex,scrPos);
clip(scrcol - _CutOut);
float speed = _RandomSpeed * _Time.y;
float Random = tex2D(_NoiseTex,float2(speed,speed));
float4 maincol = tex2D(_MainTex,i.uv);
return fixed4(maincol.rgb * scrcol + _Color + rimLight,_Alpha * Random);
}
ENDCG
}
}
}
使用的动画纹理 使用的噪音纹理
演示出来的最终效果: 无边缘光
有边缘光
结个尾
这个方案优点是简单易理解。但缺点嘛。。。 受模型UV的影响,你会发现扫描线不是完全按照整个机身扫描下去。。 如图,驾驶舱的扫描线就是横着扫过去的,机身是竖着扫的。 如果要解决,一个思路就是上文大佬的屏幕空间计算方案,可以让整个模型扫描线顺畅。。。但问题又绕回去了。
那么就先写到这,等路过的大佬看看我
|