日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

Unity3D Shader 新手教程(1/6)

發布時間:2024/1/8 编程问答 44 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Unity3D Shader 新手教程(1/6) 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

剛開始接觸Unity3D Shader編程時,你會發現有關shader的文檔相當散,這也造成初學者對Unity3D Shader編程望而卻步。該系列教程的第一篇文章(譯者注:即本文,后續還有5篇文章)詳細介紹了Unity3D中的表面著色器(Surface Shader)的,為學習更復雜的Shader編程打下基礎。

動機

如果你是剛剛接觸Shader編程的新手,你可能不知道從何開始踏出Shader編程的第一步。本教程將帶你一步步完成一個表面著色器(Surface Shader)和片段著色器(Fragment Shader)。本教程也將介紹在Unity3D Shader編程中所使用的一些函數和變量,這些內容可能和你在網上看到的不一樣哦!

如果你滿足下面的條件,我覺得你應該看看這篇文章:

  • 如果你是shader編程的新手。
  • 你想在你的游戲中使用shader做一些很炫酷的效果,但是你在網上找不到可用的Shader(譯者注:o(╯□╰)o自己動手豐衣足食)
  • 由于缺乏對基礎知識的了解,造成不能隨心所欲使用Strumpy著色器編輯器譯者注:Strumpy Shader Editor,一種圖形化編寫shader的方式,看著很誘人!)
  • 你想在你的shader代碼中手動處理紋理(Textures)

本文是該系列教程的第一篇文章,隨后我們會制作一些更復雜的shader。相比起來,第一篇文章確實很簡單。

關于作者

我也是Shader編程的新手----所以我決定寫這篇教程幫助大家入門——我當初也在入門上遇到很多苦惱。事實上我并不是一個Shader編程專家。

當我想了解Shader編程時,我曾反復閱讀官方文檔,但是我最終發現官方文檔講述的順序并不適合我學習shader。所以我覺得我應該寫一篇教程,并分享我所學到的知識。不過寫完教程之后,我發現再次閱讀官方文檔時,覺得明白多了。

盡管本教程中的所有例子都能正常運行,但是我相信肯定有更好shaders實現這些例子。如果聰明的你對這些例子中的shaders有更好的建議,請在評論區留言!

我之所以學習shader編程是因為我需要在我創建的游戲世界中創建些東西,但這個游戲世界創建起來有個麻煩之處,因為它是由不同角色組成的,而我必須創建由多個部分組成的一個統一網格(mesh)。所以我只能對每個角色使用一次繪制調用(draw call)。(譯者注:完全不知道他在講什么?所以我把原文放在下面給大家評評理)

My reason for getting into shader programming was to build something that I needed for a world populated with an endless array of different characters.? I needed to build a combined mesh out of multiple parts so I only have one draw call per character.

通過打開和關閉角色的穿衣效果,我使用Megafiers(一個變形插件)修改了角色的基本網格(base meshes)。其中的困難在于我只有一個紋理(texture),但是我卻想給每個角色的皮膚,服飾以及其他的特征使用不同的顏色。我想到一個方法----對每個角色使用不同的3個4x4紋理,并使用一個shader來給模型上色。我將在整個教程中詳細描述我做的這個shader,但是現在—我想你們已經迫不及待地想看我創建的角色表演一段即興的快閃舞(flash mob dance)(譯者注:網上截的圖片)

著色器和材質(shaders&materials)

一個shader所做的就是將一個模型的網格(mesh)渲染到屏幕上。Shader可以被定義為一系列的屬性(譯者注:就像一個函數里面的參數一樣,你可以改變函數的不同賦值來改變函數的輸出結果),你可以通過改變這些屬性來改變模型渲染到屏幕上的效果。而這些屬性被存放起來,放到一個叫做材質(material)的地方。

Unity3D Shader有以下幾種

  • 表面著色器(surface shader)----后臺自動為你做的絕大部分的工作,減少了你工作量,并且適合絕大多數需要shader的情況。
  • 片段著色器(fragment shader)----可以讓你做更多的效果,但是此shader更難寫。你也可以用它做一些底層的工作,比如頂點光照(Vertex lighting,即在每個頂點存儲該點的光照信息)。頂點光照對于移動設備很有用(譯者注:估計省內存吧)。該shader對于一些需要多通道(multiple passes)的高級渲染效果也很有效。

本文中我們將關注點放在表面著色器上。

學習Shader的資源

如果你要學習Shader編程,我向你推薦下面幾個資源

  • Martin Kraus‘s fantastic Wiki Book GLSL Programming/Unity
  • Unity‘s Shader Reference
  • NVidia‘s tutorial on the CG programming language
  • CreativeTD‘s video series on writing surface shaders

Shader的流水化工作方式

譯者注:Shader的工作方式也稱為shader流水線(pipeline),因為shader工作方式很類似汽車流水線,將模型上一系列頂點數據和其他各種數據作為輸入,用這個shader組成的流水線加工下,出來的就成了炫酷的效果了。)

你將在shader流水線中看到不明覺厲的各種術語,我將用我自己的語言盡量降低理解的難度。

Shader的工作就是輸入一些3D幾何信息,經過shader處理后將其變為2D的像素呈現在屏幕上。好處是在shader處理過程中,你只需要改變少數幾個屬性就可以產生不同的效果。對于表面著色器,該工作流程看起來像下面這樣:

(譯者注:簡單講解一下這個流程圖,首先要渲染的物體將自己的幾何信息傳遞到Shader中,并且系統得到了該物體的頂點信息,然后你可以選擇經不經過Vertex Function來處理這些頂點信息,隨后經過光柵化(將三維幾何信息映射到二維屏幕上,打個不恰當的比喻,相當于把3D模型拍扁到屏幕上,然后你就可以專心處理屏幕上的像素了),每個像素經過你的shader代碼將得到最終的顏色值)

注意在表面著色器(Surface Shader)中的函數退出之前,像素的顏色還沒有計算出來。這意味著你可以再次之前傳入頂點的法向量來影響光照的計算。

片段著色器(Fragment Shader)有著同樣的工作流程,但事實上,片段著色器中必須有Vertex Function(上圖中的Vertex Function部分就是可選的(Optional)),而且需要在像素處理階段做很多的工作才能產生最終的像素。而表面著色器隱藏了這些。(譯者注:給我的感覺就是片段著色器向用戶提供了更多的接口進行更高級的渲染)。

下圖展示了你的代碼如何被調用以及代碼構成

從上圖我們可以看到,當你寫一個shader的時候,你可能得有一些屬性值(properties),并且有一個或多個Subshaders。具體使用哪個Subshader進行處理取決于你的運行平臺。你應該還要指定一個Fallback shader,當你的subshader沒有一個能運行在你的目標設備上,將使用Fallback shader(譯者注:有點像備胎)

每個Subshader都至少有一個通道(pass)作為數據的輸入和輸出。你可以使用多個通道(passes)執行不同的操作,比如在一個Grab Pass中,你可以獲取將要呈現到屏幕上的像素值(譯者注:類似于glsl中的fragment buffer)。當你想制作高級的扭曲效果,這非常有用。雖然當你開始學習shader編程時,你可能并不會使用到它。另外一個使用多通道(multiple passes)的原因是在不同時刻,你可能需要寫入或者禁止寫入深度緩存的使用。

當你寫表面著色器時,我們將直接在Subshader這個層次上寫代碼,系統將把我們的代碼編譯成若干個合適的通道(pass)。

盡管shader最終產生的是二維像素,但是其實這些像素除了保存xy坐標外,本身保存著深度值(即每個像素點上的內容在原先3D場景中離照相機的遠近),這樣距離照相機近的物體就會把距離照相機遠的物體遮擋住,在屏幕上顯示時,就是將其像素值覆蓋。

你可以控制是否在你的shader中使用深度緩存(Z-buffer)產生一些特效,或者在Pass中使用一些指令決定shader是否可以寫入Z-buffer:比如使用ZWrite Off時,任何你輸出的東西都不會更新Z-buffer的值,即關閉的Z-Buffer的寫入功能。

你可以使用Z-buffer技術在別的物體上掏出一個洞,你可以先寫入需要打洞區域的深度值,但不輸出打洞區域所屬的像素值,然后在你模型后面的物體的深度值將無法寫入(因為Z-buffer覺得你的模型已經擋住了后面的物體)(譯者注:這樣你打洞區域顯示的就是一開始使用的背景色,會造成一個洞穿過了這些物體的效果)

下面是一些shader代碼:

希望你能看出上面代碼是由PropertiesSubShaderFallback三段代碼組成的。

理解Shader代碼

文章剩下的部分將講述上面那段簡單代碼到底做了什么?真正的干貨馬上就來了,你必須好好掌握這些內容。

當你進行shader編程時,你必須使用正確的變量名和函數名來調用它們,事實上變量的名稱在某些情況下能讓人一眼看出它的特定含義。

創建并使用默認Shader

(譯者注:在詳細介紹Shader之前,我們先簡單介紹下shader如何使用。)

1.?我們先打開Unity(我的版本是4.6.1),創建新工程,并在Assets文件夾下創建三個目錄,如下:

2.?我們再創建一個cube。

可以在Inspector面板看到新創建的cube所使用的Material如下。

3.?打開Material文件夾,我們在其中創建一個Shader和一個Material。

此時New Material的默認Shader為Diffuse。

我們將NewShader拖到New Material上。

可以看到該材質所使用的Shader變成我們新建的NewShader了。當然你也可以直接點擊材質編輯器中Shader下拉框,選擇相應的Shader。

4.?最后將New Material拖到cube上。可以看到cube所使用的材質和Shader都變成了我們新創建的材質和Shader了。

Properties(屬性值)簡介

你在shader代碼中的Properties{…}部分定義Shader中的屬性值(屬性值就是用戶傳入給shader的數據,比如紋理之類的,然后shader處理這些紋理,產生特效。可以理解為屬性值相當于一種全局變量,而Shader就是那個主函數,Unity的優勢在于給這個全局變量賦值可以在Inspector面板進行)。注意Properties(屬性值)是所有Subshader代碼中的共享的,意味著所有SubShader代碼中都可以使用這些屬性值。

屬性值(property)定義的形式:

_Name(“Displayed Name”,type) = default value[{options}]

  • _Name?屬性值的名稱,是在shader代碼內部使用的,區別于下面的Displayed Name,后者是在Inspector 面板上顯示的,作為外界(用戶)的輸入提示。
  • Displayed Name?呈現在材質編輯器中的屬性值名稱,在Inspector面板上顯示。

總結:打開我們創建的NewShader。可以看到_MainTex是在代碼中使用的,而Base (RGB)是在材質編輯器中使用的

  • type?屬性值的類型,包括:
    • Color?– 表示純色,使用了RGBA表示法
    • 2D?– 代表尺寸為2的冪次的紋理(如2,4,8,16…256,512)
    • Rect?– 代表紋理(texture),不同于上面的紋理,此處紋理的大小不一定是2的冪次。
    • Cube?– 用于3d中的cube map,經常提到的天空盒就是使用了cube map。
    • Range(min, max)?– 在min和max之間的一個值,在面板中可用滑動條改變其值大小。
    • Float?– 任意一浮點數。
    • Vector?– 4維向量值,本質就是4個浮點數組成的類型。

來張全家福:

  • default value?屬性值的初始值,就相當于你的變量初始化的那個值。
    • Color – (red,green,blue,alpha)?使用了RGBA這種格式的顏色,alpha指的是透明度– 比如 (1,1,1,1)
    • 2D/Rect/Cube?– 紋理的類型,上面已經介紹過了。初始化值可以使一個空字符串,或者"white", "black", "gray", "bump"(說明此紋理是一個凹凸紋理)
    • Float/Range?– 這個沒啥說的,跟浮點數初始化一樣一樣的
    • Vector – 4維向量,其中4個數均為浮點數 (x,y,z,w)
  • { options }?這里注意了,{options}?僅僅用于紋理類型,比如上面提到的2DRectCube,對于這些類型,如果沒有options可填,至少要寫一個空的{},否則編譯出錯。可以使用空格將多個options(選項)分開 ,可用的options(選項)如下:
    • ?TexGen?texgenmode紋理坐標自動生成的方式。可以是ObjectLinear,?EyeLinear,?SphereMap,?CubeReflect,CubeNormal其中之一,這些方式和OpenGL中的紋理坐標生成方式相對應,具體詳見這篇博文。注意當你寫Vertex Function時,紋理坐標產生方式將被忽略。

下面舉幾個屬性值寫法的例子:

// 定義了一個半透明(alpha=0.5)效果的紅色作為默認顏色值_MainColor(“Main Color”,Color)=(1,0,0,0.5)// 定義了一個默認值為白色的紋理_Texture(“Texture”,2D) =”white” {}

注意屬性值的定義末尾處不需添加分號。

標簽(Tags)

你的表面著色器可以用一個或多個標簽(tags)進行修飾。這些標簽的作用是告訴硬件何時去調用你的shader代碼。

在我們的例子中,我們使用:Tags {“RenderType” = “Opaque”},這意味著當程序去渲染不透明的幾何體時,將調用我們的shader,Unity定義了一系列這樣的渲染過程。另一個很容易理解的標簽就是Tags {“RenderType” = “Transparent”},意味著我們的shader只會輸出半透明或透明的像素值。

其它一些有用的標簽,比如“IgnoreProjector”=“True”,意味著你渲染的物體不會受到projectors(投影儀)的影響。

“Queue”=“xxxx”(給shader所屬的對象貼上渲染隊列的標簽)。當渲染的對象類型是透明物體時,Queue標簽能產生一些非常有趣的效果。該標簽決定了物體渲染的順序(譯者注:我猜測它的工作方式是這樣的,一個場景中有很多個物體,當這些物體被渲染時,必須有一個渲染的順序,比如背景應該比其他物體先渲染出來,否則背景會將之前渲染的物體遮擋住,具體方法是將背景使用的shader中貼上一個“Queue”=“Backfround”標簽,這樣使用該shader的物體將被貼上Background的標簽。總之當渲染整個場景時,unity會根據這些渲染隊列的標簽決定按什么順序去渲染對應標簽所屬的物體)。

  • Background?– 在所有其他物體渲染之前渲染,被用于天空盒或類似的背景效果。
  • Geometry(默認tags為geometry)?– 適用于大多數物體。非透明物體使用這種渲染順序。
  • AlphaTest?– 順利通過alpha測試的像素(alpha-test是指當前像素的alpha小于一定的值就舍棄該像素)使用該渲染順序。單獨設置該渲染順序是因為在所有實體渲染過后,該渲染順序將對渲染經過alpha測試的物體更有效率。
  • Transparent?– 該渲染標簽所屬的物體將在標簽為Geometry和AlphaTest之后的物體渲染,并且這些貼著Transparent的所有物體本身是從后往前依次渲染的。任何經過alpha-blended的物體都應該使用該標簽(譯者注:alpha-blended是指使用當前像素的alpha作為混合因子,來混合之前寫入到緩存中像素值,此時注意shader是不能寫入深度緩存的,因為如果不關閉寫入深度緩存,那么在進行深度檢測的時候,它背后的物體本來我們是可以透過它被我們看到的,但由于深度檢測時,小于它的深度就被剔除了,從而我們就看不到它后面的物體了),玻璃和粒子效果比較適合該渲染標簽。
  • Overlay?– 該渲染標簽適合覆蓋效果,任何最后渲染的效果都可以使用該標簽,比如透鏡光暈。

有趣的是你可以給這些基本的渲染標簽進行加加減減。這些預定義的值本質上是一組定義整數,Background = 1000, Geometry = 2000, AlphaTest = 2450, Transparent = 3000,最后Overlay = 4000(譯者注:從此處我們也可以一窺究竟,貌似數值大的后渲染。)這些預設值這對透明物體有很大影響,比如一個湖水的平面覆蓋了你用廣告牌制作的樹,你可以對你的樹使用“Queue”=”Transparent-102”,這樣你的樹就會繪制在湖水前面了。

Shader的整體結構

讓我們回顧下shader代碼的結構。

#pragma surface surf Lambert?這段代碼表示其中surface表示這是一個表面著色器,進行結果輸出的函數名稱為surf,其使用的光照模型為Lambert光照模型。

我們的CG程序使用了一種經過修飾的類C語言 —— CG語言(是Nvidia和微軟共同出品的一種shader語言)。詳見Nvidia的文檔?—— 我在文中也會介紹一些基本的Cg使用方法。

浮點數類型(float)和向量值類型(vec)一般都會在末尾加上2,3,4這些數字(float2,float4,vec3…)表示該類型具體有幾個元素組成。這種定義方式使數值操作變得更方便,你可以將其當做一個整體使用,或者單獨使用其分量。

//定義一個浮點類型的二維坐標vec2 coordinate;//定義一個顏色變量(4個浮點值分量的顏色值)float4 color;//通過點乘得到3個浮點值分量的顏色值float3 multipliedColor = color.rgb * coordinate.x;

你可以使用.xyzw或.rgba來表明你使用的變量類型具體的含義,比如.xyzw可能表示的是旋轉四元數,而.xyz表示位置或法向量,.rgba表示顏色。當然,你可以僅僅使用float作為單個浮點值類型。其實對.rgba等分量訪問符的使用也稱作swizzle,尤其是對顏色的處理,比如顏色空間的轉換可能會用到它,比如color=color.abgr;

你將會遇到half(半精度)和double(雙精度)類型,half(一般16bit)即正常float(一般32bit)的一半精度,double(一般64bit)是正常float的兩倍精度(此處的倍數衡量的方式不是指表示的范圍,而是表示可以使用的bit位數)。使用half經常是出于性能考慮的原因。還有一種區別于浮點數的定點數fixed,精度更低。

當你想將顏色值規范到0~1之間時,你可能會想到使用saturate函數(saturate(x)的作用是如果x取值小于0,則返回值為0。如果x取值大于1,則返回值為1。若x在0到1之間,則直接返回x的值.),當然saturate也可以使用變量的swizzled版本,比如saturate(somecolor.rgb);

你可以使用length函數得到一個向量的長度,比如float size = length(someVec4.xz);

如何從表面著色器輸出信息

我們的surface function(表面函數)每個像素調用一次,系統已經事先計算出當前處理的像素的輸入值(準確來說應該是輸入結構體,即Input IN中的Input類型)。 它是根據每個網格上的面片,并進行插值得到的結果。

來看看我們的surf函數

void surf (Input IN, inout SurfaceOutput o) {o.Albedo = tex2D (_MainTex, IN.uv_MainTex).rgb;}

很明顯我們可以看出,我們返回了o.Albeodo值 – 該值是Unity為我們定義的SurfaceOutput結構體中的某個成員。接下來讓我們看看SurfaceOutput具體定義了哪些成員。該Albedo表示像素的顏色。

struct SurfaceOutput {half3 Albedo; //該像素的顏色值 half3 Normal; //該像素的法向量 half3 Emission; //該像素的輻射光,輻射光是最簡單的一種光,它直接從物體發出并且不受任何光源影響 half Specular; //該像素的鏡面高光 half Gloss; //該像素的發光強度 half Alpha; //該像素的透明度 };

你只要將該結構體中值交給Unity,Unity會自動根據這些值產生最終效果,而不需要你關心其中的細節。

我答應你們的干貨就在下面

首先看看作為我們surf函數的輸入是啥?

我們定義了一個輸入結構體如下:

struct Input {float2 uv_MainTex;};

通過簡單地創建結構體,我們告訴系統當我們每次調用surf函數時,獲取MainTex在該像素的紋理坐標。如果我們有第二個紋理叫做—_OtherTexture,我們可以通過在輸入結構體中添加下面代碼得到它的紋理坐標

struct Input {float2 uv_MainTex;float2 uv_OtherTexture;};

如果對于其他紋理,我們有第二套紋理坐標,我們可以這樣做:

struct Input {float2 uv_MainTex;float2 uv2_OtherTexture;};

此時對于我們所使用的所有紋理,我們的輸入結構體包含一套uv坐標或者一套uv2坐標。

如果我們的shader很復雜并且需要知道像素的其他相關信息,我們就可以將以下變量包含在輸入結構體中,以此來查詢其他的相關變量。

  • float3?viewDir?–?視圖方向( view direction)值。為了計算視差效果(Parallax effects),邊緣光照(rim lighting)等,需要包含視圖方向(view direction)值。
  • float4? with COLOR semantic(比如float4 currentColor,即用戶自定義和顏色相關的變量名稱) – 每個頂點(per-vertex)顏色的插值。
  • float4 screenPos?– 為了反射效果,需要包含屏幕空間中的位置信息
  • float3 worldPos?– 世界空間中的位置
  • float3 worldRefl?– 世界空間中的反射向量。如果表面著色器(surface shader) 不為SurfaceOutput結構中的Normal賦值,將包含這個參數。
  • float3 worldNormal?– 世界空間中的法線向量(normal vector)。如果表面著色器(surface shader) 不為SurfaceOutput結構中的Normal賦值,將包含這個參數。
  • INTERNAL_DATA?– 相對于上面的float3 worldRefl和float3 worldNormal,如果表面著色器為SurfaceOutput結構中的Normal賦值了,將使用該參數。為了獲得基于每個頂點法線貼圖( per-pixel normal map)的反射向量(reflection vector)需要使用世界反射向量(WorldReflectionVector (IN, o.Normal)),其中o.Normal表示的是切空間的法向量,而非世界坐標系下的法向量。
  • 你可能會問上面的COLOR semantic是什么意思?當你寫一個正常的片段著色器時,你得告訴別人你的輸入結構體每個變量代表什么意思?如果你夠瘋狂,你可以試試下面這樣定義:float2 MyUncleFred : TEXCOORD0; 并告訴別人MyUncleFred表示該模型的uv坐標。(畫外音就是這種變量命名方式很令人費解)在表面著色器中你唯一擔心的就是對COLOR類型的定義。float4 currentColor : COLOR;可以看做目前已經經過插值后的像素顏色。當然你也可以不用關心這些,不過建議你命名上最好規范些,方便自己也方便別人。

該shader實際做了哪些事?

現在我們還有兩行代碼沒有詳細討論:

Sampler2D _MainTex;

對每一個屬性值,我們定義了屬性值區域(Properties Section),該區域用來定義CG程序中使用的變量。在使用中,我們必須保證屬性名稱一致。

注意輸入結構體中的uv_MainTex是uv+對應屬性值(文中為_MainTex,注意前面帶下劃線是CG官方推薦的寫法),如果你使用uv2,那將寫作uv2_MainTex。注意Sampler2D _MainTex中的_MainTex變量是一個Sampler2D(這個Sampler2D,可以理解為引用一個2D Texture),它引用了Properties中的_MainTex(譯者注:注意兩者同名。解釋通了sampler2D是什么之后,還需要解釋下為什么在這里需要一句對_MainTex的聲明,之前我們不是已經在Properties里聲明過它是貼圖了么。答案是我們用來實例的這個shader其實是由兩個相對獨立的塊組成的,外層的屬性聲明,回滾等等是Unity可以直接使用和編譯的ShaderLab;而現在我們是在CGPROGRAM...ENDCG這樣一個代碼塊中,這是一段CG程序。對于這段CG程序,要想訪問在Properties中所定義的變量的話,必須使用和之前變量相同的名字進行聲明。于是其實sampler2D _MainTex;做的事情就是再次聲明并鏈接了_MainTex,使得接下來的CG程序能夠使用這個變量。),他可以根據指定的uv坐標來提供對應紋理上的像素值,而此處uv_MainTex的作用就是提供紋理_MainTex的uv坐標值。

如果我們定義了一個_Color變量,我們可以定義它的屬性為

float4 _Color;

我們surf函數中唯一一行代碼

o.Albedo = tex2d( _MainTex, IN.uv_MainTex).rgb;

tex2d的作用是利用IN.uv_MainTex所代表的uv坐標(注意我們上面指定了uv坐標產生的方式,所以此處的IN.uv_MainTex是自動生成的)對紋理_MainTex進行采樣。此處,對于o.Albedo我們只取顏色分量中的rgb三分量,其中alpha值(透明度)目前不需要,至少對于非透明物體alpha值得作用不大。

如果你要設置alpha值的話,可以像下面這樣賦值

float4 texColor = tex2d( _MainTex, IN.uv_MainTex );o.Albedo = texColor.rgb;o.Alpha = texColor.a;

總結

你已經了解了很多的術語,但是目前我們所寫的shader還相當有限,但是當學習完第二部分教程后,我們就可以做一些很酷炫的shader了,因為第二部分我們將開始使用多重紋理,法向量等等酷炫技術。

  • 在第二部分中,我們創建了一個實現積雪效果的shader,根據積雪的程度來修改模型,以呈現不同效果。
  • 在第三部分我們改進了我們的shader來混合巖石邊緣的積雪。
  • 在第四部分,我們使用黑色邊緣和漸變紋理來創建了具有卡通效果的shader。
  • 在第五部分,我們創建了一個頂點/片段多通道凹凸紋理著色器(vertex/fragment multipass bumped shader) – 其復雜程度遠遠超越表面著色器
  • 在第六部分,我們創建了一個頂點/片段著色器(vertex/fragment shader)來制作相比于我們第四部分使用表面著色器制作的卡通效果shader更好的shader。

總結

以上是生活随笔為你收集整理的Unity3D Shader 新手教程(1/6)的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。

主站蜘蛛池模板: 久久av影院 | 日本中文字幕一区二区 | 久久伊人国产 | 久久五月婷 | 女教师三上悠亚ssni-152 | 精品国产人妻一区二区三区 | 伊人色av | 欧洲女性下面有没有毛发 | 超碰在线国产97 | 超碰在线影院 | 久久最新精品 | 亚洲电影影音先锋 | 国产午夜久久久 | 成a人片亚洲日本久久 | 久久久久免费视频 | 老妇高潮潮喷到猛进猛出 | 国产精品99精品久久免费 | 国产成人99 | 91av短视频 | 久久久国产亚洲 | 亚洲国产精品欧美久久 | 亚洲精品大片www | 麻豆传媒在线观看 | 国产精品免费看久久久无码 | 手机av网站 | 免费欧美在线 | 四虎成人精品永久免费av九九 | 少妇高潮网站 | 国产精品无码无卡无需播放器 | 午夜影院0606 | 国产午夜av | 精品一区二区久久久久久按摩 | 加勒比精品在线 | 女人扒开腿免费视频app | 禁久久精品乱码 | 国产主播在线观看 | 热久久中文字幕 | 九九爱精品视频 | 午夜精彩视频 | 狠狠综合一区 | 欧美大片免费在线观看 | 国产精品破处 | 91偷拍富婆spa盗摄在线 | 欧美性大战久久久久久久 | 日韩av在线天堂 | 69sese| 久久久久久久久久久网站 | 亚洲一区欧美激情 | 影音先锋成人 | 欧美精品99 | 伊人啪啪网 | 欧美日视频 | 午夜之声l性8电台lx8电台 | 青草久久久| 97热久久| 我的公把我弄高潮了视频 | 精品欧美一区二区三区免费观看 | 91爱爱影院| 国产亚洲精品女人久久久久久 | 三级五月天 | 欧美日本韩国一区 | 在线色站| 日本人妻一区 | 中文字幕国产 | 香蕉成视频人app下载安装 | 欧美视频在线免费 | 在线中文字日产幕 | 大奶子情人 | 一区二区三区视频免费视 | 欧美亚洲第一区 | 七仙女欲春2一级裸体片 | 国产一级片毛片 | 前任攻略在线观看免费完整版 | 女性向片在线观看 | 免费乱淫视频 | 国产在线a视频 | 色综合色综合色综合 | 亚洲一卡二卡 | 粉嫩av| 毛片a | 成人免费观看视频大全 | 毛片麻豆 | 天堂av电影在线观看 | 荷兰av | 91亚洲天堂 | 天天看片中文字幕 | 国产99re | 少妇99 | 久久精品天天中文字幕人妻 | 国产男女无套免费网站 | 亚洲欧洲精品成人久久奇米网 | 在线观看www视频 | 国产精品亚洲а∨天堂免在线 | 日韩人妻无码一区二区三区 | 国产91福利| 蜜臀少妇久久久久久久高潮 | 欧美日韩一区二区三区免费 | 婷婷一级片 | 悠悠色在线 |