關於Unity中Cg的基本語法和使用


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變紅色

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM