最近在学习Shader,这个算是这段时间的一个小的回顾吧
==================================================================================================
先简单的说明一下,我们是希望通过两个pass通道进行渲染,第一个pass处理顶点的放大,以及方法之后的外部贴图,后一个pass混合前一个渲染的颜色值,做出一个类似于两个圆套接的一个样子。。。代码如下
Shader "ShaderTest_01/Test_01"
{
properties
{
[HDR]_Color("Main Color",Color) = (1,1,1,1)
_VertexScale("顶点缩放系数",range(0,1)) = 0
_Attenuation("内部衰减系数",range(1,36)) = 8
_ScaleTex("外围pass贴图",2D) = "while" {}
}
SubShader
{
Tags{ "RenderType"="Opaque" "Queue"="Transparent" "LightMode"="ForwardBase"}
LOD 200
pass
{
blend srcalpha OneMinusSrcAlpha
CGPROGRAM
#include "UnityCG.cginc"
#pragma vertex vert
#pragma fragment frag
float _ScaleAttenuation;
float _VertexScale;
sampler2D _ScaleTex;
float4 _ScaleTex_ST;
struct a2v
{
float4 vertex : POSITION;
float3 normal : NORMAL;
float2 uv : TEXCOORD0;
};
struct v2f
{
float4 pos : POSITION;
float4 vertex : TEXCOORD4;
float3 normal : TEXCOORD5;
float2 uv : TEXCOORD0;
};
v2f vert(a2v v)
{
v2f o;
v.vertex.xyz += v.normal.xyz * _VertexScale;
o.pos = UnityObjectToClipPos(v.vertex);
o.vertex = v.vertex;
o.normal = v.normal;
o.uv = TRANSFORM_TEX(v.uv, _ScaleTex);
return o;
}
fixed4 frag(v2f v): COLOR
{
float3 V = normalize(WorldSpaceViewDir(v.vertex)).xyz;
float3 N = normalize(mul(unity_ObjectToWorld,v.vertex)).xyz;
float e = 1 - saturate(dot(V,N));
fixed4 color = fixed4 (1,1,1,0.1);
fixed4 tex= tex2D(_ScaleTex,v.uv);
fixed4 t_color = fixed4(0,0,0,1);
t_color.a *= saturate((1 - 0.9));
t_color.a = max(t_color.a * 10000,0.1);
color += t_color;
if(tex.r > 0.1 && e < 0.95)
{
discard;
}
color.a *= e;
return color;
}
ENDCG
}
pass
{
blend srcalpha OneMinusSrcAlpha
CGPROGRAM
#include "UnityCG.cginc"
#pragma vertex vert
#pragma fragment frag
float4 _Color;
float _Attenuation;
struct v2f
{
float4 pos : POSITION;
float4 vertex : TEXCOORD4;
float3 normal : TEXCOORD5;
};
v2f vert(appdata_base v)
{
v2f o;
o.pos = UnityObjectToClipPos(v.vertex);
o.vertex = v.vertex;
o.normal = v.normal;
return o;
}
fixed4 frag(v2f v): COLOR
{
float3 V = normalize(WorldSpaceViewDir(v.vertex)).xyz;
float3 N = normalize(mul((float3x3)unity_ObjectToWorld,v.vertex)).xyz;
float e = 1 - saturate(dot(V,N));
fixed4 color = fixed4 (1,1,1,1);
color *= pow(e,_Attenuation);
color *= _Color;
return color;
}
ENDCG
}
}
}
最终这个长得跟个桃子一样的就是实现目标了
===========================================以下为讲解============================================
我们需要注意的就是第一个pass里面的 ZWrite off 这句话,试想一下,假设我们不关闭深度写入,那么我们知道,我们第一个pass执行完毕之后顶点数据肯定是要在第二个pass之前的(因为放大了X倍),所以就会导致我们第二个pass里面的所有片源都会被第一个pass遮挡,所以,在这里我们要把第一个pass的深度写入关闭。。。
顶点没什么好说的,没做什么操作
而片元里面。。。或许已经有小伙伴发现了,两个pass片元代码其实差不多。。。对,这个代码其实是通过世界方向上的顶点来和相机的坐标进行一个点乘,求出顶点与相机的角度形成的Cos值,计算得出的角度来进行一个从中部到边缘的一个透明到加深的一个代码块,而使用这种代码的原因则是因为我们的blend采用的 blend srcalpha one 也就是一个颜色相加操作,如果我们只用同一个代码块不进行任何参数上的修改的话,那么,由于两个渲染的顶点不同,就会出现第一个pass渲染的颜色把第二个pass上的颜色覆盖的情况发生,所以为了防止这种情况发生,我们为两个pass分别用了同样的一套代码,不同的参数实现。。。(感觉不用在讲解了,这个地方都说完了 = = )
不过在这里,遇到了一个挺奇怪的事情,本来想让外围的贴图进行一个时间平移的,但没想到从百度上下载的这张贴图没办法进行平移,见识太少 = =