ObjectOutline.shader 4.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203
  1. Shader "Custom/ObjectOutline" {
  2. Properties{
  3. _Diffuse("Diffuse", Color) = (1,1,1,1)
  4. _OutlineCol("OutlineCol", Color) = (1,0,0,1)
  5. _OutlineFactor("OutlineFactor", Range(0,1)) = 0.1
  6. _MainTex("Base 2D", 2D) = "white"{}
  7. }
  8. //子着色器
  9. SubShader
  10. {
  11. //描边使用两个Pass,第一个pass沿法线挤出一点,只输出描边的颜色
  12. Pass
  13. {
  14. //剔除正面,只渲染背面,对于大多数模型适用,不过如果需要背面的,就有问题了
  15. Cull Front
  16. CGPROGRAM
  17. //使用vert函数和frag函数
  18. #pragma vertex vert
  19. #pragma fragment frag
  20. #include "UnityCG.cginc"
  21. fixed4 _OutlineCol;
  22. float _OutlineFactor;
  23. struct v2f
  24. {
  25. float4 pos : SV_POSITION;
  26. };
  27. v2f vert(appdata_full v)
  28. {
  29. v2f o;
  30. //在vertex阶段,每个顶点按照法线的方向偏移一部分,不过这种会造成近大远小的透视问题
  31. //v.vertex.xyz += v.normal * _OutlineFactor;
  32. o.pos = UnityObjectToClipPos(v.vertex);
  33. //将法线方向转换到视空间
  34. float3 vnormal = mul((float3x3)UNITY_MATRIX_IT_MV, v.normal);
  35. //将视空间法线xy坐标转化到投影空间,只有xy需要,z深度不需要了
  36. float2 offset = TransformViewToProjection(vnormal.xy);
  37. //在最终投影阶段输出进行偏移操作
  38. o.pos.xy += offset * _OutlineFactor;
  39. return o;
  40. }
  41. fixed4 frag(v2f i) : SV_Target
  42. {
  43. //这个Pass直接输出描边颜色
  44. return _OutlineCol;
  45. }
  46. ENDCG
  47. }
  48. //正常着色的Pass
  49. Pass
  50. {
  51. CGPROGRAM
  52. //使用vert函数和frag函数
  53. #pragma vertex vert
  54. #pragma fragment frag
  55. //引入头文件
  56. #include "Lighting.cginc"
  57. //定义Properties中的变量
  58. fixed4 _Diffuse;
  59. sampler2D _MainTex;
  60. //使用了TRANSFROM_TEX宏就需要定义XXX_ST
  61. float4 _MainTex_ST;
  62. //定义结构体:vertex shader阶段输出的内容
  63. struct v2f
  64. { float4 pos : SV_POSITION;
  65. float3 worldNormal : TEXCOORD0;
  66. float2 uv : TEXCOORD1;
  67. };
  68. //定义顶点shader,参数直接使用appdata_base(包含position, noramal, texcoord)
  69. v2f vert(appdata_base v)
  70. {
  71. v2f o;
  72. o.pos = UnityObjectToClipPos(v.vertex);
  73. //通过TRANSFORM_TEX宏转化纹理坐标,主要处理了Offset和Tiling的改变,默认时等同于o.uv = v.texcoord.xy;
  74. o.uv = TRANSFORM_TEX(v.texcoord, _MainTex);
  75. o.worldNormal = mul(v.normal, (float3x3)unity_WorldToObject);
  76. return o;
  77. }
  78. //定义片元shader
  79. fixed4 frag(v2f i) : SV_Target
  80. {
  81. //unity自身的diffuse也是带了环境光,这里我们也增加一下环境光
  82. fixed3 ambient = UNITY_LIGHTMODEL_AMBIENT.xyz * _Diffuse.xyz;
  83. //归一化法线,即使在vert归一化也不行,从vert到frag阶段有差值处理,传入的法线方向并不是vertex shader直接传出的
  84. fixed3 worldNormal = normalize(i.worldNormal);
  85. //把光照方向归一化
  86. fixed3 worldLightDir = normalize(_WorldSpaceLightPos0.xyz);
  87. //根据半兰伯特模型计算像素的光照信息
  88. fixed3 lambert = 0.5 * dot(worldNormal, worldLightDir) + 0.5;
  89. //最终输出颜色为lambert光强*材质diffuse颜色*光颜色
  90. fixed3 diffuse = lambert * _Diffuse.xyz * _LightColor0.xyz + ambient;
  91. //进行纹理采样
  92. fixed4 color = tex2D(_MainTex, i.uv);
  93. color.rgb = color.rgb* diffuse;
  94. return fixed4(color);
  95. }
  96. ENDCG
  97. }
  98. }
  99. //前面的Shader失效的话,使用默认的Diffuse
  100. FallBack "Diffuse"
  101. }