Shader案例篇—聲納光波效果(轉(zhuǎn))

轉(zhuǎn)自http://www.manew.com/thread-98405-1-1.html

一微服、前言

終于周末了趾疚,心心掛念的依然還是那段代碼。沒辦法职辨,苦逼的命盗蟆。還是廢話少說(shuō),先上效果圖如圖所示舒裤,前面兩個(gè)的效果圖是兩種模式下的

不同效果喳资,最后一章圖片是在其中一種模式下,場(chǎng)景進(jìn)行了精心布置后的效果圖腾供。

看效果圖會(huì)不自覺的認(rèn)為實(shí)現(xiàn)這個(gè)效果是不是要在場(chǎng)景中的物體中進(jìn)行繪制仆邓,如果真是要這樣做的話那是在是太耗性能了(畢竟都工作了鲜滩,本人畢業(yè)

了就不想在搞那些不實(shí)用的

)。其實(shí)节值,這個(gè)是通過(guò)控制攝像機(jī)的最后渲染來(lái)實(shí)現(xiàn)的效果的徙硅,后面我會(huì)給出這個(gè)案例的工程文件下載地址。讀者

在運(yùn)行模式的Scene視圖里將看到場(chǎng)景的物體(立方體)并沒有被額外渲染搞疗,有了這個(gè)思路對(duì)于后面理解代碼的實(shí)現(xiàn)原理會(huì)很有幫助嗓蘑。

二、原理

1匿乃、Shader部分—光照計(jì)算

這里用到的光照計(jì)算都比較簡(jiǎn)單桩皿,光照模式我使用了最簡(jiǎn)單的漫反射模式,代碼如下

//光照計(jì)算

float4x4 modelMatrix = _Object2World;

float4x4 modelMatrixInverse = _World2Object;

float3 normalDirection = normalize(

mul(float4(input.normal, 0.0), modelMatrixInverse).xyz);

float3 lightDirection = normalize(_WorldSpaceLightPos0.xyz);

float3 diffuseReflection = _LightColor0.rgb * max(0.0, dot(normalDirection, lightDirection));

output.col = float4(diffuseReflection, 1.0);

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

如圖所示為漫反射的示意圖幢炸,它的計(jì)算公式為

詳細(xì)的介紹和代碼可以參考這里

2泄隔、Shader部分—聲納光波的計(jì)算

Shader代碼如下:

//聲納光波計(jì)算

#ifdef SONAR_DIRECTIONAL

floatw = dot(output.pos.xyz, _SonarWaveVector);

#else

floatw = length(output.pos.xyz - _SonarWaveVector);

#endif

// Moving wave.

w -= _Time.y * _SonarWaveParams.w;

// Get modulo (w % params.z / params.z)

w /= _SonarWaveParams.z;

w = w - floor(w);

// Make the gradient steeper.

floatp = _SonarWaveParams.y;

w = (pow(w, p) + pow(1 - w, p * 4)) * 0.5;

// Amplify.

w *= _SonarWaveParams.x;

fixed3 col = _SonarWaveColor * w + _SonarAddColor;

代碼中使用了預(yù)編譯命令,是考慮了前面說(shuō)的效果圖中的兩種模式的切換宛徊。為此佛嬉,還必須在前面添加預(yù)編譯命令

[C#]純文本查看復(fù)制代碼

#pragma multi_compile SONAR_DIRECTIONAL SONAR_SPHERICAL

這個(gè)命令的大概意思就是說(shuō)可以將這兩個(gè)模式的Shader一起編譯,然后就可以在C#代碼里通過(guò)

[C#]純文本查看復(fù)制代碼

Shader.DisableKeyword("SONAR_SPHERICAL");

或者

[C#]純文本查看復(fù)制代碼

?

Shader.EnableKeyword("SONAR_SPHERICAL");

來(lái)進(jìn)行切換

完整頂點(diǎn)片段Shader代碼如下:

[C#]純文本查看復(fù)制代碼

Shader"CgInUnity/SonarFxVF"

{

Properties

{

_SonarBaseColor("Base Color",? Color) = (0.1, 0.1, 0.1, 0)

_SonarWaveColor("Wave Color",? Color) = (1.0, 0.1, 0.1, 0)

_SonarWaveParams("Wave Params", Vector) = (1, 20, 20, 10)

_SonarWaveVector("Wave Vector", Vector) = (0, 0, 1, 0)

_SonarAddColor("Add Color",?? Color) = (0, 0, 0, 0)

}

SubShader

{

Tags{"LightMode"="ForwardBase"}

// make sure that all uniforms are correctly set

Pass

{

CGPROGRAM

#pragma vertex vert

#pragma fragment frag

#pragma multi_compile SONAR_DIRECTIONAL SONAR_SPHERICAL

#include "UnityCG.cginc"

structvertexInput

{

float4 vertex : POSITION;

float3 normal:NORMAL;

};

structvertexOutput

{

float4 pos:SV_POSITION;

float4 col:COLOR;

};

float3 _SonarBaseColor;

float3 _SonarWaveColor;

float4 _SonarWaveParams;// Amp, Exp, Interval, Speed

float3 _SonarWaveVector;

float3 _SonarAddColor;

uniform float4 _LightColor0;

vertexOutput vert (vertexInput input)

{

vertexOutput output;

//光照計(jì)算

float4x4 modelMatrix = _Object2World;

float4x4 modelMatrixInverse = _World2Object;

float3 normalDirection = normalize(

mul(float4(input.normal, 0.0), modelMatrixInverse).xyz);

float3 lightDirection = normalize(_WorldSpaceLightPos0.xyz);

float3 diffuseReflection = _LightColor0.rgb * max(0.0, dot(normalDirection, lightDirection));

output.col = float4(diffuseReflection, 1.0);

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

//聲納光波計(jì)算

#ifdef SONAR_DIRECTIONAL

floatw = dot(output.pos.xyz, _SonarWaveVector);

#else

floatw = length(output.pos.xyz - _SonarWaveVector);

#endif

// Moving wave.

w -= _Time.y * _SonarWaveParams.w;

// Get modulo (w % params.z / params.z)

w /= _SonarWaveParams.z;

w = w - floor(w);

// Make the gradient steeper.

floatp = _SonarWaveParams.y;

w = (pow(w, p) + pow(1 - w, p * 4)) * 0.5;

// Amplify.

w *= _SonarWaveParams.x;

fixed3 col = _SonarWaveColor * w + _SonarAddColor;

output.col += float4(col, 1);

returnoutput;

}

float4 frag (vertexOutput input) : COLOR

{

returninput.col;

}

ENDCG

}

}

}

喜歡用簡(jiǎn)潔的Surface Shader代碼的童鞋可以用如下代碼替換:

Shader"CgInUnity/SonarFxSurf"

{

Properties

{

_SonarBaseColor? ("Base Color",? Color)? = (0.1, 0.1, 0.1, 0)

_SonarWaveColor? ("Wave Color",? Color)? = (1.0, 0.1, 0.1, 0)

_SonarWaveParams ("Wave Params", Vector) = (1, 20, 20, 10)

_SonarWaveVector ("Wave Vector", Vector) = (0, 0, 1, 0)

_SonarAddColor?? ("Add Color",?? Color)? = (0, 0, 0, 0)

}

SubShader

{

Tags {"RenderType"="Opaque"}

CGPROGRAM

#pragma surface surf Lambert

#pragma multi_compile SONAR_DIRECTIONAL SONAR_SPHERICAL

structInput

{

float3 worldPos;

};

float3 _SonarBaseColor;

float3 _SonarWaveColor;

float4 _SonarWaveParams;// Amp, Exp, Interval, Speed

float3 _SonarWaveVector;

float3 _SonarAddColor;

voidsurf(Input IN, inout SurfaceOutput o)

{

#ifdef SONAR_DIRECTIONAL

floatw = dot(IN.worldPos, _SonarWaveVector);

#else

floatw = length(IN.worldPos - _SonarWaveVector);

#endif

// Moving wave.

w -= _Time.y * _SonarWaveParams.w;

// Get modulo (w % params.z / params.z)

w /= _SonarWaveParams.z;

w = w - floor(w);

// Make the gradient steeper.

floatp = _SonarWaveParams.y;

w = (pow(w, p) + pow(1 - w, p * 4)) * 0.5;

// Amplify.

w *= _SonarWaveParams.x;

// Apply to the surface.

o.Albedo = _SonarBaseColor;

o.Emission = _SonarWaveColor * w + _SonarAddColor;

}

ENDCG

}

Fallback"Diffuse"

}

這個(gè)代碼看似簡(jiǎn)單闸天,但是對(duì)于處在學(xué)習(xí)基礎(chǔ)原理階段的童鞋暖呕,我的建議還是多動(dòng)手寫寫頂點(diǎn)片段Shader,實(shí)現(xiàn)簡(jiǎn)單的光照模式苞氮、頂點(diǎn)變換等等對(duì)于學(xué)

習(xí)Shader會(huì)非常有幫助的缰揪。

3、C#腳本部分

腳本部分最關(guān)鍵的就是使用上述的Shader去渲染攝像機(jī)葱淳,這個(gè)需要通過(guò)如下的代碼來(lái)實(shí)現(xiàn)嗎钝腺,這段代碼的意思是替換成這個(gè)Shader來(lái)渲染攝像機(jī)

[C#]純文本查看復(fù)制代碼

GetComponent().SetReplacementShader(shader,null);

其他的功能就是出傳遞參數(shù)給Shader來(lái)實(shí)現(xiàn)最終隨時(shí)間變換的效果,完整的代碼如下:




usingUnityEngine;

[RequireComponent(typeof(Camera))]

publicclassSonarFxControl : MonoBehaviour

{

// 聲納的模式

publicenumSonarMode { Directional, Spherical }

[SerializeField] SonarMode _mode = SonarMode.Directional;

publicSonarMode mode {get{return_mode; }set{ _mode = value; } }

// 聲納波的方向(僅僅在Directional模式下)

[SerializeField] Vector3 _direction = Vector3.forward;

publicVector3 direction {get{return_direction; }set{ _direction = value; } }

// 聲納波區(qū)域(僅僅在Spherical模式下)

[SerializeField] Vector3 _origin = Vector3.zero;

publicVector3 origin {get{return_origin; }set{ _origin = value; } }

// 背景顏色(Surfface Shader下有用)

[SerializeField] Color _baseColor =newColor(0.2f, 0.2f, 0.2f, 0);

publicColor baseColor {get{return_baseColor; }set{ _baseColor = value; } }

// 聲納波的顏色

[SerializeField] Color _waveColor =newColor(1.0f, 0.2f, 0.2f, 0);

publicColor waveColor {get{return_waveColor; }set{ _waveColor = value; } }

// 波的高度\振幅

[SerializeField]float_waveAmplitude = 2.0f;

publicfloatwaveAmplitude {get{return_waveAmplitude; }set{ _waveAmplitude = value; } }

// 波的顏色指數(shù)

[SerializeField]float_waveExponent = 22.0f;

publicfloatwaveExponent {get{return_waveExponent; }set{ _waveExponent = value; } }

// 波的時(shí)間間隔

[SerializeField]float_waveInterval = 20.0f;

publicfloatwaveInterval {get{return_waveInterval; }set{ _waveInterval = value; } }

// 波的速度

[SerializeField]float_waveSpeed = 10.0f;

publicfloatwaveSpeed {get{return_waveSpeed; }set{ _waveSpeed = value; } }

// 額外的顏色

[SerializeField] Color _addColor = Color.black;

publicColor addColor {get{return_addColor; }set{ _addColor = value; } }

[SerializeField] Shader shader;

intbaseColorID;

intwaveColorID;

intwaveParamsID;

intwaveVectorID;

intaddColorID;

voidAwake()

{

baseColorID = Shader.PropertyToID("_SonarBaseColor");

waveColorID = Shader.PropertyToID("_SonarWaveColor");

waveParamsID = Shader.PropertyToID("_SonarWaveParams");

waveVectorID = Shader.PropertyToID("_SonarWaveVector");

addColorID = Shader.PropertyToID("_SonarAddColor");

}

voidOnEnable()

{

GetComponent().SetReplacementShader(shader,null);

Update();

}

voidOnDisable()

{

GetComponent().ResetReplacementShader();

}

voidUpdate()

{

Shader.SetGlobalColor(baseColorID, _baseColor);

Shader.SetGlobalColor(waveColorID, _waveColor);

Shader.SetGlobalColor(addColorID, _addColor);

var param =newVector4(_waveAmplitude, _waveExponent, _waveInterval, _waveSpeed);

Shader.SetGlobalVector(waveParamsID, param);

if(_mode == SonarMode.Directional)

{

Shader.DisableKeyword("SONAR_SPHERICAL");

Shader.SetGlobalVector(waveVectorID, _direction.normalized);

}

else

{

Shader.EnableKeyword("SONAR_SPHERICAL");

Shader.SetGlobalVector(waveVectorID, _origin);

}

}

}

三赞厕、結(jié)語(yǔ)

最后可以看看這種方式實(shí)現(xiàn)的聲納波效果的性能消耗如何艳狐,我們可以在運(yùn)行的時(shí)候打開state看到如圖所示的統(tǒng)計(jì)圖,瞬間有沒有覺得這個(gè)效果

其實(shí)還蠻有實(shí)用價(jià)值的皿桑。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末毫目,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子诲侮,更是在濱河造成了極大的恐慌镀虐,老刑警劉巖,帶你破解...
    沈念sama閱讀 218,525評(píng)論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件沟绪,死亡現(xiàn)場(chǎng)離奇詭異刮便,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)绽慈,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,203評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門恨旱,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)辈毯,“玉大人,你說(shuō)我怎么就攤上這事搜贤∽晃郑” “怎么了?”我有些...
    開封第一講書人閱讀 164,862評(píng)論 0 354
  • 文/不壞的土叔 我叫張陵仪芒,是天一觀的道長(zhǎng)唁影。 經(jīng)常有香客問我,道長(zhǎng)掂名,這世上最難降的妖魔是什么夭咬? 我笑而不...
    開封第一講書人閱讀 58,728評(píng)論 1 294
  • 正文 為了忘掉前任,我火速辦了婚禮铆隘,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘南用。我一直安慰自己膀钠,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,743評(píng)論 6 392
  • 文/花漫 我一把揭開白布裹虫。 她就那樣靜靜地躺著肿嘲,像睡著了一般。 火紅的嫁衣襯著肌膚如雪筑公。 梳的紋絲不亂的頭發(fā)上雳窟,一...
    開封第一講書人閱讀 51,590評(píng)論 1 305
  • 那天,我揣著相機(jī)與錄音匣屡,去河邊找鬼封救。 笑死,一個(gè)胖子當(dāng)著我的面吹牛捣作,可吹牛的內(nèi)容都是我干的誉结。 我是一名探鬼主播,決...
    沈念sama閱讀 40,330評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼券躁,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼惩坑!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起也拜,我...
    開封第一講書人閱讀 39,244評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤以舒,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后慢哈,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體蔓钟,經(jīng)...
    沈念sama閱讀 45,693評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,885評(píng)論 3 336
  • 正文 我和宋清朗相戀三年卵贱,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了奋刽。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片瓦侮。...
    茶點(diǎn)故事閱讀 40,001評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖佣谐,靈堂內(nèi)的尸體忽然破棺而出肚吏,到底是詐尸還是另有隱情,我是刑警寧澤狭魂,帶...
    沈念sama閱讀 35,723評(píng)論 5 346
  • 正文 年R本政府宣布罚攀,位于F島的核電站,受9級(jí)特大地震影響雌澄,放射性物質(zhì)發(fā)生泄漏斋泄。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,343評(píng)論 3 330
  • 文/蒙蒙 一镐牺、第九天 我趴在偏房一處隱蔽的房頂上張望炫掐。 院中可真熱鬧,春花似錦睬涧、人聲如沸募胃。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,919評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)痹束。三九已至,卻和暖如春讶请,著一層夾襖步出監(jiān)牢的瞬間祷嘶,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,042評(píng)論 1 270
  • 我被黑心中介騙來(lái)泰國(guó)打工夺溢, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留论巍,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 48,191評(píng)論 3 370
  • 正文 我出身青樓风响,卻偏偏與公主長(zhǎng)得像环壤,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子钞诡,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,955評(píng)論 2 355

推薦閱讀更多精彩內(nèi)容