1. 程式人生 > >Unity&Shader基礎篇-“Hello Cg”

Unity&Shader基礎篇-“Hello Cg”

1.3.1、從簡單的模板程式開始

1、開啟Unity程式,在Project中選擇Create 選擇Shader>Unlit Shader。程式的名字最好和shader的用途有關聯,讓人一看就知道這個shader是用來做什麼的。

2、將下面的模板程式複製到這個新建的Shader程式檔案中,替換Unity自動生成的程式碼。程式註釋部分給出了每一行程式碼的含義。

Shader "Cg Minimal shader" { // 定義Shader的名字,這個名字胡出現控制面	//板上作為材質的shader程式索引,還可以通過加“/”來將shader程式歸類
	//如:Custom/Cg Minimal shader
   SubShader { // 一個Shader有多個SubShader,Unity會自動選擇最合適的
      Pass { // 一個SubShader有多個Pass塊
         CGPROGRAM // Unity的Cg程式預編譯命令
         #pragma vertex vert 
            // 定義一個頂點著色器程式名字為vert
         #pragma fragment frag
            // 定義一個片段著色器程式名字為frag
         float4 vert(float4 vertexPos : POSITION) : SV_POSITION 
            // 頂點著色器程式,引數進行語義繫結 
	//POSITION為輸入繫結,SV_POSITION為輸出繫結
         {
            return mul(UNITY_MATRIX_MVP, vertexPos);
               // 用內建的矩陣UNITY_MATRIX_MVP轉變頂點著色器程式的輸入資料 	      //vertexPos並返回這個轉變之後的資料,之後它將作為片段
             // 著色器程式的輸入引數 
         }

         float4 frag(void) : COLOR // 片段著色器,它的輸入語義這裡用了Void
				   //表示接受所有的型別,你還可以換成和頂點、				//程式的輸入一樣的語義
			//float4 vertexPos : POSITION(SV_POSITION)
				    //用COLOR進行輸出語義繫結
         {
            return float4(1.0, 0.0, 0.0, 1.0); 
            		
         }

         ENDCG // 結束Cg程式的預編譯命令
      }
   }
}

3、建立一個材質球,Unity中有多種方式來對這個材質球進行shader程式繫結,推薦使用一個簡便的方式,可以在建立材質球的時候,選擇你要繫結的shader程式,然後點Create>Material。這是最方便直接的方式,不僅名字會保持和shader檔名一樣,同時還將此shader同材質進行了繫結,其他的方式都比較繁瑣。

4、建立一個Cube並將這個材質球賦給這個Cube,Cube顯示為完全的紅色,如果不是則說明這個Shader程式沒有被編譯,此時只需要關閉並重新開啟即可。

注:本文中規定Shader即為頂點著色器和片段著色器,在別的文章中Shader只是頂點著色器和片段著色器中的一個。

1.3.2、Unity中頂點和片段程式的輸入輸出

1、頂點程式的輸入引數繫結:在上一小節中頂點程式vert中通過SV_POTION進行了輸出語義繫結,返回的值即為片段程式的輸入引數,那麼頂點程式的輸入引數是從哪裡來的呢?在Unity中頂點程式的輸入引數來自於一個物體的Mesh Render元件,每一幀它會自動將物體的所有mesh資料傳送給GPU,這個就是所謂的drawcall。mesh即物體模型的網格,如果網格數少,draw call自然就會減少。網格上的資料包括位置、法線、顏色等資訊。這些資訊都有對應的語義詞,可以通過語義詞進行繫結。定義結構體的方法進行頂點程式輸入語義繫結,如:
struct vertexInput {
         float4 vertex : POSITION; // 模型空間的位置
         float4 tangent : TANGENT;  
            // 模型表面的切線
         float3 normal : NORMAL; // 模型表面的法線,它通常是單位長度
         float4 texcoord : TEXCOORD0;  // 第0套貼圖座標 
            		// (也稱為UV座標,範圍在0~1之間) 
         float4 texcoord1 : TEXCOORD1; // 第1套貼圖座標,
         fixed4 color : COLOR; // 顏色
      };

2、Unity中內建的輸入引數結構體:Unity中內建了一些頂點程式的輸入引數的結構體,在Unity>Editor>Data>CGInclude>UnityCG.cginc檔案中可找到,

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;
      fixed4 color : COLOR;
      // 多個貼圖UV座標並不是在每一個顯示卡上都支援
   };

   struct appdata_img {
      float4 vertex : POSITION;
      half2 texcoord : TEXCOORD0;
   };

要在程式碼中使用這些內建結構體一定要新增命令#include “UnityCG.cginc”。如下程式碼:

Shader "Cg shader parameters" { 
   SubShader { 
      Pass { 
         CGPROGRAM 
 
         #pragma vertex vert  
         #pragma fragment frag 

         #include "UnityCG.cginc"
 
         struct vertexOutput {
            float4 pos : SV_POSITION;
            float4 col : TEXCOORD0;
         };
 
         vertexOutput vert(appdata_full input) 
         {
            vertexOutput output;
 
            output.pos =  mul(UNITY_MATRIX_MVP, input.vertex);
            output.col = input.texcoord;
		
            return output;
         }
 
         float4 frag(vertexOutput input) : COLOR 
         {
            return input.col; 
         }
 
         ENDCG  
      }
   }
}

3、更改頂點程式的輸出引數:將頂點程式中的output.col = input.texcoord程式碼替換成如下的程式碼可以得到不同的效果:

output.col = float4(input.texcoord.x, 0.0, 0.0, 1.0);
//output.col = float4(0.0, input.texcoord.y, 0.0, 1.0);
//output.col = float4(
               (input.normal + float3(1.0, 1.0, 1.0)) / 2.0, 1.0);

1.3.3、Unity中控制Shader變數方法

Uniform引數的應用:Uniform通常都是用來修飾一些由應用程式傳入的離散資料,如:

<span style="font-size:18px;">uniform float4x4 Object2World;</span>

表示從外部傳入一個四乘四的矩陣,如此,Shader程式就可以和外部的應用程式進行互動。在Unity中可以通過控制面板或者C#指令碼來控制這些變數。

1、控制面板上控制uniform引數:在上面的模板程式的基礎上新增一個屬性,程式碼如下:

Shader "Unlit/Propertey"
{
//新增一個屬性塊,在屬性塊中定義一個變數
	Properties{
		_Color("color", Color) = (0.0, 1.0, 0.0, 1.0)
	}
		SubShader{
			Pass{
			CGPROGRAM
			#pragma vertex vert 

			#pragma fragment frag	
	//在Pass塊中使用該屬性塊中的變數必須要使用	
	//uniform關鍵字重新定義該變數
			uniform float4 _Color;

		float4 vert(float4 vertexPos : POSITION) : SV_POSITION
		{
			return mul(UNITY_MATRIX_MVP, vertexPos);
		}
		float4 frag(void) : COLOR
		{
			return _Color;

		}

			ENDCG
		}
	}
}

在SubShader上面添加了一個屬性模組,屬性塊中定義了一個顏色變數_Color,屬性模組中變數的定義形式為:

_ParamName("Display Name",ParamType)=defaultValue[{options}]

_ParamName:該屬性變數的名字,Shader程式碼中即使用這個變數名字來索引;

Display Name:在控制面板上顯示該屬性的名字,在Unity中可以是中文;

ParamType:該屬性變數的型別,這個型別並不是Cg語言的資料型別,而是Unity中特有的屬性型別,在Unity中屬性變數的型別以及各自對應的Cg資料型別為:

    數值型別:

       Range(min,max):會在控制面板上顯示一個滑動條,最小值為min,最        大值為max,值的型別為浮點型別;

       Flaot:浮點型別資料,注意此處第一個字母大寫;

       Int:整數型別資料,注意此處第一個字母的大寫;

    向量型別:

       Color:顏色屬性,也是一個四維的向量,值的範圍為0~1;

       Vector:四維向量,值可以任意指定;

    貼圖型別:

       2D:2的階數(如256,1024等)大小的貼圖,它的座標UV範圍(0~1,0~1);

       Rect:非2的階數的大小的貼圖,它的座標UV的範圍(0~1,0~1);

        Cube:立方體貼圖,即六張2D貼圖的組合;

       3D:3D紋理貼圖,Unity的指令碼和Shader中支援3D貼圖的使用和建立,     但是3D貼圖的使用不能像2D貼圖那樣直接。它的座標UVW的範圍        (0~1,0~1,0~1),常見的應用如,火焰、煙霧以及光線等。

定義了屬性塊中的變數必須要在Pass塊中使用uniform關鍵字重新定義這個變數才能在該Pass塊的Shader程式碼中使用,如果有多個Pass塊都會使用這個變數就必須要在每一個Pass塊中都重新定義這個變數。在上面的程式碼中的第一個Pass塊中使用uniform定義了變數_Color,在之後的Pass塊中要使用都必須定

Pass{
			CGPROGRAM
			...
			#pragma fragment frag	
			uniform float4 _Color;
			...
			ENDCG
	     }
//如果有多個Pass塊使用這個變數,需要在每一個Pass中都定義這個變數
	Pass{
			CGPROGRAM
			...
			uniform float4 _Color;
			...
			ENDCG
}
...

義這個變數。uniform變數的定義必須在CGPROGRAM~ENDCG之間,否則會編譯報錯,最好的習慣是將變數的定義在緊跟CGPROGRAM之後。

●option:這個選項只對2D、Rect以及Cube貼圖有用,它是在沒有選中使用者自己的貼圖時候預設使用Unity內建的貼圖來填充,這些貼圖的型別可以是 “white”,“black”, “gray” 以及 “bump”中的一種,也可以為空。

屬性的個性顯示:

●[HideInInspector]:在控制面板上隱藏這個屬性變數,直接在屬性塊中的變數前面新增即可,如:


Properties{
	[HideInInspector]
	_Color("color", Color) = (0.0, 1.0, 0.0, 1.0)
	}

●[NoScaleOffset]:這個是針對貼圖變數的,隱藏控制面板中的貼圖變數的tilling和offset

●[Gamma]:將float和Vector型別的屬性在控制面板上顯示成類似顏色屬性那樣的UI互動面板,常用的型別有:

    ●Toggle]:定義float型別的屬性變數,在控制面板上將顯示一個勾選框如:

[Toggle] _Invert("Invert?", Float) = 0

這個變數的值為1或0,勾選表示1,反之為0;

    ●[Enum]:定義float型別的屬性變數,控制面板上顯示一個下拉列表,下拉列表中可以選擇自定義的資料,如:

[Enum(One,1,Two,2)] _Num ("Num Enum", Float) = 1

在控制面板上將顯示下拉列表,列表中有兩個變數One和Two,它們的值分別為1和2。最大能列舉的列表量個數為7個;

    ●[KeywordEnum]:定義float型別的屬性變數,在控制面板上顯示一個下拉列表,裡面可以列舉Shader的關鍵字。

    ●[PowerSlider]:定義Range型別的變數,Range變數本來就會在控制面板上顯示滑動條,但是在拖動的時候變數的值是以線性進行增減的,而加上這個特性的Range變數會以指定的指數形式增減。如:

[PowerSlider(2.0)] _Shin ("Shin", Range (0.01, 1)) = 0.1
在控制面板上拖動這個變數將會以2次曲線的形式進行增減。
  [Space]:定義所有型別的變數,使得變數在控制面板上距離上一個變數保持一定的距離,如:其中50表示間隔的空間,可以不新增,也即為預設一個空格的距離
[Space(50)] _Prop ("Prop", Float) = 0
●[Header]:定義所有型別的變數,能在控制面板上顯示自定義的變數標題,如:“Floatvariable”會出現在控制面板上變數的上方,不能為中文。
[Header(Float variable)] _P ("P", Float) = 0

2、在程式碼中控制uniform引數

要在程式碼中控制uniform的引數,可以不用在屬性塊中定義,只需要在Shader程式碼中使用關鍵字uniform定義變數。修改上述的Shader程式碼如下:

Shader "Unlit/Propertey"
{
//新增一個屬性塊,在屬性塊中註釋掉剛剛定義的變數
	Properties{
		//_Color("color", Color) = (0.0, 1.0, 0.0, 1.0)
	}
		SubShader{
			Pass{
			CGPROGRAM
			#pragma vertex vert 
			#pragma fragment frag	
			//必須使用uniform關鍵字定義該變數才能在C#指令碼			//中呼叫
			uniform float4 _Color;
		float4 vert(float4 vertexPos : POSITION) : SV_POSITION
		{
			return mul(UNITY_MATRIX_MVP, vertexPos);
		}
		float4 frag(void) : COLOR
		{
			return _Color;

		}

			ENDCG
		}
	}
}

建立一個C#指令碼,將下面的程式碼複製到新建的C#指令碼中,並將這個指令碼拖到上述Shader的物體上,保證C#指令碼和Shader程式碼執行在同一個物體上。

using UnityEngine;
using System.Collections;
[ExecuteInEditMode]
public class Propertey : MonoBehaviour {
    private Renderer _renderer;

	// Use this for initialization
	void Start () {
        _renderer=GetComponent<Renderer>();
	
	}
	
	// Update is called once per frame
	void Update () {
        _renderer.sharedMaterial.SetColor("_Color", new Color(1, 1, 0, 0.5f));
	
	}
}

本段程式碼中在類的前面添加了[ExecuteInEditMode],保證指令碼可以在編輯狀態下就被執行。通過程式碼

_renderer.sharedMaterial.SetColor("_Color", new Color(1, 1, 0, 0.5f));

對shader中的“_Color”變數進行設定,你可以通過更改程式碼中的值類瀏覽變換的效果。

sharedMaterial和material的區別:程式碼中可以將sharedMaterial替換成material,編譯會報錯並提示我們使用sharedMaterial,此處是因為在編輯模式下執行,如果去掉編輯模式,直接執行得到的效果也是一樣的。material是針對當前的材質,在當前的材質基礎上再例項化一個材質,使用material的時候,如圖1.5所示,會在該材質球的後面添加了“(Instance)”,表示這個指令碼

在使用material控制是隻對當前的材質球有效,對其他使用該材質球的物體無


圖1.5C#指令碼中使用material控制uniform引數

效。而在使用sharedMaterial的時候是沒有“(Instance)”,在C#指令碼中對該材質球進行修改會影響到其他使用該材質球的物體。如此,我們必須要在使用指令碼控制的時候區別對待。

指令碼控制的常用方法

Color GetColor(string propertyName):通過屬性名字獲取顏色屬性值,並使用這個值作為返回值;

float GetFloat(string PropertyName):通過屬性名字獲取一個浮點型別的屬性值,並使用值作為返回值;

int GetInt(string PropertyName):通過屬性名字獲取一個整數型別的屬性值,並將這個值作為返回值;

TextureGetTexture(string PropertyName):通過屬性名字來獲取一個貼圖,並將這個貼圖作為返回值;

對應Color、float、int以及Texture的還有設定方法,都是通過屬性名字來對相應的屬性進行設定,更多的方法請參閱Unity官網文件,網址為:點選開啟連結

1.3.4、Unity中寫Shader程式應用

新建一個Shader程式,將下面的程式碼複製到這個Shader程式檔案中

Shader "UnityCg/worldSpaceColor"
{
	Properties{
		_Point("原點", Vector) = (0., 0., 0., 1.0)
		_DistanceNear("閾值距離", Float) = 5.0
		_ColorNear("離原點小於閾值距離的點的顏色", Color) = (0.0, 1.0, 0.0, 1.0)
		_ColorFar("離原點大於閾值距離的點的顏色", Color) = (0.3, 0.3, 0.3, 1.0)
	}

		SubShader{
		Pass{
		CGPROGRAM

#pragma vertex vert  
#pragma fragment frag 

#include "UnityCG.cginc" 

	//使用關鍵字uniform再定義屬性中的變數
	uniform float4 _Point;
	uniform float _DistanceNear;
	uniform float4 _ColorNear;
	uniform float4 _ColorFar;

	struct vertexInput {
		float4 vertex : POSITION;
	};
	struct vertexOutput {
		float4 pos : SV_POSITION;
		float4 position_in_world_space : TEXCOORD0;
	};

	vertexOutput vert(vertexInput input)
	{
		vertexOutput output;

		output.pos = mul(UNITY_MATRIX_MVP, input.vertex);

		//_Object2World是Unity內建的四乘四矩陣,使用了#include "UnityCG.cginc" 命令就可以直接使用,不用再使用uniform關鍵字進行定義
		output.position_in_world_space =
			mul(_Object2World, input.vertex);
		return output;
	}

	float4 frag(vertexOutput input) : COLOR
	{
		//計算原點和這個物體的片段點之間的距離
		float dist = distance(input.position_in_world_space,
		_Point);
	if (dist < _DistanceNear)
	{
		return _ColorNear;
	}
	else
	{
		return _ColorFar;
	}
	}

		ENDCG
	}
	}
}

這個程式實現的效果即:物體在世界座標系的位置與預設的原點位置“Point”的距離小於閾值“DistanceNear”部分就顯示“ColorNear”的顏色值,大於閾值“DistanceNear”部分就顯示“ColorFar”的顏色值。

相關推薦

Unity&Shader基礎-“Hello Cg

1.3.1、從簡單的模板程式開始 1、開啟Unity程式,在Project中選擇Create 選擇Shader>Unlit Shader。程式的名字最好和shader的用途有關聯,讓人一看就知道這個shader是用來做什麼的。 2、將下面的模板程式複製到這個新建的S

【遊戲渲染】Unity&Shader基礎-Cg語法,資料型別與關鍵字

1.2、Cg語法基礎 如C++、C#和Java等高階語言一樣,Cg語言也有自己的資料型別和關鍵字。掌握和理解這些關鍵字是寫好Cg程式的基礎。 1.2.1、Cg的資料型別與關鍵字 基本資料型別:Cg支援7種基本的資料型別 1、float,32

Unity&Shader基礎-可程式設計GPU圖形繪製管線

Cg是最早的為可程式設計圖形硬體設計的高階程式語言。它是英偉達和微軟公司一起合作開發出來了語言,如果你非常熟悉C語言或者其他的程式語言,如C++、C#或者Java等,那對於Cg語言你將會非常容易掌握。

Unity&Shader基礎-常用函式的使用與案例

Shader "Unlit/Chapter6-Animations" { Properties { _SpeedY("第一部分的速度",Range(0,3)) = 1 _Amplitude("第二部分的振幅",Range(0,1)) = 0.8 _RSpeedX("圓周運動X方向的速度",Ra

Unity Shader入門精要學習筆記 - 第3章 Unity Shader 基礎

但是 detail spa net 表示 part 文件 人的 text 來源作者:candycat http://blog.csdn.net/candycat1992/article/ 概述 總體來說,在Unity中我們需要配合使用材質和Unity Shader才能達

3.Unity Shader 基礎

目錄   一對好兄弟:材質和Unity Shader Unity中shader ShaerLab Unity Shader 的結構 1.建立 2.Properties 3.SubShader 狀態設定([RenderSetup]) SubShader

Unity Editor 基礎(二):自定義 Inspector 面板

自定義Inspector屬性面板 EditorGUILayout 編輯器介面佈局  這是一個編輯器類,如果想使用它你需要把它放到工程目錄下的Assets/Editor資料夾下。編輯器類在UnityEditor名稱空間下。所以當使用C#指令碼時,你需要在指令碼前面加上

Unity Editor 基礎(三):自定義視窗案例二

本文為本人學習上鍊接的筆記微有改動,請點選以上鍊接檢視原文,尊重樓主智慧財產權。 ----------------------------------------------------------------------------------------------

Unity Editor 基礎(四):Handles

本文為本人學習上鍊接的筆記微有改動,請點選以上鍊接檢視原文,尊重樓主智慧財產權。 Unity Editor:Handles 最終效果: 準備:  Scripts資料夾中建立C#指令碼”MyHandles”,在Editor資料夾中建立C#指令碼”HandleIns

Unity Editor 基礎(五):Gizmos

本文為本人學習上連線的筆記有改動,請點選以上鍊接檢視原文,尊重樓主智慧財產權。 Unity Editor–Gizmos 目標:  1.瞭解一些屬性的使用 最終效果: 準備工作:  在之前的專案或者新建的專案中建立如下目錄結構: 如果是新的專案,只需建立S

Unity Editor 基礎(六):Property Drawers

本案例中樓主似乎把person拼錯了,類名不用多管,看內涵。 Property Drawers:繪製屬性 目標:  瞭解一些屬性的使用  自定義一個Property Drawers 最終效果: 準備: 建立一個新的工程或者用上一篇的工程,然後C#指令碼: 

Unity Editor 基礎(七):Property Attributes自定義屬性

Property Attributes自定義屬性 目標:  1.瞭解一些基本的使用  2.自定義一個Property Attributes 最終效果: 準備: 大夥們還記得《Unity Editor 基礎篇(一):Build-In Attribute》裡所說的

Unity Editor 基礎(九):EditorUtility編輯器工具

EditorUtility 編輯器工具 轉自:http://blog.csdn.net/liqiangeastsun/article/details/42174339,請檢視原文,尊重樓主原創版權。 這是一個編輯器類,如果想使用它你需要把它放到工程目錄下的Assets/E

Unity Editor 基礎(十三):MenuItem屬性

MenuItem選單項  MenuItem屬性允許你新增選單項到主選單和檢視面板上下文選單。  (該屬性把任意靜態函式變為一個選單命令。僅靜態函式能使用這個MenuItem屬性。) 1.為Unity新增選單項 使用方法: MenuItem(string itemNa

Unity Shader 基礎教程

轉至(https://blog.csdn.net/jianzuoguang/article/details/80471598) githup(https://github.com/Centribo/Unity-Shader-Basics-Tutorial) Unity-Shader-基礎教程

Unity&Shader高階-渲染路徑(Rendering Paths)

一、前言 在Unity的Camera中常常會看到一個Rendering Paths的選項,裡面有5個選項,其中兩個比較重要的選項分別是“Deferred Shading”和“Forward Rende

Unity&Shader案例—旋轉、平移和縮放

一、前言      在Unity中通過控制物體的Transform可以很容易的對物體進行旋轉、平移和縮放,得到一些簡單的動畫效果。但是有個不好的地方是,一旦這個物體上有碰撞體的話,會跟環境發生碰撞。我就就想能不能在不麻煩特效動畫那邊的情況下,自己用Shader去處理一些基於

Unity Shader (二)Cg語言

一、Cg基本資料型別 float 32位浮點數 half 16位浮點數 int 32位整型 fixed 12位定點數 bool 布林資料 simpler* 紋理物件的控制代碼( the handle to a text

Unity&Shader案例—地圖上熱圖分佈

一、介紹        在2維平面地圖上隨機或者指定位置生成一系列的熱量、能源或者其他需要表示的資訊的分佈圖。可以通過切換不同的貼圖表示不同的資訊,如圖所示表示的是該地區的降水量的變化如圖所示為表示該地區的溫度變化分佈圖二、實現       在貼圖的的某個位置處繪製指定半徑的

筆記一 ——Unity Shader概念

學習教材:《UnityShader入門精要》——馮樂樂 部分計算圖例為《UnityShader入門精要》書中截圖 程式碼和例項截圖均為實際操作執行結果 渲染流水線 渲染流水線從概念部分分為三個部分: 應用階段 應用階段為開發者完全控制部分,主要提供渲染所需要的渲染資