Shader 源码-Unlit-Color
需要有一定的shader基础,深刻理解unity 内置shader的实现原里。
先贴代码,逐步分析
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68
| // Unity built-in shader source. Copyright (c) 2016 Unity Technologies. MIT license (see license.txt)
// Unlit shader. Simplest possible colored shader. // - no lighting // - no lightmap support // - no texture
Shader "Unlit/Color" { Properties { _Color ("Main Color", Color) = (1, 1, 1, 1) }
SubShader { Tags { "RenderType" = "Opaque" } LOD 100
Pass { CGPROGRAM #pragma vertex vert #pragma fragment frag #pragma target 2.0 #pragma multi_compile_fog
#include "UnityCG.cginc"
struct appdata_t { float4 vertex: POSITION; UNITY_VERTEX_INPUT_INSTANCE_ID };
struct v2f { float4 vertex: SV_POSITION; UNITY_FOG_COORDS(0) UNITY_VERTEX_OUTPUT_STEREO };
fixed4 _Color;
v2f vert(appdata_t v) { v2f o; UNITY_SETUP_INSTANCE_ID(v); UNITY_INITIALIZE_VERTEX_OUTPUT_STEREO(o); o.vertex = UnityObjectToClipPos(v.vertex); UNITY_TRANSFER_FOG(o, o.vertex); return o; }
fixed4 frag(v2f i): SV_Target { fixed4 col = _Color; UNITY_APPLY_FOG(i.fogCoord, col); UNITY_OPAQUE_ALPHA(col.a); return col; } ENDCG } } }
|
#pragma multi_compile_fog
实现很简单,重点点记录
- #pragma multi_compile_fog
- UNITY_VERTEX_INPUT_INSTANCE_ID
- UNITY_FOG_COORDS(0)
- UNITY_VERTEX_OUTPUT_STEREO
- UNITY_SETUP_INSTANCE_ID(v)
- UNITY_INITIALIZE_VERTEX_OUTPUT_STEREO(o)
- UNITY_TRANSFER_FOG(o, o.vertex)
- UNITY_APPLY_FOG(i.fogCoord, col)
- UNITY_OPAQUE_ALPHA(col.a)
这些在一个基础的顶点片元着色器的基本原里。
基础概念宏定义
1 2 3 4 5 6 7 8 9 10
| #define 标识 //定义标识,如果 (标识) 已经被标识过会报错。 #undef 标识 //取消标识的定义 #ifdef 标识 //判断某个宏是否被定义,若已定义,执行随后的语句 #ifndef 标示 // 判断"标示"是否定义,如果被定义则返回false,如果没有被定义则返回true
#if //编译预处理中的条件命令,相当于C语法中的if语句 #elif // 若#if, #ifdef, #ifndef或前面的#elif条件不满足,则执行#elif之后的语句,相当于C语法中的else-if #else //与#if, #ifdef, #ifndef对应, 若这些条件不满足,则执行#else之后的语句,相当于C语法中的else #endif //#if, #ifdef, #ifndef这些条件命令的结束标志. defined(宏) 与#if, #elif配合使用,判断某个宏是否被定义
|
#include “UnityCG.cginc”
这里需要注意下,include并不是像c++ 这样在调用shader时将文件include进去,而是在编译shader时决定生成的代码。可以测试在去掉#pragma multi_compile_fog前后点击shader面板 Compile and show code 查看编译后的代码。
追到UnityCG.cginc文件中查看UNITY_FOG_COORDS宏
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
| #if defined(FOG_LINEAR) || defined(FOG_EXP) || defined(FOG_EXP2) #define UNITY_FOG_COORDS(idx) UNITY_FOG_COORDS_PACKED(idx, float1)
#if (SHADER_TARGET < 30) || defined(SHADER_API_MOBILE) // mobile or SM2.0: calculate fog factor per-vertex #define UNITY_TRANSFER_FOG(o,outpos) UNITY_CALC_FOG_FACTOR((outpos).z); o.fogCoord.x = unityFogFactor #define UNITY_TRANSFER_FOG_COMBINED_WITH_TSPACE(o,outpos) UNITY_CALC_FOG_FACTOR((outpos).z); o.tSpace1.y = tangentSign; o.tSpace2.y = unityFogFactor #define UNITY_TRANSFER_FOG_COMBINED_WITH_WORLD_POS(o,outpos) UNITY_CALC_FOG_FACTOR((outpos).z); o.worldPos.w = unityFogFactor #define UNITY_TRANSFER_FOG_COMBINED_WITH_EYE_VEC(o,outpos) UNITY_CALC_FOG_FACTOR((outpos).z); o.eyeVec.w = unityFogFactor #else // SM3.0 and PC/console: calculate fog distance per-vertex, and fog factor per-pixel #define UNITY_TRANSFER_FOG(o,outpos) o.fogCoord.x = (outpos).z #define UNITY_TRANSFER_FOG_COMBINED_WITH_TSPACE(o,outpos) o.tSpace2.y = (outpos).z #define UNITY_TRANSFER_FOG_COMBINED_WITH_WORLD_POS(o,outpos) o.worldPos.w = (outpos).z #define UNITY_TRANSFER_FOG_COMBINED_WITH_EYE_VEC(o,outpos) o.eyeVec.w = (outpos).z #endif #else #define UNITY_FOG_COORDS(idx) #define UNITY_TRANSFER_FOG(o,outpos) #define UNITY_TRANSFER_FOG_COMBINED_WITH_TSPACE(o,outpos) #define UNITY_TRANSFER_FOG_COMBINED_WITH_WORLD_POS(o,outpos) #define UNITY_TRANSFER_FOG_COMBINED_WITH_EYE_VEC(o,outpos) #endif
|
当开启Fog时
1
| #define UNITY_FOG_COORDS(idx) UNITY_FOG_COORDS_PACKED(idx, float1)
|
UNITY_FOG_COORDS_PACKED
1
| #define UNITY_FOG_COORDS_PACKED(idx, vectype) vectype fogCoord : TEXCOORD##idx;
|
可知实际 UNITY_FOG_COORDS(0) 如果Fog开启,相当一在片元数据中定义了
1
| float1 fogCoord : TEXCOORD0
|
UNITY_TRANSFER_FOG
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
| #if defined(FOG_LINEAR) || defined(FOG_EXP) || defined(FOG_EXP2) #define UNITY_FOG_COORDS(idx) UNITY_FOG_COORDS_PACKED(idx, float1)
#if (SHADER_TARGET < 30) || defined(SHADER_API_MOBILE) // mobile or SM2.0: calculate fog factor per-vertex #define UNITY_TRANSFER_FOG(o,outpos) UNITY_CALC_FOG_FACTOR((outpos).z); o.fogCoord.x = unityFogFactor #define UNITY_TRANSFER_FOG_COMBINED_WITH_TSPACE(o,outpos) UNITY_CALC_FOG_FACTOR((outpos).z); o.tSpace1.y = tangentSign; o.tSpace2.y = unityFogFactor #define UNITY_TRANSFER_FOG_COMBINED_WITH_WORLD_POS(o,outpos) UNITY_CALC_FOG_FACTOR((outpos).z); o.worldPos.w = unityFogFactor #define UNITY_TRANSFER_FOG_COMBINED_WITH_EYE_VEC(o,outpos) UNITY_CALC_FOG_FACTOR((outpos).z); o.eyeVec.w = unityFogFactor #else // SM3.0 and PC/console: calculate fog distance per-vertex, and fog factor per-pixel #define UNITY_TRANSFER_FOG(o,outpos) o.fogCoord.x = (outpos).z #define UNITY_TRANSFER_FOG_COMBINED_WITH_TSPACE(o,outpos) o.tSpace2.y = (outpos).z #define UNITY_TRANSFER_FOG_COMBINED_WITH_WORLD_POS(o,outpos) o.worldPos.w = (outpos).z #define UNITY_TRANSFER_FOG_COMBINED_WITH_EYE_VEC(o,outpos) o.eyeVec.w = (outpos).z #endif #else #define UNITY_FOG_COORDS(idx) #define UNITY_TRANSFER_FOG(o,outpos) #define UNITY_TRANSFER_FOG_COMBINED_WITH_TSPACE(o,outpos) #define UNITY_TRANSFER_FOG_COMBINED_WITH_WORLD_POS(o,outpos) #define UNITY_TRANSFER_FOG_COMBINED_WITH_EYE_VEC(o,outpos) #endif
|
因为 #pragma target 2.0 时 SHADER_TARGET <30 所以
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| #if defined(FOG_LINEAR) // factor = (end-z)/(end-start) = z * (-1/(end-start)) + (end/(end-start)) #define UNITY_CALC_FOG_FACTOR_RAW(coord) float unityFogFactor = (coord) * unity_FogParams.z + unity_FogParams.w #elif defined(FOG_EXP) // factor = exp(-density*z) #define UNITY_CALC_FOG_FACTOR_RAW(coord) float unityFogFactor = unity_FogParams.y * (coord); unityFogFactor = exp2(-unityFogFactor) #elif defined(FOG_EXP2) // factor = exp(-(density*z)^2) #define UNITY_CALC_FOG_FACTOR_RAW(coord) float unityFogFactor = unity_FogParams.x * (coord); unityFogFactor = exp2(-unityFogFactor*unityFogFactor) #else #define UNITY_CALC_FOG_FACTOR_RAW(coord) float unityFogFactor = 0.0 #endif
#define UNITY_CALC_FOG_FACTOR(coord) UNITY_CALC_FOG_FACTOR_RAW(UNITY_Z_0_FAR_FROM_CLIPSPACE(coord))
#define UNITY_TRANSFER_FOG(o,outpos) UNITY_CALC_FOG_FACTOR((outpos).z); o.fogCoord.x = unityFogFactor
|
可以追溯宏定义的运算 得到 fogCoord值,并在 UNITY_APPLY_FOG(i.fogCoord, col);得到新得col值。
备注
INSTANCE 和FOG 会在后面补充,这里只记录shader分析的一个过程。