1.Shader在什么情况下使用
Particles/Additive(粒子/叠加)到了粒子系列了,之所以先写前面几篇是因为本shader中都用到了,篇幅有限,因此分了几篇来写。本文注释中有关INSTANCE_ID和软粒子的深度计算方法都没有搞明白,不懂的部分只能后面再深入研究了不能阻挡学习的脚步。
2.Shader的价值(用的多不多),Shader的难度
Additive应该是用的非常多的,难度非常大,毕竟有些细节我还没搞明白。
3.代码详细注释
// Unity built-in shader source. Copyright (c) 2016 Unity Technologies. MIT license (see license.txt)
Shader "Legacy Shaders/Particles/Additive" {
Properties {
_TintColor ("Tint Color", Color) = (0.5,0.5,0.5,0.5)//明调颜色
_MainTex ("Particle Texture", 2D) = "white" {}//贴图
_InvFade ("Soft Particles Factor", Range(0.01,3.0)) = 1.0//软粒子因子
}
Category {
Tags {
"Queue"="Transparent" //申明渲染队列为透明(3000)
"IgnoreProjector"="True"//忽略所有阴影
"RenderType"="Transparent" //声明为透明物体
"PreviewType"="Plane" //指示材质检视面板预览应如何显示材质。默认情况下,材质显示为球体,但也可以将 PreviewType 设置为“Plane”(将显示为 2D)或“Skybox”(将显示为天空盒)
}
// Blend SrcAlpha One//透明混合模式
// ColorMask指定渲染结果的输出通道,而不是通常的 RGBA 四个通道都被写入
// ColorMask RGB,RBA等,意思是输出颜色中RGB,RBA通道会被写入
// ColorMask R,意思是输出颜色中只有R通道会被写入
// ColorMask 0,意思是不会输出任何颜色
// 默认值为RGBA,即四个通道都写入
ColorMask RGB
// //双面显示,关闭裁剪
// Cull Off
// //关闭灯光影响
// Lighting Off
// //关闭深度写入
// ZWrite Off
SubShader {
Pass {
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#pragma target 2.0
//使用您定义的一组关键字来编译多个实例。查看已编译的着色器,multi_compile_particles添加了SOFTPARTICLES_ON和SOFTPARTICLES_OFF,因此,这只是Unity自己的粒子关键字风格,包含该关键字。此外,您可以在质量设置中切换关键字。
//简单说所有multi_compile开头的都是声明宏定义
//之后就可以用#if xxxx #endif了
//或者使用官方定义的宏定义如下,可以自动生成一些宏定义
// #pragma multi_compile_particles表示允许使用官方的软阴影粒子SOFTPARTICLES_ON/SOFTPARTICLES_OFF的宏定义开关
#pragma multi_compile_particles
//雾效宏定义,不了解可以看雾效篇
#pragma multi_compile_fog
#include "UnityCG.cginc"
sampler2D _MainTex;
fixed4 _TintColor;
struct appdata_t {
float4 vertex : POSITION;
fixed4 color : COLOR;
float2 texcoord : TEXCOORD0;
//在“顶点着色器输入/输出”结构中定义一个语义为SV_InstanceID的元素。一些要更改的属性,则可以根据ID进行更改,而无需为MaterialPropertyBlock设置其他属性。
//在UnityInstancing.cginc文件中可找到UNITY_VERTEX_INPUT_INSTANCE_ID的定义
//#define UNITY_VERTEX_INPUT_INSTANCE_ID uint instanceID : SV_InstanceID;
//通常用在GPU Instancing和VR中
//在VR中他们将实例ID和眼睛索引传递给片段着色器。这使您可以访问片段着色器中的实例化属性,以及进行可能需要的每眼唯一工作。例如,如果您使用任何视图矩阵或投影矩阵或片段着色器中的相机位置,则这些都需要眼图索引以提供正确的值,否则,您将始终访问左眼。
//这部分网上资料太少-。-搜不到,暂时不理解,就先这样吧
UNITY_VERTEX_INPUT_INSTANCE_ID
};
struct v2f {
float4 vertex : SV_POSITION;
fixed4 color : COLOR;
float2 texcoord : TEXCOORD0;
////雾效,不了解可以看雾效篇
UNITY_FOG_COORDS(1)
//如果启用软粒子
#ifdef SOFTPARTICLES_ON
float4 projPos : TEXCOORD2;
#endif
UNITY_VERTEX_OUTPUT_STEREO
};
float4 _MainTex_ST;
v2f vert (appdata_t v)
{
v2f o;
//同UNITY_VERTEX_INPUT_INSTANCE_ID
//需要写在vert shader的最前面
UNITY_SETUP_INSTANCE_ID(v);
UNITY_INITIALIZE_VERTEX_OUTPUT_STEREO(o);
//取裁剪空间顶点位置
o.vertex = UnityObjectToClipPos(v.vertex);
//如果软粒子系统打开,需要#pragma multi_compile_particles
//开关在质量设置里
#ifdef SOFTPARTICLES_ON
//ComputeScreenPos传入裁剪空间顶点坐标变换到齐次坐标系下的坐标
//齐次坐标就是将笛卡尔坐标转成矩阵,便于变换操作
o.projPos = ComputeScreenPos (o.vertex);
//计算顶点摄像机空间的深度:距离裁剪平面的距离,线性变化;
//在顶点着色器中取出深度信息储存到projPos,在片段着色器中使用
COMPUTE_EYEDEPTH(o.projPos.z);
#endif
//获取mesh顶点色
//一般情况下顶点色都是没有使用的默认为白色
o.color = v.color;
//将模型顶点的uv和Tiling、Offset两个变量进行运算,计算出实际显示用的顶点uv
//如果不需要Tiling、Offset可以移除
o.texcoord = TRANSFORM_TEX(v.texcoord,_MainTex);
//雾效,不了解可以看雾效篇
UNITY_TRANSFER_FOG(o,o.vertex);
return o;
}
UNITY_DECLARE_DEPTH_TEXTURE(_CameraDepthTexture);
float _InvFade;
fixed4 frag (v2f i) : SV_Target
{
#ifdef SOFTPARTICLES_ON
//获得当前片元显示的深度
//LinearEyeDepth 负责把深度纹理的采样结果转换到视角空间下的深度值
float sceneZ = LinearEyeDepth (SAMPLE_DEPTH_TEXTURE_PROJ(_CameraDepthTexture, UNITY_PROJ_COORD(i.projPos)));
//顶点计算出来的深度
float partZ = i.projPos.z;
//saturate将值限制到0-1
//使用混合度_InvFade乘以两个深度的差
//有关这两个深度查到的信息不多,暂时也搞不明白,先搁这后面明白了再更
float fade = saturate (_InvFade * (sceneZ-partZ));
//混合度影响一下透明度
i.color.a *= fade;
#endif
//最终颜色混合
// alpha should not have double-brightness applied to it, but we can't fix that legacy behavior without breaking everyone's effects, so instead clamp the output to get sensible HDR behavior (case 967476)alpha不应该应用双倍的亮度,但是我们不能在不破坏每个人的效果的情况下修复遗留行为,所以取而代之的是钳制输出以获得合理的HDR行为(案例967476)
fixed4 col = 2.0f * i.color * _TintColor * tex2D(_MainTex, i.texcoord);
//限制透明度区间
col.a = saturate(col.a);
//雾效混合,不了解可以看雾效篇
UNITY_APPLY_FOG_COLOR(i.fogCoord, col, fixed4(0,0,0,0)); // fog towards black due to our blend mode由于我们的混合模式雾向黑色
return col;
}
ENDCG
}
}
}
}
4.Shader编写思路,用到的知识点
粒子其实主要就是显示原本的颜色并且提亮,本Shader涵盖了很多如适配性代码,其中软粒子主要是指粒子图像边缘混合时柔化,具体可以自行百度,其他的知识点参考本系列前面几篇。
Legacy Shaders下的Particles系列基本与本文98%相似,各个不同仅修改了混合方式,至于透明混合方式写法都比较简单,本文不再讨论,读者自行研究(本系列的主要目的是梳理官方shader了解各种语法用法知识点,而非实现具体逻辑及shader效果)。