1. 程式人生 > >用Shader實現的一些效果

用Shader實現的一些效果

/////////////////////////////////////////////////////////橡皮效果////////////////////////////////////////////////////////////////////

堡壘之夜,裡面敲擊建築時有橡皮那種彈彈彈的效果

 

最終效果  

思路

  • 根據對應的座標和範圍內的頂點,根據法線進行偏移。
  • 根據時間計算偏移持續時間和反彈次數。

原始碼

[AppleScript] 純文字檢視 複製程式碼

?

01

02

03

04

05

06

07

08

09

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

Shader "QQ/Elastic"

{

Properties

{

_MainTex("Texture", 2D) = "white" {}

_Position("xyz:position,w:range",vector) = (0,0,0,1)

_Normal("xyz:normal,w:intensity",vector) = (0,1,0,0)

_PointTime("point time",float) = 0

_Duration("duration",float) = 2

_Frequency("frequency"

,float) = 5

}

SubShader

{

Tags { "RenderType" = "Opaque" }

LOD 100

Pass

{

CGPROGRAM

#pragma vertex vert

#pragma fragment frag

// make fog work

#pragma multi_compile_fog

#include "UnityCG.cginc"

struct appdata

{

float4 vertex : POSITION;

float2 uv : TEXCOORD0;

};

struct v2f

{

float2 uv : TEXCOORD0;

UNITY_FOG_COORDS(1)

float4 vertex : SV_POSITION;

};

sampler2D _MainTex;

float4 _MainTex_ST;

float4 _Position;

float4 _Normal;

float _PointTime;

float _Duration;

float _Frequency;

v2f vert(appdata v)

{

v2f o;

float t = _Time.y - _PointTime;

if (t>0&&t<_Duration)

{

float r = 1 - saturate(length(v.vertex.xyz - _Position.xyz) / _Position.w);

float l = 1 - t / _Duration;

v.vertex.xyz += r * l * _Normal.xyz * _Normal.w * cos(t * _Frequency);

}

o.vertex = UnityObjectToClipPos(v.vertex);

o.uv = TRANSFORM_TEX(v.uv, _MainTex);

UNITY_TRANSFER_FOG(o, o.vertex);

return o;

}

fixed4 frag(v2f i) : SV_Target

{

fixed4 col = tex2D(_MainTex, i.uv);

UNITY_APPLY_FOG(i.fogCoord, col);

return col;

}

ENDCG

}

}

}



指令碼

[AppleScript] 純文字檢視 複製程式碼

?

01

02

03

04

05

06

07

08

09

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

using System.Collections;

using System.Collections.Generic;

using UnityEngine;

interface IElastic

{

void OnElastic(RaycastHit hit);

}

[RequireComponent(typeof(MeshRenderer))]

public class ElasticObject : MonoBehaviour, IElastic

{

private static int s_pos, s_nor, s_time;

static ElasticObject()

{

s_pos = Shader.PropertyToID("_Position");

s_nor = Shader.PropertyToID("_Normal");

s_time = Shader.PropertyToID("_PointTime");

}

private MeshRenderer mesh;

private void Start()

{

mesh = GetComponent<MeshRenderer>()

}

//呼叫該方法

public void OnElastic(RaycastHit hit)

{

//反彈的座標

Vector4 v = transform.InverseTransformPoint(hit.point);

//受影響頂點範圍的半徑

v.w = 0.6f;

mesh.material.SetVector(s_pos, v);

//法線方向,該值為頂點偏移方向,可自己根據需求傳。

v = transform.InverseTransformDirection(hit.normal.normalized);

//反彈力度

v.w = 0.2f;

mesh.material.SetVector(s_nor, v);

//重置時間

mesh.material.SetFloat(s_time, Time.time);

}

}

/////////////////////////////////////////////////////////Shader能量護盾////////////////////////////////////////////////////////////////////

利用場景的深度資訊——能量護盾

利用場景的深度資訊可以做一些很有趣的效果,比如能量護盾~

這個效果雖然不算複雜但是很多遊戲裡面有有應用,看起來也夠炫酷。而利用深度資訊還可以做很多其他的效果。以後有空慢慢更新吧…………

下面正題

這個效果分為三個部分:

半透效果

最簡單的一部分,但需要一些關於shader的常識性知識。

shader設定

逐句分析:

Cull Off  關閉背面剪裁。因為是要半透的自然可以看到背面,因此需要關閉背面剪裁

ZWrite Off 關閉Z快取寫入。因為護盾本身是不會遮擋到其他物體的,因此關閉。這裡的遮擋需要理解渲染管線的Z快取原理。

ZTest On 開啟Z快取測試。護盾需要被其他物體所遮擋。同上需要理解Z快取。

Blend SrcAlpha OneMinusSrcAlpha 混合方式 Alpha混合。意思是用Alpha的值來控制計算顏色和顏色快取中的值進行混合。(混合的方法有很多具體可查閱相關文件)

然後在ps裡瞎雞兒做個護盾樣子的圖取樣就行了~(其實可以弄個GrabPass然後加個噪音擾動弄出能量扭曲空間的效果)。這裡偷個懶就不搞了~

護盾貼圖

邊緣高亮

法線方向和視角的方向差異越大就說明越靠近邊緣,再加個引數用來調整。

ps:可以在頂點著色器裡獲得法線和視角方向以減少計算量,在片段著色器裡使用的時候記得歸一化。

獲取法線和視角方向

相交高亮

這就是關鍵了。

現在頂點著色器裡獲得對應的場景座標

隨後在片段著色器裡用場景座標對深度圖進行取樣

需要注意的是:這裡的_CameraDepthTexture需要在前面提前宣告。

我們用自身的座標和場景深度相減。得到的值小於一定範圍就認為是和場景相交的部分了。

最後使用高亮的係數對根據貼圖取樣的顏色和高亮的顏色進行插值得到了最終的顏色值。

下面是程式碼:

[AppleScript] 純文字檢視複製程式碼

?

01

02

03

04

05

06

07

08

09

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

75

76

77

78

79

80

81

82

83

84

85

86

87

88

89

90

91

92

93

Shader "Unlit/depth"

{

    Properties

    {

        _MainTex ("Texture", 2D) = "black" {}

        _Threshold("相交閾值", Range(0.0, 1)) = 1

        _ViewThreshold("視角閾值", Range(0.0, 2)) = 1

        _HighlightColor("高光顏色", Color) = (1,1,1,1)

    }

    SubShader

    {

        Tags {

                "RenderType"="Transparent"

                "Queue" = "Transparent"

            }

        LOD 100

        Pass

        {

            Cull Off

            ZWrite Off

            ZTest On

            Blend SrcAlpha OneMinusSrcAlpha

            CGPROGRAM

            #pragma vertex vert

            #pragma fragment frag

            #include "UnityCG.cginc"

            //定義深度圖

            uniform sampler2D_float _CameraDepthTexture;

            fixed _Threshold;

            fixed _ViewThreshold;

            fixed4 _HighlightColor;

            struct appdata

            {

                float4 vertex : POSITION;

                float3 normal : NORMAL;

                float2 uv : TEXCOORD0;

            };

            struct v2f

            {

                float2 uv : TEXCOORD0;

                UNITY_FOG_COORDS(1)

                float4 vertex : SV_POSITION;

                float4 screenPos : TEXCOORD2;

                float3 worldNormal : TEXCOORD3;

                float3 worldViewDir : TEXCOORD4;

            };

            sampler2D _MainTex;

            float4 _MainTex_ST;

            v2f vert (appdata v)

            {

                v2f o;

                o.vertex = UnityObjectToClipPos(v.vertex);

                o.uv = TRANSFORM_TEX(v.uv, _MainTex);

                o.worldNormal = UnityObjectToWorldNormal(v.normal);

                o.worldViewDir = UnityWorldSpaceViewDir(mul(unity_ObjectToWorld, v.vertex));

                o.screenPos = ComputeScreenPos(o.vertex);

                COMPUTE_EYEDEPTH(o.screenPos.z);

                return o;

            }

            fixed4 frag (v2f i) : SV_Target

            {

                float4 final = tex2D(_MainTex, i.uv);

                fixed3 worldNormal = normalize(i.worldNormal);

                fixed3 worldViewDir = normalize(i.worldViewDir);

                //法線方向和視角方向的點積

                fixed edge = 1 - abs(dot(worldNormal, worldViewDir)) * _ViewThreshold;

                //根據自身的場景座標取樣深度圖得到當前位置的場景深度

                float sceneZ = LinearEyeDepth(SAMPLE_DEPTH_TEXTURE_PROJ(_CameraDepthTexture, UNITY_PROJ_COORD(i.screenPos)));

                float selfZ = i.screenPos.z;

                float intersect = 1- min ( (abs(sceneZ - selfZ)) / _Threshold, 1);

                return lerp(final,_HighlightColor,max(edge,intersect));

            }

            ENDCG

        }

    }

}


http://www.manew.com/thread-115809-1-1.html