C#使用Shader實現(xiàn)夜幕降臨倒計時的效果
最近火爆全球的PC游戲Battlerite(戰(zhàn)爭儀式)在倒計時的會生成一種類似夜幕降臨的效果,會以戰(zhàn)場中心為圓心,某個長度為半徑的范圍外是暗的,而這個半徑會逐漸縮小,而圓之外的陰暗部分是附著地形的,本文就嘗試使用屏幕后處理的手段來實現(xiàn)這種效果。
(暫時缺少Battlerite的截圖,稍后會補上)
首先看效果圖:
注:本文參考了Tasharen Fog of War插件
創(chuàng)建一個C#腳本,命名為NightFall.cs,為NightFall類創(chuàng)建一些公共變量(nightColor,center和radius),另外還需要一個NightFall.shader。
首先,我們要確定這個效果是在場景渲染之后還未送到屏幕顯示之前的實現(xiàn)的,所以,NightFall腳本是要掛載到主Camera上的(添加特性[RequireComponent(typeof(Camera))]),并要實現(xiàn)OnRenderImage方法。
其次,在OnRenderImage方法里,我們最終需要調(diào)用Graphics.Blit方法,而這個方法的第三個參數(shù)是Material類型,所以我們需要在代碼里創(chuàng)建一個臨時材質(zhì),這個材質(zhì)使用了NightFall.shader。
再次,我們需要在Shader里面將屏幕坐標轉(zhuǎn)換為世界坐標,來計算與世界中心的坐標,所以我們需要MVP的逆矩陣(參考Shader山下(十六)坐標空間與轉(zhuǎn)換矩陣)。
最后,為了附著地形,我們需要在Shader計算深度,也就是坐標點與攝像機的相對距離,所以需要攝像機的位置。
C#的代碼:
using UnityEngine;
[RequireComponent(typeof(Camera))]
public class NightFall : MonoBehaviour
{
public Shader shader;
public Color nightColor = new Color(0.05f, 0.05f, 0.05f, 0.5f);
public Vector3 center = Vector3.zero;
public float radius = 10;
Camera mCam;
Matrix4x4 mInverseMVP;
Material mMat;
/// The camera we're working with needs depth.
void OnEnable ()
{
mCam = GetComponent<Camera>();
mCam.depthTextureMode = DepthTextureMode.Depth;
if (shader == null) shader = Shader.Find("Image Effects/NightFall");
}
/// Destroy the material when disabled.
void OnDisable () { if (mMat) DestroyImmediate(mMat); }
/// Automatically disable the effect if the shaders don't support it.
void Start ()
{
if (!SystemInfo.supportsImageEffects || !shader || !shader.isSupported)
{
enabled = false;
}
}
// Called by camera to apply image effect
void OnRenderImage (RenderTexture source, RenderTexture destination)
{
print (nightColor);
print (destination);
// Calculate the inverse modelview-projection matrix to convert screen coordinates to world coordinates
mInverseMVP = (mCam.projectionMatrix * mCam.worldToCameraMatrix).inverse;
if (mMat == null)
{
mMat = new Material(shader);
mMat.hideFlags = HideFlags.HideAndDontSave;
}
Vector4 camPos = mCam.transform.position;
// This accounts for Anti-aliasing on Windows flipping the depth UV coordinates.
// Despite the official documentation, the following approach simply doesn't work:
// http://docs.unity3d.com/Documentation/Components/SL-PlatformDifferences.html
if (QualitySettings.antiAliasing > 0)
{
RuntimePlatform pl = Application.platform;
if (pl == RuntimePlatform.WindowsEditor ||
pl == RuntimePlatform.WindowsPlayer ||
pl == RuntimePlatform.WindowsWebPlayer)
{
camPos.w = 1f;
}
}
mMat.SetVector("_CamPos", camPos);
mMat.SetMatrix("_InverseMVP", mInverseMVP);
mMat.SetColor("_NightColor", nightColor);
mMat.SetVector ("_Center", center);
mMat.SetFloat ("_Radius", radius);
Graphics.Blit(source, destination, mMat);
}
}
Shader代碼:
Shader "Image Effects/NightFall"
{
Properties
{
_NightColor ("Night Color", Color) = (0.05, 0.05, 0.05, 0.05)
_Center ("Center", Vector) = (0,0,0,0)
_Radius ("Radius", float) = 10
}
SubShader
{
Pass
{
ZTest Always
Cull Off
ZWrite Off
Fog { Mode off }
Blend SrcAlpha OneMinusSrcAlpha
CGPROGRAM
#pragma vertex vert_img
#pragma fragment frag vertex:vert
#pragma fragmentoption ARB_precision_hint_fastest
#include "UnityCG.cginc"
sampler2D _CameraDepthTexture;
uniform float4x4 _InverseMVP;
uniform float4 _CamPos;
uniform half4 _NightColor;
uniform half4 _Center;
uniform half _Radius;
struct Input
{
float4 position : POSITION;
float2 uv : TEXCOORD0;
};
void vert (inout appdata_full v, out Input o)
{
o.position = mul(UNITY_MATRIX_MVP, v.vertex);
o.uv = v.texcoord.xy;
}
float3 CamToWorld (in float2 uv, in float depth)
{
float4 pos = float4(uv.x, uv.y, depth, 1.0);
pos.xyz = pos.xyz * 2.0 - 1.0;
pos = mul(_InverseMVP, pos);
return pos.xyz / pos.w;
}
fixed4 frag (Input i) : COLOR
{
#if SHADER_API_D3D9 || SHADER_API_D3D11
float2 depthUV = i.uv;
depthUV.y = lerp(depthUV.y, 1.0 - depthUV.y, _CamPos.w);
float depth = UNITY_SAMPLE_DEPTH(tex2D(_CameraDepthTexture, depthUV));
float3 pos = CamToWorld(depthUV, depth);
#else
float depth = UNITY_SAMPLE_DEPTH(tex2D(_CameraDepthTexture, i.uv));
float3 pos = CamToWorld(i.uv, depth);
#endif
// Limit to sea level
if (pos.y < 0.0)
{
// This is a simplified version of the ray-plane intersection formula: t = -( N.O + d ) / ( N.D )
float3 dir = normalize(pos - _CamPos.xyz);
pos = _CamPos.xyz - dir * (_CamPos.y / dir.y);
}
half4 col;
float dis = length(pos.xz - _Center.xz);
if (dis < _Radius)
{
col = fixed4(0,0,0,0);
}
else
{
col = _NightColor;
}
return col;
}
ENDCG
}
}
Fallback off
}
需要說明的幾個點:
1、因為平臺差異性,為了兼容Direct3D,所以在C#和shader里通過CamPos(_CamPos)的w分量來調(diào)整uv坐標。
2、這里雖然沒有聲明_MainTex,但是_MainTex實際上就是即將成像的屏幕圖像,所以這里的i.uv也就是指屏幕圖像的紋理坐標。
3、_CameraDepthTexture是攝像機的深度紋理,通過UNITY_SAMPLE_DEPTH方法獲取深度。
4、CamToWorld里面,先是根據(jù)uv坐標和深度depth創(chuàng)建了一個float4的坐標值pos,然后對pos乘2減1是將這個坐標范圍從[0,1]轉(zhuǎn)換到了[-1,1],對應(yīng)世界坐標。然后使用傳入的MVP逆矩陣_InverseMVP乘以這個坐標值,就得到了屏幕點的世界坐標。最后將pos的xyz分量除以w分量,這里w分量表示因為遠近而產(chǎn)生的縮放值。
5、在計算過世界坐標之后,對于y小于0的坐標要做一下處理,將效果限制在海平面(sea level)之上,使用射線平面相交方程(ray-plane intersection formula)的簡化版本來處理。
6、最后根據(jù)距離返回色彩值。
如果要實現(xiàn)夜幕降臨倒計時的效果,只需要在控制腳本(C#)中獲取Camera上的NightFall組件,根據(jù)時間修改radius變量即可。
以上所述是小編給大家介紹的C#使用Shader實現(xiàn)夜幕降臨倒計時的效果,希望對大家有所幫助,如果大家有任何疑問請給我留言,小編會及時回復(fù)大家的。在此也非常感謝大家對我們網(wǎng)站的支持!
上一篇:C#中常用的正則表達式實例
欄 目:C#教程
本文標題:C#使用Shader實現(xiàn)夜幕降臨倒計時的效果
本文地址:http://www.jygsgssxh.com/a1/C_jiaocheng/6218.html
您可能感興趣的文章
- 01-10C#實現(xiàn)txt定位指定行完整實例
- 01-10WinForm實現(xiàn)仿視頻播放器左下角滾動新聞效果的方法
- 01-10C#實現(xiàn)清空回收站的方法
- 01-10C#實現(xiàn)讀取注冊表監(jiān)控當前操作系統(tǒng)已安裝軟件變化的方法
- 01-10C#實現(xiàn)多線程下載文件的方法
- 01-10C#實現(xiàn)Winform中打開網(wǎng)頁頁面的方法
- 01-10C#實現(xiàn)遠程關(guān)閉計算機或重啟計算機的方法
- 01-10C#自定義簽名章實現(xiàn)方法
- 01-10C#文件斷點續(xù)傳實現(xiàn)方法
- 01-10winform實現(xiàn)創(chuàng)建最前端窗體的方法


閱讀排行
本欄相關(guān)
- 01-10C#通過反射獲取當前工程中所有窗體并
- 01-10關(guān)于ASP網(wǎng)頁無法打開的解決方案
- 01-10WinForm限制窗體不能移到屏幕外的方法
- 01-10WinForm繪制圓角的方法
- 01-10C#實現(xiàn)txt定位指定行完整實例
- 01-10WinForm實現(xiàn)仿視頻播放器左下角滾動新
- 01-10C#停止線程的方法
- 01-10C#實現(xiàn)清空回收站的方法
- 01-10C#通過重寫Panel改變邊框顏色與寬度的
- 01-10C#實現(xiàn)讀取注冊表監(jiān)控當前操作系統(tǒng)已
隨機閱讀
- 01-11Mac OSX 打開原生自帶讀寫NTFS功能(圖文
- 01-10C#中split用法實例總結(jié)
- 08-05dedecms(織夢)副欄目數(shù)量限制代碼修改
- 08-05織夢dedecms什么時候用欄目交叉功能?
- 08-05DEDE織夢data目錄下的sessions文件夾有什
- 01-10SublimeText編譯C開發(fā)環(huán)境設(shè)置
- 04-02jquery與jsp,用jquery
- 01-11ajax實現(xiàn)頁面的局部加載
- 01-10使用C語言求解撲克牌的順子及n個骰子
- 01-10delphi制作wav文件的方法


