由於博客寫到瞭插值這一塊,它是一個不大又不小的知識,這裡寫一篇簡單的博客記錄一下。稍微註意一下就是我們這裡所謂的lerp函數是針對CG/HLSL(一種Shader語法)中的lerp函數

我們先看一下它的函數簽名和定義

lerp(y_{1},y_{2},weight) = y_{1} + (y_{2} – y_{1})*weight\

從定義來看還是挺簡單的,我們主要是理解它有什麼作用。另外我們規定,weight是一個在區間[0,1]的實數,倒不是因為取更大的值之後,這個函數就無定義瞭,而是因為取更大的值,這個函數就失去瞭我們構造它的理由,另外,CG會限制weight的值在0-1的范圍內,超過這個范圍會被留在邊界0或者邊界1

這裡的y1被稱為起點,而y2被稱為終點,lerp函數就是取值y1到y2中間的一個值。取多少呢?就由weight來控制,當weight為0.5時,它正好落在起點和終點的中間。為瞭更加方便理解,我們可以把這個公式換成這種格式

lerp(y_{1},y_{2},weight) = (1 – weight) times y_{1} + weight times y_{2}\

簡單來說,lerp函數就是在y1和y2之間過渡,唯一不同的地方就是,y1和y2可以是一個值,也可以是一個函數。比如,我們可以在正弦函數和線性函數之前做過渡,我們先看一下正弦函數

再看一下最簡單的線性函數(恒等映射函數y=x)

在它倆之間做過渡,我們隻需要寫出lerp(sin(x),x,0.5)即可。當然,可以調整weight參數觀察不同的結果。

weight為0.5時:

weight為0.8時:

weight為0.2時:

是不是非常的直觀,所以這就扯到瞭Lerp函數的兩種不同的作用。

  • 構造新的函數
  • 在兩個值之間進行過度

我們可以通過Lerp函數來編寫一個簡單的Shader測試一下。

Shader "Sundry/LerpTest"{
Properties{
_BaseColor1("First Color",Color) = (1.0,1.0,1.0,1.0)
_BaseColor2("Second Color",Color) = (1.0,1.0,1.0,1.0)
_Weight("Lerp Weight",Range(0,1)) = 0.5
}

SubShader{
pass{
Tags{"LightMode"="ForwardBase"}
CGPROGRAM
#pragma vertex Vertex
#pragma fragment Pixel
#include "Lighting.cginc"

struct vertexOutput{

float4 pos : SV_POSITION;
float3 worldNormal : TEXCOORD0;
float3 worldPos : TEXCOORD1;
};

fixed4 _BaseColor1;
fixed4 _BaseColor2;
fixed _Weight;

vertexOutput Vertex(appdata_base v){

vertexOutput o;
o.pos = UnityObjectToClipPos(v.vertex);
o.worldNormal = UnityObjectToWorldNormal(v.normal);
o.worldPos = mul(unity_ObjectToWorld,v.vertex).xyz;

return o;
}

fixed4 Pixel(vertexOutput i):SV_TARGET{

fixed3 lightDir = normalize(UnityWorldSpaceLightDir(i.worldPos));
fixed3 worldNormal = normalize(i.worldNormal);

fixed3 albedo = lerp(_BaseColor1.xyz,_BaseColor2.xyz,_Weight);
//在顏色1和顏色2之間以weight過度

fixed3 ambient = UNITY_LIGHTMODEL_AMBIENT.xyz * albedo;
fixed3 diffuse = _LightColor0.xyz * albedo * saturate(dot(worldNormal,lightDir));

return fixed4(ambient + diffuse,1.0);
}

ENDCG
}
}
}