本系列文章由@浅墨_毛星云 出品,转载请注明出处。
文章链接: http://blog.csdn.net/poem_qianmo/article/details/51764028
作者:毛星云(浅墨) 微博:http://weibo.com/u/1723155442
本文工程使用的Unity3D版本: 5.2.1
这篇文章主要讲解了如何在Unity3D中分别使用Surface Shader和Vertex & Fragment Shader来编写边缘发光Shader。
一、最终实现的效果
边缘发光Shader比较直观的一个运用便是模拟宇宙中的星球效果。将本文实现的边缘发光Shader先赋一个Material,此Material再赋给一个球体,加上Galaxy Skybox, 实现的效果如下图:
当然,边缘发光Shader也可以实现例如暗黑三中精英怪的高亮效果,将一个怪物模型本身的Shader用边缘发光Shader替代,实现效果如下图:
以下是本文实现的Shader在编辑器中的一些效果图。
二、Shader实现思路分析
思路方面,其实理解起来非常简单,就是在正常的漫反射Shader的基础之上,在最终的漫反射颜色值出来之后,再准备一个自发光颜色值,附加上去,即得到了最终的带自发光的颜色值。
按公式来表达,也就是这样:
最终颜色 = (漫反射系数 x 纹理颜色 x RGB颜色)+自发光颜色
按英文公式来表达,也就是这样:
FinalColor=(Diffuse x Texture x RGBColor)+Emissive
三、Surface Shader版边缘发光Shader实现
如果读过这个系列第一篇文章的朋友,应该还记得这个系列的第一篇文章(传送门:http://blog.csdn.net/poem_qianmo/article/details/40723789),里面的TheFirstShader,它就是一个标准的使用Unity Surface Shader实现的边缘发光Shader。
利用Unity自身的Shader封装,Surface Shader,也就是Shaderlab,算是新手或者想快速上手的童鞋学习Unity中Shader书写的一个非常好的切入点。
这边贴出经过加强的第一期TheFirstShader详细注释后的源代码。可以发现里面关于主要框架的注释都是中英双语的,因为发现不少国外友人也关注了我在Github上的Shader repo(https://github.com/QianMo/Awesome-Unity-Shader),为了方便他们以及后面更多的国外友人,以后如果周末写博客的时间充裕,就干脆写中英双语的注释得了。
OK,详细注释后的Surface Shader版可发光Shader源代码如下:
- Shader "Learning Unity Shader/Lecture 14/Surface Rim Shader"
- {
-
- Properties
- {
-
- _MainColor("【主颜色】Main Color", Color) = (0.5,0.5,0.5,1)
-
- _MainTex("【纹理】Texture", 2D) = "white" {}
-
- _BumpMap("【凹凸纹理】Bumpmap", 2D) = "bump" {}
-
- _RimColor("【边缘发光颜色】Rim Color", Color) = (0.17,0.36,0.81,0.0)
-
- _RimPower("【边缘颜色强度】Rim Power", Range(0.6,36.0)) = 8.0
-
- _RimIntensity("【边缘颜色强度系数】Rim Intensity", Range(0.0,100.0)) = 1.0
- }
-
-
- SubShader
- {
-
- Tags
- {
- "RenderType" = "Opaque"
- }
-
-
- CGPROGRAM
-
-
- #pragma surface surf Lambert
-
-
- struct Input
- {
-
- float2 uv_MainTex;
-
- float2 uv_BumpMap;
-
- float3 viewDir;
- };
-
-
-
- float4 _MainColor;
-
- sampler2D _MainTex;
-
- sampler2D _BumpMap;
-
- float4 _RimColor;
-
- float _RimPower;
-
- float _RimIntensity;
-
-
- void surf(Input IN, inout SurfaceOutput o)
- {
-
- o.Albedo = tex2D(_MainTex, IN.uv_MainTex).rgb*_MainColor.rgb;
-
- o.Normal = UnpackNormal(tex2D(_BumpMap, IN.uv_BumpMap));
-
- half rim = 1.0 - saturate(dot(normalize(IN.viewDir), o.Normal));
-
- o.Emission = _RimColor.rgb * pow(rim, _RimPower)*_RimIntensity;
- }
-
-
- ENDCG
- }
-
-
- Fallback "Diffuse"
- }
稍微琢磨一下就明白,此Shader其实就是用利用了Unity5中封装好的Standard Surface Output结构体中的Emission(自发光)属性,来达到这样的边缘光效果,技术含量很有限。这边附一下Unity5中的SurfaceOutputStandard原型:
-
- struct SurfaceOutputStandard
- {
- fixed3 Albedo;
- fixed3 Normal;
- half3 Emission;
- half Metallic;
- half Smoothness;
- half Occlusion;
- fixed Alpha;
- };
将此Shader赋给Material后在编辑器效果图:
里面有6个参数,包括主颜色、纹理、凹凸纹理、边缘发光颜色、边缘颜色强度、边缘颜色强度系数这六个参数可以定制与调节,只要贴图资源到位,就很容易可以调出自己满意的效果来。
四、可编程Shader版边缘发光Shader的实现
这篇文章核心主要就是实现本节的这个可编程版(也就是Vertex & Fragment Shader)边缘发光Shader。大家知道,Vertex & Fragment Shader是比Surface Shader更高一段位的实现形态,有更大的可控性,更好的可编程性,可以实现更加丰富的效果,是更贴近CG着色语言的一种Shader形态。
OK,直接贴出经过详细注释的Vertex & Fragment Shader版边缘发光Shader实现源代码:
- Shader "Learning Unity Shader/Lecture 14/Basic Rim Shader"
- {
-
- Properties
- {
-
- _MainColor("【主颜色】Main Color", Color) = (0.5,0.5,0.5,1)
-
- _TextureDiffuse("【漫反射纹理】Texture Diffuse", 2D) = "white" {}
-
- _RimColor("【边缘发光颜色】Rim Color", Color) = (0.5,0.5,0.5,1)
-
- _RimPower("【边缘发光强度】Rim Power", Range(0.0, 36)) = 0.1
-
- _RimIntensity("【边缘发光强度系数】Rim Intensity", Range(0.0, 100)) = 3
- }
-
-
- SubShader
- {
-
- Tags
- {
- "RenderType" = "Opaque"
- }
-
-
- Pass
- {
-
- Name "ForwardBase"
-
-
- Tags
- {
- "LightMode" = "ForwardBase"
- }
-
-
- CGPROGRAM
-
-
- #pragma vertex vert
- #pragma fragment frag
-
-
- #include "UnityCG.cginc"
- #include "AutoLight.cginc"
-
-
- #pragma target 3.0
-
-
-
- uniform float4 _LightColor0;
-
- uniform float4 _MainColor;
-
- uniform sampler2D _TextureDiffuse;
-
- uniform float4 _TextureDiffuse_ST;
-
- uniform float4 _RimColor;
-
- uniform float _RimPower;
-
- uniform float _RimIntensity;
-
-
- struct VertexInput
- {
-
- float4 vertex : POSITION;
-
- float3 normal : NORMAL;
-
- float4 texcoord : TEXCOORD0;
- };
-
-
- struct VertexOutput
- {
-
- float4 pos : SV_POSITION;
-
- float4 texcoord : TEXCOORD0;
-
- float3 normal : NORMAL;
-
- float4 posWorld : TEXCOORD1;
-
- LIGHTING_COORDS(3,4)
- };
-
-
- VertexOutput vert(VertexInput v)
- {
-
- VertexOutput o;
-
-
-
- o.texcoord = v.texcoord;
-
- o.normal = mul(float4(v.normal,0), _World2Object).xyz;
-
- o.posWorld = mul(_Object2World, v.vertex);
-
- o.pos = mul(UNITY_MATRIX_MVP, v.vertex);
-
-
- return o;
- }
-
-
- fixed4 frag(VertexOutput i) : COLOR
- {
-
-
- float3 ViewDirection = normalize(_WorldSpaceCameraPos.xyz - i.posWorld.xyz);
-
- float3 Normalection = normalize(i.normal);
-
- float3 LightDirection = normalize(_WorldSpaceLightPos0.xyz);
-
-
-
- float Attenuation = LIGHT_ATTENUATION(i);
-
- float3 AttenColor = Attenuation * _LightColor0.xyz;
-
-
- float NdotL = dot(Normalection, LightDirection);
- float3 Diffuse = max(0.0, NdotL) * AttenColor + UNITY_LIGHTMODEL_AMBIENT.xyz;
-
-
-
- half Rim = 1.0 - max(0, dot(i.normal, ViewDirection));
-
- float3 Emissive = _RimColor.rgb * pow(Rim,_RimPower) *_RimIntensity;
-
-
-
- float3 finalColor = Diffuse * (tex2D(_TextureDiffuse,TRANSFORM_TEX(i.texcoord.rg, _TextureDiffuse)).rgb*_MainColor.rgb) + Emissive;
-
-
- return fixed4(finalColor,1);
- }
-
-
- ENDCG
- }
- }
-
-
- FallBack "Diffuse"
- }
相信不少朋友已经看出来了,与普通的漫反射Shader相比,这个Shader的魔力就在于多出了“8.4准备自发光参数”和“8.5在最终颜色中加入自发光颜色"两个步骤而已,前面都是普通的Vertex & Fragment Shader常规写法。
将此Shader赋给Material,得到的效果如下:
当然,你也可以将这两个Shader用于场景中各种模型,以下是一组效果图:
OK,这篇文章的内容大致如此。我们下篇文章,再会。
附: 本文配套源码下载链接
【Github】本文Shader源码