您的位置:首页 > 移动开发 > Unity3D

UnityShader边缘光

2017-08-30 17:13 399 查看
SurfaceOutput数据结构

struct SurfaceOutput
{
fixed3 Albedo;  // diffuse color
fixed3 Normal;  // tangent space normal, if written
fixed3 Emission;
half Specular;  // specular power in 0..1 range
fixed Gloss;    // specular intensity
fixed Alpha;    // alpha for transparencies
};

官方shader文档 https://docs.unity3d.com/Manual/SL-SurfaceShaderExamples.html 中的样例Rim Lighting代码如下

Shader "Custom/MyShader" {
Properties{
_MainTex("Texture", 2D) = "white" {}
_BumpMap("Bumpmap", 2D) = "bump" {}
_RimColor("Rim Color", Color) = (0.26,0.19,0.16,0.0)
_RimPower("Rim Power", Range(0.5,8.0)) = 3.0
}
SubShader{
Tags{ "RenderType" = "Opaque" }
CGPROGRAM
#pragma surface surf Lambert
struct Input {
float2 uv_MainTex;
float2 uv_BumpMap;
float3 viewDir;
};
sampler2D _MainTex;
sampler2D _BumpMap;
float4 _RimColor;
float _RimPower;
void surf(Input IN, inout SurfaceOutput o) {
o.Albedo = tex2D(_MainTex, IN.uv_MainTex).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);
}
ENDCG
}
Fallback "Diffuse"
}

对渲染流水线不了解的话会比较难理解以下这两句,这两句是实现边缘光的关键。

half rim = 1.0 - saturate(dot(normalize(IN.viewDir), o.Normal));
o.Emission = _RimColor.rgb * pow(rim, _RimPower);
在摄像机空间也就是view空间,lookat的位置减去eyes的位置也就是viewdir向量,是view空间的z轴正方向。经过normalize后,向量长度变为1,同时方向不变。与相应的物体上点的法向量点乘,相当于得到法向量方向和viewDir的余弦值。这样就知道该点与视线的夹角。因为目的是边缘发光,边缘的特点就是刚才点乘的结果为余弦90度,也就是0。而球体的中心点,与viewdir点乘的结果为绝对值为1。接着同样作为减数,用1减去这两个,得到1和0,结果作为亮度的比例即可。



把对应的rim值乘上一个强度的次方,乘上相应的颜色,赋值给Emission。中心红点不发光,而边缘的值会发出最强的光,中间的即为过渡部分。结果如下


表面着色器的边缘光两三句代码就实现了,有兴趣的可以去试一下用顶点片元着色器来实现边缘光。如果弄清楚渲染管道,那应该不算很复杂的功能,网上也有用顶点片元着色器实现边缘光的文章。

学习材料:

学习shader之前必须知道的东西之计算机图形学(一)渲染管线  
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: