Cg是類似於C語言的發展起來的圖形編程語言,Cgraphics,它的很多表達式if...else...和C語言非常相像,也和C#非常相像。
由於Shader是寫給顯卡執行的,所以沒有輸出語句來調試,很多地方調試不了,只能靠Unity編輯器來幫我們報錯,寫起來一定要小心謹慎。
基本類型表達式
1:語法和C語言類是,有對應的編譯器,程序是給顯卡運行;
2: 可以從渲染流水線中獲得對應的輸入;
3: 指定的輸出能流入下一個流水線模塊;
4: 操作符號和C語言一樣,可以使用 +, -, * / <, >, <=, >= 等運算;
5: Cg提供了float half double 浮點類型;單精度,半精度,雙精度
7: Cg 支持定點數 fixed來高效處理 某些小數;
8: Cg使用int來表示整數;
9: bool 數據類型來表示邏輯類型;
10:sampler*,紋理對象的句柄, sampler/1D/2D/3D/CUBE/RECT,往shader里面關聯一個圖片,關聯紋理Texture,使用sampler
11: 內置向量數據類型: float4(float, float, float, float), 向量長度不能超過4;
12: 內置矩陣數據類型: float1x1 float2x3 float4x3 float4x4;不能超過4x4;
13: 數組類型float a[10]; 10個float, float4 b[10], 10個float4;
14: 語義綁定 float4 a : POSITION,返回值也可以語義綁定;獲得上一個工位的數據和流向下一個工位的輸出。只有綁定語義如Position,上一個工位才知道要傳頂點的位置給它。
fixed定點數:如有一個32bit的Int,我要把前面16位表示整數,后面16位表示小數,用來存放35.4這個數,這個數據類型叫做定點數。實質是用整數表示小數,因為35.4輸出的時候是一個比較大的整數,而它的內容里面可以表示小數。
定點數的加減法實際上也就是整數的加減法,性能比浮點數好,顏色就是用fixed類型表示fixed4。
結構體與語義
1: struct name {
類型 名字;
// 盡量不要使用;
返回值 函數名稱(參數) { // 如果成員函數里面使用,數據成員,該成員定義在函數前;
}
};
2:輸入語義與輸出語義:
語義: 一個階段處理數據,然后傳輸給下一個階段,那么每個階段之間的接口, 例如:頂點處理器的輸入數據是處於模型空間的頂點數據(位置、法向量),輸出的是投影坐標和光照顏色;片段處理器要將光照顏色做為輸入;C/C++用指針,而Cg通過語義綁定的形式;
輸入語義: 綁定接收參數,從上一個流水線獲得參數;
輸出語義: 綁定輸出參數到下一個流水線模塊;
語義: 入口函數上有意義(頂點着色入口,像素着色入口),普通的函數無意義;
常用語義修飾
1:POSITION : 位置
2:TANGENT : 切線
3: NORMAL: 法線
4: TEXCOORD0: 第一套紋理
5: TEXCOORD1: 第二套紋理
6: TEXCOORD2: 第三套紋理
7: TEXCOORD3: 第四套紋理
8: COLOR: 顏色
標准內置函數
1:abs(num)絕對值;
2: 三角函數;
3: cross(a, b) 兩個向量的叉積;
4: determinant(M)矩陣的行列式;
5: dot(a, b) 兩個向量的點積;
6: floor(x)向下取整;
7: lerp(a, b, f), 在a, b之間線性插值;
8: log2(x) 基於2為底的x的對數;
9: mul(m, n): 矩陣x矩陣, 矩陣x向量, 向量x矩陣;
10: power(x, y) x的y次方;
11: radians(x) 度轉弧度;
12: reflect(v, n) v 關於法線n的反射向量;
13: round(x) 靠近取整;
14: tex2D(smapler, x) 二維紋理查找
15: tex3Dproj(smapler, x) 投影三維紋理查找;
16: texCUBE 立方體貼圖紋理查找;
Unity自帶函數
1: 引用Unity自帶的函數庫: #include “UnityCG.cginc” Unity-->Edit-->Data-->CGIncludes;
2: TRANSFORM_TEX: 根據頂點的紋理坐標,計算出對應的紋理的真正的UV坐標;
3: 使用屬性的變量: 在shader里面需要使用屬性變量還需要在shader中定義一下這個變量的類型和名字;
名字要保持一致;
4: 外部修改shader的編輯器上的參數值;
例子:打開上次的那個MyShader
1.使用編輯器的顏色對物體進行着色
Shader "Custom/MyShader" { // 屬性,可以在編輯器里面bind和修改的; Properties { _Color ("Color", Color) = (1,1,1,1) _MainTex ("Albedo (RGB)", 2D) = "white" {} _Glossiness ("Smoothness", Range(0,1)) = 0.5 _Metallic ("Metallic", Range(0,1)) = 0.0 } SubShader { Pass { CGPROGRAM // 插入Cg代碼開始 fixed4 _Color; //必須定義同樣的變量才能使用它 #pragma vertex my_vert // 把my_vert作為頂shader的入口 // 怎么樣獲得這個上一個工位的參數; -->語義bind float4 my_vert(float4 pos : POSITION) : POSITION { return mul(UNITY_MATRIX_MVP, pos); } #pragma fragment my_frag fixed4 my_frag() : COLOR{ return _Color;//使用編輯器選擇的顏色,着色物體 } ENDCG // 插入Cg代碼結束 } } FallBack "Diffuse" }
2.使用編輯器的紋理對物體進行繪制
Shader "Custom/MyShader" { // 屬性,可以在編輯器里面bind和修改的; Properties { _Color ("Color", Color) = (1,1,1,1) _MainTex ("Albedo (RGB)", 2D) = "white" {} _Glossiness ("Smoothness", Range(0,1)) = 0.5 _Metallic ("Metallic", Range(0,1)) = 0.0 } SubShader { Pass { CGPROGRAM // 插入Cg代碼開始 //fixed4 _Color; // 定義同樣的變量 sampler2D _MainTex; // 定義同樣名字的變量; #pragma vertex my_vert // 把my_vert作為頂shader的入口 // 怎么樣獲得這個上一個工位的參數; -->語義bind float4 my_vert(float4 pos : POSITION) : POSITION { return mul(UNITY_MATRIX_MVP, pos); } #pragma fragment my_frag fixed4 my_frag(float2 uv : TEXCOORD0) : COLOR{ //return _Color;//使用編輯器選擇的顏色,着色物體 return tex2D(_MainTex, uv);//根據uv來查到紋理並返回,我的理解是返回的東西就幫我們繪制了。uv---->_MainTex---->tex2D---->放回tex2D } ENDCG // 插入Cg代碼結束 } } FallBack "Diffuse" }
編寫好代碼后把貼圖拖進材質球MyShader的紋理屬性中,視圖中就顯示出對應的紋理貼圖。
3.定義結構體和函數來使用
Shader "Custom/MyShader" { // 屬性,可以在編輯器里面bind和修改的; Properties { _Color ("Color", Color) = (1,1,1,1) _MainTex ("Albedo (RGB)", 2D) = "white" {} _Glossiness ("Smoothness", Range(0,1)) = 0.5 _Metallic ("Metallic", Range(0,1)) = 0.0 } SubShader { Pass { CGPROGRAM // 插入Cg代碼開始 struct my_struct { int a; }; float sum(float a, float b) { return a + b; } fixed4 _Color; // 定義同樣的變量 #pragma vertex my_vert // 把my_vert作為頂shader的入口 // 怎么樣獲得這個上一個工位的參數; -->語義bind float4 my_vert(float4 pos : POSITION) : POSITION { return mul(UNITY_MATRIX_MVP, pos); } #pragma fragment my_frag fixed4 my_frag() : COLOR{ return _Color; } ENDCG // 插入Cg代碼結束 } } FallBack "Diffuse" }
4.語義綁定可以綁定一個結構體,在結構體里面再指定哪個屬性。Unity其實給我們定義了很多常用的結構體,可以直接使用,在 “UnityCG.cginc” Unity-->Edit-->Data-->CGIncludes;里面查看
Shader "Custom/MyShader" { // 屬性,可以在編輯器里面bind和修改的; Properties { _Color ("Color", Color) = (1,1,1,1) _MainTex ("Albedo (RGB)", 2D) = "white" {} _Glossiness ("Smoothness", Range(0,1)) = 0.5 _Metallic ("Metallic", Range(0,1)) = 0.0 } SubShader { Pass { CGPROGRAM // 插入Cg代碼開始 fixed4 _Color; // 定義同樣的變量 //結構體包裝語義 struct my_vert_data { float4 pos : POSITION; }; #pragma vertex my_vert // 把my_vert作為頂shader的入口 // 怎么樣獲得這個上一個工位的參數; -->語義bind float4 my_vert(my_vert_data data) : POSITION { return mul(UNITY_MATRIX_MVP, data.pos); } #pragma fragment my_frag fixed4 my_frag(float2 uv : TEXCOORD0) : COLOR{ return _Color; } ENDCG // 插入Cg代碼結束 } } FallBack "Diffuse" }
使用C#腳本來控制和編寫shader
0.shader文件里面的代碼是這樣的:
Shader "Custom/MyShader" { // 屬性,可以在編輯器里面bind和修改的; Properties { _Color ("Color", Color) = (1,1,1,1) _MainTex ("Albedo (RGB)", 2D) = "white" {} _Glossiness ("Smoothness", Range(0,1)) = 0.5 _Metallic ("Metallic", Range(0,1)) = 0.0 } SubShader { Pass { CGPROGRAM // 插入Cg代碼開始 fixed4 _Color; //必須定義同樣的變量才能使用它 #pragma vertex my_vert // 把my_vert作為頂shader的入口 // 怎么樣獲得這個上一個工位的參數; -->語義bind float4 my_vert(my_vert_data data) : POSITION { return mul(UNITY_MATRIX_MVP, data.pos); } #pragma fragment my_frag fixed4 my_frag() : COLOR{ return _Color;//使用編輯器選擇的顏色,着色物體 } ENDCG // 插入Cg代碼結束 } } FallBack "Diffuse" }
1.創建一個叫shader_ctrl的腳本
2.掛載到Cube節點下,這個Cube的材質屬性就是Myshader材質球,Myshader材質球的shader屬性是MyShader.shader文件
3.打開shader_ctrl的腳本,內容如下(記得關聯public 材質屬性):
using UnityEngine; using System.Collections; public class shader_ctrl : MonoBehaviour { public Material material; // Use this for initialization void Start () { material.SetColor("_Color", new Color(1.0f, 0.0f, 0.0f, 1.0f));//修改顏色為紅色 } // Update is called once per frame void Update () { } }
4.運行,發現cube變紅色
