前1篇介紹了如果編寫最基本的shader,接下來本文將會簡單的深入1下,我們先來看下效果吧
呃,gif效果不好,實際效果是很平滑的動態過渡
1.首先我們要實現1個彩色方塊
2.讓色采動起來
over
先看代碼吧:
Shader "LT/Lesson2"
{
Properties {
_OffsetX ("Offset X", Range (-1.5, 1.5) ) = 0
_OffsetY ("Offset Y", Range (-1.5, 1.5) ) = 0
_OffsetZ ("Offset Z", Range (-1.5, 1.5) ) = 0
}
SubShader
{
Pass
{
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "UnityCG.cginc"
struct VertextOutput {
float4 pos : SV_POSITION ;
fixed4 col : COLOR ;
};
uniform float _OffsetX;
uniform float _OffsetY;
uniform float _OffsetZ;
VertextOutput vert ( appdata_base input )
{
VertextOutput result;
result.pos = mul(UNITY_MATRIX_MVP , input.vertex ) ;
result.col = input.vertex + float4( _OffsetX, _OffsetY, _OffsetZ, 0);
return result;
}
fixed4 frag ( VertextOutput input ) : COLOR
{
return input.col;
}
ENDCG
}
}
}
恩~~,首先呢,我們這次輸出的色彩不同的位置色彩不同,所以我們需要1個同時能存位置和色彩的結構體:
struct VertextOutput {
float4 pos : SV_POSITION ;
// 位置信息, 后面的: SV_POSITION是必須的,固然你也能夠換成: POSITION
fixed4 col : COLOR ;
// 色彩信息, 后面的: COLOR不是必須的,你可以隨意取名字比如 : FUCK
// 但是嘛,為了代碼方便瀏覽,還是寫成COLOR吧
};
然后呢我們只有這樣1個模型:
24個頂點(每一個面頂點單算的),12個3角形,兩個空的UV(這個是unity自帶的cube模型)
這個模型是沒有任何色彩信息,所以我們需要自己在shader中生成他的色彩
出于方便斟酌,我們將這個模型的頂點(XYZ)變成RGB的色彩,由于恰好3個值都有變化嘛
因而有了這樣的代碼
result.col = input.vertex + float4( _OffsetX, _OffsetY, _OffsetZ, 0);
前面頂點位置就不作處理了,直接換算成Unity坐標就完了
result.pos = mul(UNITY_MATRIX_MVP , input.vertex ) ;
然后我們來講說傳入參數中的appdata_base
對VertextOutput vert ( appdata_base input )這個函數命名
學過C語言的應當知道前面是返回值類型 括號里面是傳入值類型和名字吧
然后這個appdata_base呢是定義在#include “UnityCG.cginc”的1個結構體
(強行帶節奏引入了UnityCG.cginc,其實也能夠像前面1篇1樣使用float4 position : POSITION,只是這里為了早點引入UnityCG.cginc而已)
我們可以看1下UnityCG.cginc的部份代碼:
// Dynamic & Static lightmaps contain indirect diffuse ligthing, thus ignore SH
#define UNITY_SHOULD_SAMPLE_SH ( defined (LIGHTMAP_OFF) && defined(DYNAMICLIGHTMAP_OFF) )
struct appdata_base {
float4 vertex : POSITION;
float3 normal : NORMAL;
float4 texcoord : TEXCOORD0;
};
struct appdata_tan {
float4 vertex : POSITION;
float4 tangent : TANGENT;
float3 normal : NORMAL;
float4 texcoord : TEXCOORD0;
};
struct appdata_full {
float4 vertex : POSITION;
float4 tangent : TANGENT;
float3 normal : NORMAL;
float4 texcoord : TEXCOORD0;
float4 texcoord1 : TEXCOORD1;
float4 texcoord2 : TEXCOORD2;
float4 texcoord3 : TEXCOORD3;
#if defined(SHADER_API_XBOX360)
half4 texcoord4 : TEXCOORD4;
half4 texcoord5 : TEXCOORD5;
#endif
fixed4 color : COLOR;
};
全部有點小長,我只粘貼1部份,其實就是1大堆Unity的定義而已,
我們再來看看
struct appdata_base {
float4 vertex : POSITION; //位置
float3 normal : NORMAL; //法線
float4 texcoord : TEXCOORD0; // 紋理
};
其實這是1個簡化的模型數據,包括了1些經常使用的參數,如果我們寫的shader主要是給手機使用的話,這些數據基本也就夠了,而且目前我們也就用了他的位置的信息,固然你也能夠傳入1個appdata_full 類型,區分不大
至于_OffsetX,_OffsetY,_OffsetZ3個外接屬性的定義就不多做贅述了
然后我們就通過
VertextOutput vert ( appdata_base input )
{
VertextOutput result;
result.pos = mul(UNITY_MATRIX_MVP , input.vertex ) ;
result.col = input.vertex + float4( _OffsetX, _OffsetY, _OffsetZ, 0);
return result;
}
計算出了相應頂點的色彩
然后直接在面片渲染函數中把對應點的色彩賦值給他就好了
return input.col;
注意這里我們的傳入參數變成了vert 的返回值
fixed4 frag ( VertextOutput input ) : COLOR
好來看下初步的效果:
這里我們就完成了1個RBG CUBE了。
下面對1些原理性的東西簡單解釋1下
前面我解釋過vert函數是1個頂點調用1次,這里我們的模型1共才24個頂點,但是為啥出來這么多個色彩呢,這里就跟渲染流程的光柵化有關。默許情況下,光柵化會保持平滑過渡,如果兩邊不匹配就會在中間插值,然后對我們的模型而言,1個面上每一個頂點的色彩都不同,所以他就會自動插入很多個頂點,并且自動漸變色彩來滿足平滑過渡(也就是說如果你色彩都1樣,就不會插點了,固然你也能夠手動不讓它插點,概念比較多,這里就不展開了,我們要快速上手嘛)
這里是我強行要加的1個功能,不然感覺這篇blog就太少內容咯,哈哈
有兩種實現方法:
1.unity中通過C#代碼去控制剛才開放出來的參數
2.shader中自己通過時間去更改色彩
我們既然是學shader,固然是在shader中進行更改啦
直接上代碼:
result.col = input.vertex + float4( _SinTime.w + 0.5, _SinTime.w + 0.5, _SinTime.w + 0.5, 0);
呃,對,就改這1行。效果就是實現啦,大家可以自己行試1下
下面解釋1小下下:
_SinTime是unity為shader內置的1個時間的sin值得變量(看名字也看的出來吧)
需要引入#include “UnityCG.cginc” (這也是為啥我前面強行帶節奏的緣由)
然后來普及下Unity為我們內置了哪些東西吧:
Transformations 變換
float4x4 UNITY_MATRIX_MVP
Current model*view*projection matrix
當前物體*視*投影矩陣。(注:物體矩陣為 本地->世界)
float4x4 UNITY_MATRIX_MV
Current model*view matrix
當前物體*視矩陣
float4x4 UNITY_MATRIX_P
Current projection matrix
當前物體*投影矩陣
float4x4 UNITY_MATRIX_T_MV
Transpose of model*view matrix
轉置物體*視矩陣
float4x4 UNITY_MATRIX_IT_MV
Inverse transpose of model*view matrix
逆轉置物體*視矩陣
float4x4 UNITY_MATRIX_TEXTURE0 to UNITY_MATRIX_TEXTURE3
Texture transformation matrices
貼圖變換矩陣
float4x4 _Object2World
Current model matrix
當前物體矩陣
float4x4 _World2Object
Inverse of current world matrix
物體矩陣的逆矩陣
float3 _WorldSpaceCameraPos
World space position of the camera
世界坐標空間中的攝像機位置
float4 unity_Scale
xyz components unused; .w contains scale for uniformly scaled objects.
不適用xyz份量,而是通過w份量包括的縮放值等比縮放物體。
_ModelLightColor float4 Material's Main * Light color 材質的主色彩*燈光色彩
_SpecularLightColor float4 Material's Specular * Light color 材質的鏡面反射(高光)*燈光色彩。
_ObjectSpaceLightPos float4 Light's position in object space. w component is 0 for directional lights, 1 for other lights
物體空間中的燈光為,平行光w份量為零其燈光為1;
_Light2World float4x4 Light to World space matrix 燈光轉世界空間矩陣
_World2Light float4x4 World to Light space matrix 世界轉燈光空間矩陣
_Object2Light float4x4 Object to Light space matrix 物體轉燈光空間矩陣
float4 _Time : Time (t/20, t, t*2, t*3), use to animate things inside the shaders
時間: 用于Shasder中可動畫的地方。
float4 _SinTime : Sine of time: (t/8, t/4, t/2, t)
時間的正弦值。
float4 _CosTime : Cosine of time: (t/8, t/4, t/2, t)
時間的余弦值
float4 _ProjectionParams : 投影參數
x is 1.0 or ⑴.0, negative if currently rendering with a flipped projection matrix
x為1.0 或⑴.0如果當前渲染使用的是1個反轉的投影矩陣那末為負。
y is camera's near plane y是攝像機的近剪裁平面
z is camera's far plane z是攝像機遠剪裁平面
w is 1/FarPlane. w是1/遠剪裁平面
float4 _ScreenParams : 屏幕參數
x is current render target width in pixels x是當前渲染目標在像素值中寬度
y is current render target height in pixels y是當前渲染目標在像素值中的高度
z is 1.0 + 1.0/width z是1.0+1.0/寬度
w is 1.0 + 1.0/height w是1.0+1.0/高度
呃,格式不是很好看的模樣,這里有鏈接,自己去看吧http://www.ceeger.com/Components/SL-BuiltinValues.html
有了這些東西以后呢,我們就能夠簡單的根據時間變化做1些動態shader了,比如甚么UV活動啊,色彩動態變化啊,動態模型(是動態模型不是模型動畫哈)啥的,瞬間就高大上了有不有,性能嘛取決于你寫的代碼(一樣的代碼級別下,shader速度秒殺你在c#中寫)
這1篇感覺寫的比較亂,主要是知識點比較雜(這理由不是很好找啊….諒解我語文老師是數學老師教大的)
主要知識點是介紹1下光柵化那個插值,這個很重要https://en.wikibooks.org/wiki/Cg_Programming/Rasterization(雖然我講的1筆帶過,大家去看看官方解釋吧)
然后介紹1下UnityCG.cginc,我們既然是寫的unityshader,固然還是要常常使用這個庫的啦,后面還有光照,空間矩陣啥的,基本我們要想做高級殊效離不開這個庫的,大家可以去看看這個庫源碼
了解了這些以后,就是單純的算法了(比如怎樣通過時間更改模型頂點位置實現好看的動畫啥的)
恩~~~再次坦白下寫的比較亂,如有疑問歡迎聯系QQ:8215804671起探討