【Unity3D Shader程式設計】之五 聖誕夜篇 Unity中Shader的三種形態對比 混合操作合輯
本系列文章由出品,轉載請註明出處。
本文算是固定功能Shader的最後一篇,下一次更新應該就會開始講解表面Shader,而講解完表面Shader,後續文章最終會講解到頂點著色器和片段著色器(也就是可程式設計Shader)。
文章第一部分複習和進一步瞭解了Unity中Shader的三種形態,然後講解了固定功能Shader中混合操作的方方面面,然後以6個Shader的書寫作為實戰內容,最後建立了一個溫馨美好的聖誕夜場景進行了Shader的測試。
依舊是國際慣例,先上本文配套程式的截圖吧。
聖誕節就快到了,而下次更新就已經過了聖誕節,於是這次更新淺墨就提前把這個場景放出來吧,預祝大家聖誕節快樂~
雪花飄落:
可愛的聖誕雪人:
精心裝扮的聖誕樹:
月是故鄉明:
霧氣瀰漫:
OK,圖先就上這麼多。文章末尾有更多的執行截圖,並提供了源工程的下載。可執行的exe下載在這裡:
好的,我們正式開始。
一、再談Unity中Shader的三種形態
因為Unity中基礎的固定功能Shader的知識點基本上講完,下期開始就要準備講表面著色器(Surface Shader)了,所以在文章開頭,讓我們複習和更深入瞭解一下Unity中Shader的三種形態。
在Unity中,Shader便可以分成如下三種基本型別:
1.固定功能著色器(FixedFunction Shader)
2.表面著色器(SurfaceShader)
3.頂點著色器&片段著色器(Vertex Shader & Fragment Shader)
顧名思義,其中的固定功能著色器便是我們所說的固定功能渲染管線(fixed-functionrenderingpipelines)的具體表現,而表面著色器、頂點著色器以及片段著色器便屬於可程式設計渲染管線。下面分別對其進行簡單的介紹。
1.1Unity中的Shader形態之一:固定功能Shader
這裡的固定功能著色器可以說是Unity為Shader的書寫自帶的一層殼,Unity已經在內部為我們做了大量的工作,我們只要稍微記住一些關鍵字、一些規範就可以實現出很多不錯的效果。固定功能著色器是我們初學Unity Shader的最近幾篇文章中的主要學習物件。而後面的表面著色器、頂點著色器以及片段著色器就是在固定功能著色器的基礎上嵌套了CG語言的程式碼而成的更加複雜的著色器。我們來看看他們的一些基本概念。
固定管線是為了相容老式顯示卡。都為頂點光照,就是我們前四篇文章加上這篇文章中講到的內容。
其特徵是裡面的核心是下面Material材質屬性塊、沒有CGPROGRAM和ENDCG塊,以及各種頂點著色和片段著色的巨集命令。
一個光照材質完備版的固定功能Shader示例如下:
Shader "淺墨Shader程式設計/Volume5/固定功能的Shader示例" { //-------------------------------【屬性】----------------------------------------- Properties { _Color ("主顏色", Color) = (1,1,1,0) _SpecColor ("高光顏色", Color) = (1,1,1,1) _Emission ("自發光顏色", Color) = (0,0,0,0) _Shininess ("光澤度", Range (0.01, 1)) = 0.7 _MainTex ("基本紋理", 2D) = "white" {} } //--------------------------------【子著色器】-------------------------------- SubShader { //----------------通道--------------- Pass { //-----------材質------------ Material { //可調節的漫反射光和環境光反射顏色 Diffuse [_Color] Ambient [_Color] //光澤度 Shininess [_Shininess] //高光顏色 Specular [_SpecColor] //自發光顏色 Emission [_Emission] } //開啟光照 Lighting On //開啟獨立鏡面反射 SeparateSpecular On //設定紋理並進行紋理混合 SetTexture [_MainTex] { Combine texture * primary DOUBLE, texture * primary } } } }
我們將此Shader編譯後賦給材質,得到如下效果:
實際場景中的測試效果:
1.2 Unity中的Shader形態之二:表面著色器SurfaceShader
這部分算是Unity微創新自創的一套著色器標準。
表面著色器(Surface Shader)這個概念更多的只是在Unity中聽說,可以說是Unity自己發揚光大的一項使Shader的書寫門檻降低和更易用的技術。我們會在接下來的學習中逐漸意識到Unity是如何為我們把Shader的複雜性包裝起來,使其書寫的過程更便捷和易用
的。一些特性如下:
• SurfaceShader可以認為是一個光照Shader的語法塊、一個光照VS/FS的生成器。減少了開發者寫重複程式碼的需要。
• 特徵是在SubShader裡出現CGPROGRAM和ENDCG塊。(而不是出現在Pass裡。因為SurfaceShader自己會編譯成多個Pass。)
• 編譯指令是:
#pragma surface surfaceFunction lightModel[optionalparams]
o surfaceFunction:surfaceShader函式,形如void surf (Input IN, inoutSurfaceOutput o)
o lightModel:使用的光照模式。包括Lambert(漫反射)和BlinnPhong(鏡面反射)。
也可以自己定義光照函式。比如編譯指令為#pragma surface surf MyCalc
在Shader裡定義half4 LightingMyCalc (SurfaceOutputs, 引數略)函式進行處理(函式名在簽名加上了“Lighting”)。
• 我們自己定義輸入資料結構(比如上面的Input)、編寫自己的Surface函式處理輸入、最終輸出修改過後的SurfaceOutput。而SurfaceOutput的定義為:
struct SurfaceOutput{ half3 Albedo; // 紋理顏色值(r, g, b) half3 Normal; // 法向量(x, y, z) half3 Emission; // 自發光顏色值(r, g, b) half Specular; // 鏡面反射度 half Gloss; // 光澤度 half Alpha; // Alpha不透明度};
上面是一些特性總結,讓我們看一個具體Shader示例:
Shader "淺墨Shader程式設計/Volume5/表面Shader示例 " { //-------------------------------【屬性】----------------------------------------- Properties { _MainTex ("【紋理】Texture", 2D) = "white" {} _BumpMap ("【凹凸紋理】Bumpmap", 2D) = "bump" {} _RimColor ("【邊緣顏色】Rim Color", Color) = (0.17,0.36,0.81,0.0) _RimPower ("【邊緣顏色強度】Rim Power", Range(0.6,9.0)) = 1.0 } //----------------------------【開始一個子著色器】--------------------------- SubShader { //渲染型別為Opaque,不透明 Tags { "RenderType" = "Opaque" } //-------------------開始CG著色器程式語言段----------------- CGPROGRAM //使用蘭伯特光照模式 #pragma surface surf Lambert //輸入結構 struct Input { float2 uv_MainTex;//紋理貼圖 float2 uv_BumpMap;//法線貼圖 float3 viewDir;//觀察方向 }; //變數宣告 sampler2D _MainTex;//主紋理 sampler2D _BumpMap;//凹凸紋理 float4 _RimColor;//邊緣顏色 float _RimPower;//邊緣顏色強度 //表面著色函式的編寫 void surf (Input IN, inout SurfaceOutput o) { //表面反射顏色為紋理顏色 o.Albedo = tex2D (_MainTex, IN.uv_MainTex).rgb; //表面法線為凹凸紋理的顏色 o.Normal = UnpackNormal (tex2D (_BumpMap, IN.uv_BumpMap)); //邊緣顏色 half rim = 1.0 - saturate(dot (normalize(IN.viewDir), o.Normal)); //邊緣顏色強度 o.Emission = _RimColor.rgb * pow (rim, _RimPower); } //-------------------結束CG著色器程式語言段------------------ ENDCG } //“備胎”為普通漫反射 Fallback "Diffuse" }
我們將此Shader編譯後賦給材質,得到如下效果:
調各種顏色玩一玩:
而實際場景中的測試效果(對應於一開始的金色):
1.3 Unity中的Shader形態之三:可程式設計Shader
可程式設計Shader其實就是頂點著色器和片段著色器,這一部分和DirectX系的HLSL和CG著色器語言聯絡緊密。其實就是Unity給HLSL和CG報了一個ShaderLab的殼。
研究過Direct3D和OpenGL著色器程式設計的童鞋們一定對頂點著色器和片段著色器不陌生。我們來簡單介紹一下他們的用途。
頂點著色器:產生紋理座標,顏色,點大小,霧座標,然後把它們傳遞給裁剪階段。
片段著色器:進行紋理查詢,決定什麼時候執行紋理查詢,是否進行紋理查詢,及把什麼作為紋理座標。
可程式設計Shader的特點為:
- 功能最強大、最自由的形態。
- 特徵是在Pass裡出現CGPROGRAM和ENDCG塊
- 編譯指令#pragma。詳見官網Cg snippets。其中重要的包括:
編譯指令
示例/含義
#pragma vertex name #pragma fragment name
替換name,來指定Vertex Shader函式、Fragment Shader函式。
#pragma target name
替換name(為2.0、3.0等)。設定編譯目標shader model的版本。
#pragma only_renderers name name ... #pragma exclude_renderers name name...
#pragma only_renderers gles gles3, #pragma exclude_renderers d3d9 d3d11 opengl, 只為指定渲染平臺(render platform)編譯
- 關於引用庫。通過形如#include "UnityCG.cginc"引入指定的庫。常用的就是UnityCG.cginc了。其他庫詳見官網Built-in shader include files。
- ShaderLab內建值。Unity給Shader程式提供了便捷的、常用的值,比如下面例子中的UNITY_MATRIX_MVP就代表了這個時刻的MVP矩陣。詳見官網ShaderLab built-in values。
- Shader輸入輸出引數語義(Semantics)。在管線流程中每個階段之間(比如Vertex Shader階段和FragmentShader階段之間)的輸入輸出引數,通過語義字串,來指定引數的含義。常用的語義包括:COLOR、SV_Position、TEXCOORD[n]。完整的引數語義可見HLSL Semantic(由於是HLSL的連線,所以可能不完全在Unity裡可以使用)。
- 特別地,因為Vertex Shader的的輸入往往是管線的最開始,Unity為此內建了常用的資料結構:
資料結構
含義
appdata_base
頂點著色器輸入位置、法線以及一個紋理座標。
appdata_tan
頂點著色器輸入位置、法線、切線以及一個紋理座標。
appdata_full
頂點著色器輸入位置、法線、切線、頂點顏色以及兩個紋理座標。
appdata_img
頂點著色器輸入位置以及一個紋理座標。
讓我們用一個可程式設計著色器Shader示例結束此部分的講解:
Shader "淺墨Shader程式設計/Volume5/可程式設計Shader示例" { //-------------------------------【屬性】-------------------------------------- Properties { _Color ("Color", Color) = (1.0,1.0,1.0,1.0) _SpecColor ("Specular Color", Color) = (1.0,1.0,1.0,1.0) _Shininess ("Shininess", Float) = 10 } //--------------------------------【子著色器】-------------------------------- SubShader { //-----------子著色器標籤---------- Tags { "LightMode" = "ForwardBase" } //----------------通道--------------- Pass { //-------------------開始CG著色器程式語言段----------------- CGPROGRAM #pragma vertex vert #pragma fragment frag //---------------宣告變數-------------- uniform float4 _Color; uniform float4 _SpecColor; uniform float _Shininess; //--------------定義變數-------------- uniform float4 _LightColor0; //--------------頂點輸入結構體------------- struct vertexInput { float4 vertex : POSITION; float3 normal : NORMAL; }; //--------------頂點輸出結構體------------- struct vertexOutput { float4 pos : SV_POSITION; float4 col : COLOR; }; //--------------頂點函式-------------- vertexOutput vert(vertexInput v) { vertexOutput o; //一些方向 float3 normalDirection = normalize( mul( float4(v.normal, 0.0), _World2Object ).xyz ); float3 viewDirection = normalize( float3( float4( _WorldSpaceCameraPos.xyz, 1.0) - mul(_Object2World, v.vertex).xyz ) ); float3 lightDirection; float atten = 1.0; //光照 lightDirection = normalize(_WorldSpaceLightPos0.xyz); float3 diffuseReflection = atten * _LightColor0.xyz * max( 0.0, dot( normalDirection, lightDirection ) ); float3 specularReflection = atten * _LightColor0.xyz * _SpecColor.rgb * max( 0.0, dot( normalDirection, lightDirection ) ) * pow( max( 0.0, dot( reflect( -lightDirection, normalDirection ), viewDirection ) ), _Shininess ); float3 lightFinal = diffuseReflection + specularReflection + UNITY_LIGHTMODEL_AMBIENT; //計算結果 o.col = float4(lightFinal * _Color.rgb, 1.0);//顏色 o.pos = mul(UNITY_MATRIX_MVP, v.vertex);//位置 return o; } //--------------片段函式--------------- float4 frag(vertexOutput i) : COLOR { return i.col; } //-------------------結束CG著色器程式語言段------------------ ENDCG } } //備胎 Fallback "Diffuse" }
我們將此Shader編譯後賦給材質,得到如下效果:
可以發現就算這麼簡單的可程式設計Shader其細節效果也是非常出色,比固定功能Shader和表面Shader都看起來高階。我們依然是調各種顏色玩一玩:
實際場景中的測試效果:
OK,下面我們來看本次文章的主角——blending操作。
二、混合操作(Blending)
我們直奔主題吧。混合操作最常見的用途便是用來製作透明物體、或者是進行紋理的混合。它是Shader渲染的最後一步:
如上圖所示,正被渲染的畫素經過頂點光照、頂點著色器、剔除和深度測試,霧效、Alpha測試等一系列操作之後,最後一步便是混合操作。這個時候計算結果即將被輸出到幀緩衝中。而混合操作,就是管理如何將這些畫素輸出到幀快取中的這樣一個過程——是直接替換原來的,是一加一的混合,還是有Alpha參與的不等比地混合等等。
混合操作有兩個物件:源和目標,因此也有兩個對應的因子,即源因子和目標因子(對應於下面講解的Blend SrcFactor DstFactor操作)。
而如果我們把RGB顏色通道和Alpha通道分開來操作的話,混合就有了4個操作物件(對應於下面講解的Blend SrcFactor DstFactor,SrcFactorA DstFactorA操作)。
2.1混合操作相關的句法
Blend Off
Turn off blending 關閉混合
Blend SrcFactorDstFactor
基本的配置並啟動混操作。對產生的顏色乘以SrcFactor.對 已存在於螢幕的顏色乘以DstFactor,並且兩者將被疊加在一起。
Blend SrcFactorDstFactor, SrcFactorA DstFactorA
同上,但是使用不同的要素來混合alpha通道,也就是有了4個操作物件
BlendOp Add /Min | Max | Sub | RevSub
此操作不是Blend操作一樣新增混合顏色在一起,而是對它們做不同的操作。
而如下便是常用混合操作符(blend operations)的含義列舉:
Add
將源畫素和目標畫素相加.
Sub
用源畫素減去目標畫素
RevSub
用目標畫素減去源畫素
Min
取目標畫素和源畫素顏色的較小者作為結果
Max
取目標畫素和源畫素顏色的較大者作為結果
2.2 混合因子(Blend factors)列舉
Blend SrcFactor DstFactor
以下所有的屬性都可作為SrcFactor或DstFactor。其中,Source指的是被計算過的顏色,Destination是已經在螢幕上的顏色。
One 值為1,使用此因子來讓幀緩衝區源顏色或是目標顏色完全的通過。 Zero 值為0,使用此因子來刪除幀緩衝區源顏色或目標顏色的值。 SrcColor 使用此因子為將當前值乘以幀緩衝區源顏色的值 SrcAlpha 使用此因子為將當前值乘以幀緩衝區源顏色Alpha的值。 DstColor 使用此因子為將當前值乘以幀緩衝區源顏色的值。 DstAlpha 使用此因子為將當前值乘以幀緩衝區源顏色Alpha分量的值。 OneMinusSrcColor 使用此因子為將當前值乘以(1 -幀緩衝區源顏色值) OneMinusSrcAlpha 使用此因子為將當前值乘以(1 -幀緩衝區源顏色Alpha分量的值) OneMinusDstColor 使用此因子為將當前值乘以(1 –目標顏色值) OneMinusDstAlpha 使用此因子為將當前值乘以(1 –目標Alpha分量的值) 2.3 常見的混合操作句法示例
上面都是一些句法和列表的列舉,往往會令人一頭霧水,下面這是一些示例,用其中的任何一句加在Pass中就可以實現對應的混合操作了:
Blend SrcAlpha OneMinusSrcAlpha // Alpha混合Blend One One // 相加Blend One OneMinusDstColor // 比較柔和的相加(SoftAdditive)Blend DstColor Zero // 乘法Blend DstColor SrcColor // 2倍乘法
三、QianMo's Toolkit升級到v1.3
這次QianMo's Toolkit又迎來了新的特性——飛翔。
將指令碼賦給Controller,並調整相應的速度,(並可以先禁掉之前的滑鼠視角控制相關指令碼)然後點執行,並可以在天空中自由地飛翔了。
其中用W、A、S、D控制前後左右,R、F控制上升下降。
其程式碼如下:
//-----------------------------------------------【指令碼說明】-------------------------------------------------------// 指令碼功能: 控制Contorller在場景中飛翔// 使用語言: C#// 開發所用IDE版本:Unity4.5 06f 、Visual Studio 2010 // 2014年12月 Created by 淺墨 // 更多內容或交流,請訪問淺墨的部落格:http://blog.csdn.net/poem_qianmo//---------------------------------------------------------------------------------------------------------------------//-----------------------------------------------【使用方法】-------------------------------------------------------// 第一步:在Unity中拖拽此指令碼到場景的Controller之上,或在Inspector中[Add Component]->[淺墨's Toolkit]->[SetMaxFPS]// 第二步:在面板中設定相關滑鼠速度//---------------------------------------------------------------------------------------------------------------------using UnityEngine;using System.Collections;//新增元件選單[AddComponentMenu("淺墨's Toolkit/FlyController")]public class FlyController : MonoBehaviour{ //引數定義 public float lookSpeed = 5.0f; public float moveSpeed = 1.0f; public float rotationX = 0.0f; public float rotationY = 0.0f; void Update() { //獲取滑鼠偏移量 rotationX += Input.GetAxis("Mouse X") * lookSpeed; rotationY += Input.GetAxis("Mouse Y") * lookSpeed; rotationY = Mathf.Clamp(rotationY, -90, 90); //滑鼠控制視角 transform.localRotation = Quaternion.AngleAxis(rotationX, Vector3.up); transform.localRotation *= Quaternion.AngleAxis(rotationY, Vector3.left); transform.position += transform.forward * moveSpeed * Input.GetAxis("Vertical"); transform.position += transform.right * moveSpeed * Input.GetAxis("Horizontal"); //I鍵,向上平移 if (Input.GetKey(KeyCode.R)) transform.position += transform.up * moveSpeed; //K鍵,向下平移 if (Input.GetKey(KeyCode.F)) transform.position -= transform.up * moveSpeed; }}
就這樣,我們的QianMo’s Toolkit中的工具越來越多:
四、Shader書寫實戰
1. 紋理載入Shader
因為後面幾個shader的需要,先根據我們之前所學,幾行程式碼就可以實現一個紋理載入Shader:
Shader "淺墨Shader程式設計/Volume5/18.基本紋理載入" { //-------------------------------【屬性】-------------------------------------- Properties { _MainTex ("基本紋理", 2D) = "black" { } } //--------------------------------【子著色器】-------------------------------- SubShader { //-----------子著色器標籤---------- Tags { "Queue" = "Geometry" } //子著色器的標籤設為幾何體 //----------------通道--------------- Pass { //設定紋理 SetTexture [_MainTex] { combine texture } } }}
我們將此Shader編譯後賦給材質,得到如下效果:
實際場景中的執行效果如下:
2.基本blend使用
在上面簡單的texture載入的Shader的基礎上加上一行關於blend的程式碼,就成了我們今天的第二個Shader:
Shader "淺墨Shader程式設計/Volume5/19.基本blend使用" { //-------------------------------【屬性】----------------------------------------- Properties { _MainTex ("將要混合的基本紋理", 2D) = "black" { } } //--------------------------------【子著色器】---------------------------------- SubShader { //-----------子著色器標籤---------- Tags { "Queue" = "Geometry" } //子著色器的標籤設為幾何體 //----------------通道--------------- Pass { //進行混合 Blend DstColor Zero // 乘法 //設定紋理 SetTexture [_MainTex] { combine texture } } }}
我們將此Shader編譯後賦給材質,得到如下效果:
我們採用的是乘法混合操作( Blend DstColor Zero),可以發現顏色相對於第一個Shader有了稍微的變暗。
雖然肉眼很難看出區別,但實際上的確是有變化的:
3.基本blend使用+顏色可調
再給我們的Shader加上一點可自定義的顏色,並讓紋理的alpha通道插值混合頂點顏色 。程式碼如下:
Shader "淺墨Shader程式設計/Volume5/20.基本blend使用+顏色可調" { //-------------------------------【屬性】----------------------------------------- Properties { _MainTex ("將混合的紋理", 2D) = "black" {} _Color ("主顏色", Color) = (1,1,1,0) } //--------------------------------【子著色器】-------------------------------- SubShader { //-----------子著色器標籤---------- Tags { "Queue" = "Transparent" } //子著色器的標籤設為透明 //----------------通道--------------- Pass { Blend One OneMinusDstColor // 柔性相加 SetTexture [_MainTex] { // 使顏色屬性進入混合器 constantColor [_Color] // 使用紋理的alpha通道插值混合頂點顏色 combine constant lerp(texture) previous } } }}
我們將此Shader編譯後賦給材質,得到如下效果:
調成各種顏色:
實際場景中的測試效果:
4.基本blend使用+頂點光照
在之前Shader的基礎上,給我們的Shader再加上材質屬性和頂點光照:
Shader "淺墨Shader程式設計/Volume5/21.基本blend使用+頂點光照" { //-------------------------------【屬性】----------------------------------------- Properties { _MainTex ("Texture to blend", 2D) = "black" {} _Color ("主顏色", Color) = (1,1,1,0) } //--------------------------------【子著色器】-------------------------------- SubShader { //-----------子著色器標籤---------- Tags { "Queue" = "Transparent" } //----------------通道--------------- Pass { //【1】設定材質 Material { Diffuse [_Color] Ambient [_Color] } //【2】開啟光照 Lighting On Blend One OneMinusDstColor // Soft Additive SetTexture [_MainTex] { // 使顏色屬性進入混合器 constantColor [_Color] // 使用紋理的alpha通道插值混合頂點顏色 combine constant lerp(texture) previous } } }}
於是結果如下:
調各種顏色看看:
在場景中的測試效果圖為:
5.實現玻璃效果第二版
之前我們用剔除實現過一版玻璃效果,這次我們來用blend實現完全不一樣的玻璃效果,需要載入一個cubemap(其實根據cubemap的選擇不同,會實現不同的效果,比如本次的最終效果就有點像金屬材質)。
Shader的程式碼如下:
Shader "淺墨Shader程式設計/Volume5/22.玻璃效果v2" { //-------------------------------【屬性】-------------------------------------- Properties { _Color ("Main Color", Color) = (1,1,1,1) _MainTex ("Base (RGB) Transparency (A)", 2D) = "white" {} _Reflections ("Base (RGB) Gloss (A)", Cube) = "skybox" { TexGen CubeReflect } } //--------------------------------【子著色器】-------------------------------- SubShader { //-----------子著色器標籤---------- Tags { "Queue" = "Transparent" } //----------------通道--------------- Pass { //進行紋理混合 Blend One One //設定材質 Material { Diffuse [_Color] } //開光照 Lighting On //和紋理相乘 SetTexture [_Reflections] { combine texture Matrix [_Reflection] } } }}
我們將此Shader編譯後賦給材質,得到如下效果,可以發現最終效果是一個帶室內場景反射的金屬材質:
實際場景中的測試效果:
6. 實現玻璃效果第三版
我們給上面的第二版加上第二個pass,最終程式碼如下:
Shader "淺墨Shader程式設計/Volume5/23.玻璃效果v3" { //-------------------------------【屬性】----------------------------------------- Properties { _Color ("Main Color", Color) = (1,1,1,1) _MainTex ("Base (RGB) Transparency (A)", 2D) = "white" {} _Reflections ("Base (RGB) Gloss (A)", Cube) = "skybox" { TexGen CubeReflect } } //--------------------------------【子著色器】---------------------------------- SubShader { //-----------子著色器標籤---------- Tags { "Queue" = "Transparent" } //----------------通道1-------------- Pass { Blend SrcAlpha OneMinusSrcAlpha Material { Diffuse [_Color] } Lighting On SetTexture [_MainTex] { combine texture * primary double, texture * primary } } //----------------通道2-------------- Pass { //進行紋理混合 Blend One One //設定材質 Material { Diffuse [_Color] } //開光照 Lighting On //和紋理相乘 SetTexture [_Reflections] { combine texture Matrix [_Reflection] } } }}
載入同樣的紋理和cubemap,得到的效果更加醇厚優異:
實際場景中的測試效果:
OK,這次的Shader實戰就是上面的這些了。
五、聖誕夜場景建立
就像文章開頭中說的,聖誕節就快到了,而下次更新就已經過了聖誕節,於是這次更新淺墨就提前把這個精心準備的聖誕夜場景放出來吧,預祝大家聖誕節快樂~
以大師級美工鬼斧神工的場景作品為基礎,淺墨調整了場景佈局,加入了音樂,並加入了更多高階特效,於是便得到了如此這次溫馨美好的場景。
而冬天穿衣不便,加上路滑,淺墨故意把controller調出了走路打滑的感覺。
運行遊戲,聖誕音樂漸漸響起,雪白的雪花靜靜飄落,我們來到美麗的聖誕夜:
雪花飛揚:
月上樹梢:
淺墨精心裝扮的聖誕樹:
月光給屋頂披上一層清輝:
火爐、聖誕禮物:
月是故鄉明:
可愛的聖誕雪人:
淺墨是不會告訴你們是怎麼進到門緊關的房子裡面來的,自己摸索吧~
大雪紛飛的路:
最後放一張這次Shader的全家福:
OK,美圖就放這麼多。遊戲場景可執行的exe可以在文章開頭中提供的連結下載。而以下是源工程的下載連結。
本篇文章的示例程式源工程請點選此處下載:
好的,本篇文章到這裡就全部結束了。
淺墨在這裡提前祝大家聖誕節快樂~
下週一,新的遊戲程式設計之旅,我們不見不散~
相關推薦
【Unity3D Shader程式設計】之五 聖誕夜篇 Unity中Shader的三種形態對比 混合操作合輯
本系列文章由出品,轉載請註明出處。 本文算是固定功能Shader的最後一篇,下一次更新應該就會開始講解表面Shader,而講解完表面Shader,後續文章最終會講解到頂點著色器和片段著色器(也就是可程式設計Shader)。文章第一部分複習和進一步瞭解了Unity中Shader的
【淺墨Unity3D Shader程式設計】之五 聖誕夜篇: Unity中Shader的三種形態對比&混合操作合輯
本系列文章由出品,轉載請註明出處。 QQ交流群:330595914 本文算是固定功能Shader的最後一篇,下一次更新應該就會開始講解表面Shader,而講解完表面Shader,後續文章最終會講解到頂點著色器和片段著色器(也就是可程式設計
【Java併發程式設計】之五:volatile變數修飾符—意料之外的問題(含程式碼)
示例程式 下面給出一段程式碼,通過其執行結果來說明使用關鍵字volatile產生的差異,但實際上遇到了意料之外的問題: public class Volatile extends Object implements Runnable { //value變數沒有被標記為volatile private
【Unity3D Shader程式設計】之十 深入理解Unity5中的Standard Shader(二)&螢幕油畫特效的實現
本系列文章由出品,轉載請註明出處。 本文工程使用的Unity3D版本:5.2.1 概要:本文講解了Unity中著色器編譯多樣化的思路,並對Standard Shader中正向基礎渲染通道的原始碼進行了分析,以及對螢幕油畫特效進行了實現。眾所周知,Unity官方文件對Shade
【Unity Shader程式設計】之十五 螢幕高斯模糊(Gaussian Blur)後期特效的實現
本篇文章將分析如何在Unity中基於Shader實現高斯模糊屏幕後期特效。首先放出最終的實現效果。如下幾幅圖,是在Unity中使用本文所實現的Shader得到的高斯模糊屏幕後期特效與原始圖的效果對比圖。卡通風格的效果測試:寫實風格的效果測試:OK,下面我們開始分析如何在Uni
【Unity3D Shader程式設計】之八 Unity5新版Shader模板原始碼解析&徑向模糊螢幕特效的實現
概要:本文對Unity5中全新的三種Shader模板的原始碼進行了解析,然後還講解了運動模糊螢幕特效的實現方法。前言時隔9個月,終於有了一些稍微空閒的時間,可以進行一些更新了。鑑於以後可以用來寫部落格的時間肯定不會非常充裕,個人覺得再講Shader的基礎寫法比較拖節奏,
【Unity3D Shader程式設計】之十二 可程式設計Shader初步 & 漫反射可程式設計Shader的實現
毛星雲,網路ID「淺墨」,90後,熱愛遊戲開發、遊戲引擎、計算機圖形、實時渲染等技術,就職於騰訊互娛。 微軟最有價值專家 著作《Windows遊戲程式設計之從零開始》、《OpenCV3程式設計入門》 碩士就讀於南京航空航天大學航天學院(2013級碩士研究生),已於2016年三月畢業。本科
【Unity3D Shader程式設計】之六 暗黑城堡篇: 表面著色器(Surface Shader)的寫法(一)
毛星雲,網路ID「淺墨」,90後,熱愛遊戲開發、遊戲引擎、計算機圖形、實時渲染等技術,就職於騰訊互娛。 微軟最有價值專家 著作《Windows遊戲程式設計之從零開始》、《OpenCV3程式設計入門》 碩士就讀於南京航空航天大學航天學院(2013級碩士研究生),已於2016年三月畢業。本科
【Java併發程式設計】之二十:併發新特性—Lock鎖和條件變數(含程式碼)
簡單使用Lock鎖 Java 5中引入了新的鎖機制——java.util.concurrent.locks中的顯式的互斥鎖:Lock介面,它提供了比synchronized更加廣泛的鎖定操作。Lock介面有3個實現它的類:ReentrantLock、Reetrant
【Java併發程式設計】之二十二:併發新特性—障礙器CyclicBarrier(含程式碼)
CyclicBarrier(又叫障礙器)同樣是Java 5中加入的新特性,使用時需要匯入java.util.concurrent.CylicBarrier。它適用於這樣一種情況:你希望建立一組任
【Java併發程式設計】之六:Runnable和Thread實現多執行緒的區別(含程式碼)
Java中實現多執行緒有兩種方法:繼承Thread類、實現Runnable介面,在程式開發中只要是多執行緒,肯定永遠以實現Runnable介面為主,因為實現Runnable介面相比繼承Th
【Java併發程式設計】之二十三:併發新特性—訊號量Semaphore(含程式碼)
在作業系統中,訊號量是個很重要的概念,它在控制程序間的協作方面有著非常重要的作用,通過對訊號量的不同操作,可以分別實現程序間的互斥與同步。當然它也可以用於多執行緒的控制,我們完全可以通過
Step 16:【PROCESSING 遊戲程式設計】之黃金礦工
之前,我偶看到 FAL 利用 Processing/p5.js 製作的一些迷你小遊戲(倘若你對此感興趣,請點選這裡)。Simple but fun,這亦讓我萌生了學習製作遊戲的念頭。文學、音樂、舞蹈、雕塑、繪畫、建築、戲劇、電影,“Game”作為備受爭議的第九藝
【Java併發程式設計】之十六:深入Java記憶體模型——happen-before規則及其對DCL的分析(含程式碼)
happen—before規則介紹 Java語言中有一個“先行發生”(happen—before)的規則,它是Java記憶體模型中定義的兩項操作之間的偏序關係,如果操作A先行發生於操作B,其意思就是說,在發生操作B之前,操作A產生的影響都能被操作B觀察到,“影響
【Java併發程式設計】之八:多執行緒環境中安全使用集合API(含程式碼)
在集合API中,最初設計的Vector和Hashtable是多執行緒安全的。例如:對於Vector來說,用來新增和刪除元素的方法是同步的。如果只有一個執行緒與Vector的例項互動,那麼,要求獲取
【Java併發程式設計】之十:使用wait/notify/notifyAll實現執行緒間通訊的幾點重要說明
在Java中,可以通過配合呼叫Object物件的wait()方法和notify()方法或notifyAll()方法來實現執行緒間的通訊。線上程中呼叫wait()方法,將阻塞等待其他執行緒的通知(其
【Java併發程式設計】之二十三:併發新特性—訊號量Semaphore(含程式碼)(r)
執行緒pool-1-thread-1獲得許可:0 執行緒pool-1-thread-1釋放許可:0 當前允許進入的任務個數:5 執行緒pool-1-thread-2獲得許可:1 執行緒pool-1-thread-6獲得許可:5 執行緒pool-1-thread-4獲得許可:3 執行緒pool-1-thread
【圖解資料結構】 一組動畫徹底理解二叉樹三種遍歷
二叉樹的遍歷是指從根結點出發,按照某種次序依次訪問二叉樹中所有結點,使得每個結點被訪問一次且僅被訪問一次。 在二叉樹的遍歷中存在三種較為常用的遍歷方式:前序遍歷、中序遍歷、後序遍歷。接下來我將嘗試著用三組動畫向讀者詳細的介紹這三種遍歷方式的邏輯思路,希望讓讀者看到任何的二叉樹都能在腦海中快速的勾勒出動畫。
【GPU精粹與Shader程式設計】(五) 《GPU Gems 2》全書核心內容提煉總結 · 下篇
本文由@淺墨_毛星雲 出品,首發於知乎專欄,轉載請註明出處 本文核心內容為《GPU Gems 2》中講到的真實感水體渲染,以及真實感頭髮渲染、通用的折射模擬、改進的Perlin噪聲等次核心內容。
【Unity3D自學記錄】Unity3D之自制小鐘表
new 一個 unity cond 代碼 enter 歐拉角 onu text 今天來寫一個小鐘表,事實上非常easy,就運用到了歐拉角。 首先創建時鐘、分鐘、秒鐘以及4個點(12點、3點、6點、9點)偷懶了~~沒弄那麽多點。 時鐘、分鐘、秒鐘這三個父級的中心一定要註意