UnityShader边缘光

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,结果作为亮度的比例即可。

UnityShader边缘光_第1张图片

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

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

学习材料:

学习shader之前必须知道的东西之计算机图形学(一)渲染管线  

你可能感兴趣的:(UnityShader边缘光)