UnityShader快速上手指南(二)

簡介

前一篇介紹了若是編寫最基本的shader,接下來本文將會簡單的深刻一下,咱們先來看下效果吧

這裏寫圖片描述

呃,gif效果很差,實際效果是很平滑的動態過渡

實現思路

1.首先咱們要實現一個彩色方塊
2.讓色彩動起來
overhtml

實現一個RGB CUBE

先看代碼吧:算法

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
        }
    }
}

恩~~,首先呢,咱們此次輸出的顏色不一樣的位置顏色不一樣,因此咱們須要一個同時能存位置和顏色的結構體:c#

struct VertextOutput {
                float4 pos : SV_POSITION ; 
                // 位置信息, 後面的: SV_POSITION是必須的,固然你也能夠換成: POSITION
                fixed4 col : COLOR ;
                // 顏色信息, 後面的: COLOR不是必須的,你能夠隨便取名字好比 : FUCK
                // 可是嘛,爲了代碼方便閱讀,仍是寫成COLOR吧
            };

而後呢咱們只有這樣一個模型:
這裏寫圖片描述
24個頂點(每一個面頂點單算的),12個三角形,兩個空的UV(這個是unity自帶的cube模型)
這個模型是沒有任何顏色信息,因此咱們須要本身在shader中生成他的顏色
出於方便考慮,咱們將這個模型的頂點(XYZ)變成RGB的顏色,由於恰好三個值都有變化嘛
因而有了這樣的代碼
result.col = input.vertex + float4( _OffsetX, _OffsetY, _OffsetZ, 0);
前面頂點位置就不做處理了,直接換算成Unity座標就完了
result.pos = mul(UNITY_MATRIX_MVP , input.vertex ) ;app

而後咱們來講說傳入參數中的appdata_base
對於VertextOutput vert ( appdata_base input )這個函數命名
學過C語言的應該知道前面是返回值類型 括號裏面是傳入值類型和名字吧
而後這個appdata_base呢是定義在#include "UnityCG.cginc"的一個結構體
(強行帶節奏引入了UnityCG.cginc,其實也能夠像前面一篇同樣使用float4 position : POSITION,只是這裏爲了早點引入UnityCG.cginc而已)
咱們能夠看一下UnityCG.cginc的部分代碼:ide

// 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;
};

整個有點小長,我只粘貼一部分,其實就是一大堆Unity的定義而已,
咱們再來看看函數

struct appdata_base {
    float4 vertex : POSITION; //位置
    float3 normal : NORMAL; //法線
    float4 texcoord : TEXCOORD0; // 紋理
};

其實這是一個簡化的模型數據,包含了一些經常使用的參數,若是咱們寫的shader主要是給手機使用的話,這些數據基本也就夠了,並且目前咱們也就用了他的位置的信息,固然你也能夠傳入一個appdata_full 類型,區別不大性能

至於_OffsetX,_OffsetY,_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;
            }

計算出了相應頂點的顏色
而後直接在面片渲染函數中把對應點的顏色賦值給他就好了
return input.col;
注意這裏咱們的傳入參數變成了vert 的返回值
fixed4 frag ( VertextOutput input ) : COLORui

好來看下初步的效果:
這裏寫圖片描述
這裏咱們就完成了一個RBG CUBE了。
下面對一些原理性的東西簡單解釋一下spa

光柵化?插值?

前面我解釋過vert函數是一個頂點調用一次,這裏咱們的模型一共才24個頂點,可是爲啥出來這麼多個顏色呢,這裏就跟渲染流程的光柵化有關。默認狀況下,光柵化會保持平滑過渡,若是兩邊不匹配就會在中間插值,而後對於咱們的模型而言,一個面上每一個頂點的顏色都不一樣,因此他就會自動插入不少個頂點,而且自動漸變顏色來知足平滑過渡(也就是說若是你顏色都同樣,就不會插點了,固然你也能夠手動不讓它插點,概念比較多,這裏就不展開了,咱們要快速上手嘛)

讓顏色隨着時間變化而變化

這裏是我強行要加的一個功能,否則感受這篇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);

呃,對,就改這一行。效果就是實現啦,你們能夠本身行試一下
下面解釋一小下下:
_SinTime是unity爲shader內置的一個時間的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 -1.0, negative if currently rendering with a flipped projection matrix 
x爲1.0 或者-1.0若是當前渲染使用的是一個反轉的投影矩陣那麼爲負。 
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
有了這些東西以後呢,咱們就能夠簡單的根據時間變化作一些動態shader了,好比什麼UV流動啊,顏色動態變化啊,動態模型(是動態模型不是模型動畫哈)啥的,瞬間就高大上了有不有,性能嘛取決於你寫的代碼(一樣的代碼級別下,shader速度秒殺你在c#中寫)

總結

這一篇感受寫的比較亂,主要是知識點比較雜(這理由不是很好找啊....原諒我語文老師是數學老師教大的) 主要知識點是介紹一下光柵化那個插值,這個很重要https://en.wikibooks.org/wiki/Cg_Programming/Rasterization(雖然我講的一筆帶過,你們去看看官方解釋吧) 而後介紹一下UnityCG.cginc,咱們既然是寫的unityshader,固然仍是要常用這個庫的啦,後面還有光照,空間矩陣啥的,基本咱們要想作高級特效離不開這個庫的,你們能夠去看看這個庫源碼 瞭解了這些以後,就是單純的算法了(好比怎麼經過時間更改模型頂點位置實現好看的動畫啥的) 恩~~~再次坦白下寫的比較亂,若有疑問歡迎聯繫QQ:821580467一塊兒探討

相關文章
相關標籤/搜索