用Shader实现的一些效果

///////////////////////////////////////////////卷轴//////////////////////////////////////////////////

实现原理:
还记得中学数学中圆的公式吗,就是利用这个公式计算坐标,然后实时的平移坐标轴,来完成一个圆的平移
具体做法:
1. 在一个圆中,假设圆心为坐标轴原点,那么,一个弧长对应的角度的正弦和余弦值分别可以表示水平和垂直方向上面的分量
2.角度的求法,   弧长 / 半径 = 弧度      弧度 / 2π = 角度 / 360    幸运的是,在CG函数中本来就是用的弧度作为输入参数的,所以这部分可以忽略
3.坐标轴原点的平移。将坐标轴原点作为一个变量,其实就是水平方向X上面的变量实时的计算,垂直方向Y上面不变。

using UnityEngine;
using System.Collections;
using DG.Tweening;
public class CreatPlane : MonoBehaviour
{
    public Texture2D texture;
    public Texture2D texture2;
    public int sizeX;
    public int sizeY;
    public float radius;
    private Material m_Material;
    // Use this for initialization
    void Start ()
    {

        Vector3[] vertices = new Vector3[sizeX * sizeY];
        Vector2[] UV = new Vector2[sizeX * sizeY];
        for (int y = 0; y < sizeY; y++)
        {
            for (int x = 0; x < sizeX; x++)
            {
                vertices[y * sizeX + x] = new Vector3(x * 10.0f / (sizeX - 1), 0, y * ((float)sizeY/sizeX) *10.0f / (sizeY - 1));
                UV[y * sizeX + x] = new Vector2(x * 1.0f / (sizeX - 1), y * 1.0f / (sizeY - 1));
            }
        }
        Mesh mesh = new Mesh();
        mesh.vertices = vertices;
        mesh.triangles = GetTriangles();
        mesh.uv = UV;
        
        gameObject.AddComponent().mesh = mesh;
        m_Material = new Material(Shader.Find("Unlit/Test"));
        m_Material.SetTexture("_MainTex", texture);
        m_Material.SetTexture("_SecTex", texture2);
        m_Material.SetFloat("_Radius", radius);
        m_Material.SetFloat("_MaxX", 10.0f);
        gameObject.AddComponent().material = m_Material;

        Vector3[] vertexs = GetComponent().mesh.vertices;
    }

    private int[] GetTriangles()
    {
        int index = 0;
        int[] tPolys = new int[(sizeX - 1) * (sizeY - 1) * 6];
        for (int y = 0; y < sizeY - 1; y++)
        {
            for (int x = 0; x < sizeX - 1; x++)
            {
                tPolys[index++] = (y * sizeX) + x;
                tPolys[index++] = ((y + 1) * sizeX) + x;
                tPolys[index++] = (y * sizeX) + x + 1;

                tPolys[index++] = ((y + 1) * sizeX) + x;
                tPolys[index++] = ((y + 1) * sizeX) + x + 1;
                tPolys[index++] = (y * sizeX) + x + 1;
            }
        }
        return tPolys;
    }
    
    // Update is called once per frame
    void Update ()
    {

    }
    public void SetValue(float value)
    {
        m_Material.DOFloat(value, "_Progress", 1);
    }
}

 

Shader "Unlit/Test"
{
Properties
{
_MainTex ("MainTex", 2D) = "white" {}
_SecTex ("SecTex", 2D) = "white" {}
_Radius("Radius",float) = 0
_Progress("Progress",Range(0,1)) = 0
_MaxX("MaxX",float) = 0
}
SubShader
{
Tags 

"Queue" = "Transparent"
"RenderType"="Transparent" 
}

Pass
{
Blend SrcAlpha OneMinusSrcAlpha
Cull Back
ZWrite On
CGPROGRAM
#pragma vertex vert
#pragma fragment frag

#include "UnityCG.cginc"

struct v2f
{
float2 uv : TEXCOORD0;
float4 vertex : SV_POSITION;
};

sampler2D _MainTex;
float4 _MainTex_ST;
float _Radius,_Progress,_MaxX;

v2f vert (appdata_base v)
{
float primeter = 2 * UNITY_PI * _Radius;
float x = v.vertex.x;

float centerX = _MaxX * _Progress * 0.9;
if(x < centerX && centerX < primeter)
{
float radian = (centerX - x)/_Radius;
v.vertex.x = centerX - sin(radian) * _Radius;
v.vertex.y = _Radius - cos(radian) * _Radius;
}
else if(x < centerX && centerX > primeter)
{
if(x < centerX - primeter)
{
v.vertex.x = centerX;
}
else
{
float radian = (primeter - (x - (centerX - primeter)))/_Radius;
v.vertex.x = centerX - sin(radian) * _Radius;
v.vertex.y = _Radius - cos(radian) * _Radius;
}
}
v2f o;
o.vertex = UnityObjectToClipPos(v.vertex);
o.uv = TRANSFORM_TEX(v.texcoord, _MainTex);
return o;
}

fixed4 frag (v2f i) : SV_Target
{
float s;
float c;
sincos(radians(90),s,c);
float2x2 rotate={
c,-s,
s,c
};
// sample the texture
fixed4 col = tex2D(_MainTex, mul(rotate,i.uv));
return col;
}
ENDCG
}

Pass
{
Blend SrcAlpha OneMinusSrcAlpha
Cull Front
ZWrite On
CGPROGRAM
#pragma vertex vert
#pragma fragment frag

#include "UnityCG.cginc"

struct v2f
{
float2 uv : TEXCOORD0;
float4 vertex : SV_POSITION;
};

sampler2D _SecTex;
float4 _SecTex_ST;
float _Radius,_Progress,_MaxX;

v2f vert (appdata_base v)
{
float primeter = 2 * UNITY_PI * _Radius;
float x = v.vertex.x;

float centerX = _MaxX * _Progress * 0.9;
if(x < centerX && centerX < primeter)
{
float radian = (centerX - x)/_Radius;
v.vertex.x = centerX - sin(radian) * _Radius;
v.vertex.y = _Radius - cos(radian) * _Radius;
}
else if(x < centerX && centerX > primeter)
{
if(x < centerX - primeter)
{
v.vertex.x = centerX;
}
else
{
float radian = (primeter - (x - (centerX - primeter)))/_Radius;
v.vertex.x = centerX - sin(radian) * _Radius;
v.vertex.y = _Radius - cos(radian) * _Radius;
}
}
v2f o;
o.vertex = UnityObjectToClipPos(v.vertex);
o.uv = TRANSFORM_TEX(v.texcoord, _SecTex);
return o;
}

fixed4 frag (v2f i) : SV_Target
{
float s;
float c;
sincos(radians(90),s,c);
float2x2 rotate={
c,-s,
s,c
};
// sample the texture
fixed4 col = tex2D(_SecTex, mul(rotate,i.uv));
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

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实现的一些效果_第1张图片

利用场景的深度信息可以做一些很有趣的效果,比如  能量护盾~

这个效果虽然不算复杂但是很多游戏里面有有应用,看起来也够炫酷。而利用深度信息还可以做很多其他的效果。以后有空慢慢更新吧…………

下面正题


这个效果分为三个部分:

半透效果

最简单的一部分,但需要一些关于shader的常识性知识。

shader设置

逐句分析:

Cull Off  关闭背面剪裁。因为是要半透的自然可以看到背面,因此需要关闭背面剪裁

ZWrite Off 关闭Z缓存写入。因为护盾本身是不会遮挡到其他物体的,因此关闭。这里的遮挡需要理解渲染管线的Z缓存原理。

ZTest On 开启Z缓存测试。护盾需要被其他物体所遮挡。同上需要理解Z缓存。

Blend SrcAlpha OneMinusSrcAlpha 混合方式 Alpha混合。意思是用Alpha的值来控制计算颜色和颜色缓存中的值进行混合。(混合的方法有很多具体可查阅相关文档)

然后在ps里瞎鸡儿做个护盾样子的图采样就行了~(其实可以弄个GrabPass然后加个噪音扰动弄出能量扭曲空间的效果)。这里偷个懒就不搞了~

用Shader实现的一些效果_第2张图片

护盾贴图

边缘高亮

法线方向和视角的方向差异越大就说明越靠近边缘,再加个参数用来调整。

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

        }

    }

}

 

你可能感兴趣的:(Shader)