图形特效编程---片段函数与抓屏技术

一、制作磨砂效果的毛玻璃

效果图: 

代码:

Shader "Unlit/FrostedGlass"
{
	Properties
	{
		_Radius("Radius", Range(1, 255)) = 1
	}

		Category
	{
		Tags{ "Queue" = "Transparent" "IgnoreProjector" = "True" "RenderType" = "Opaque" }

		SubShader
	{
		GrabPass
	{
		Tags{ "LightMode" = "Always" }
	}

		Pass
	{
		Tags{ "LightMode" = "Always" }

		CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#pragma fragmentoption ARB_precision_hint_fastest
#include "UnityCG.cginc"

		struct appdata_t
	{
		float4 vertex : POSITION;
		float2 texcoord: TEXCOORD0;
	};

	struct v2f
	{
		float4 vertex : POSITION;
		float4 uvgrab : TEXCOORD0;
	};

	v2f vert(appdata_t v)
	{
		v2f o;
		o.vertex = UnityObjectToClipPos(v.vertex);
#if UNITY_UV_STARTS_AT_TOP
		float scale = -1.0;
#else
		float scale = 1.0;
#endif
		o.uvgrab.xy = (float2(o.vertex.x, o.vertex.y * scale) + o.vertex.w) * 0.5;
		o.uvgrab.zw = o.vertex.zw;
		return o;
	}

	sampler2D _GrabTexture;
	float4 _GrabTexture_TexelSize;
	float _Radius;

	half4 frag(v2f i) : COLOR
	{
		half4 sum = half4(0,0,0,0);

#define GRABXYPIXEL(kernelx, kernely) tex2Dproj( _GrabTexture, UNITY_PROJ_COORD(float4(i.uvgrab.x + _GrabTexture_TexelSize.x * kernelx, i.uvgrab.y + _GrabTexture_TexelSize.y * kernely, i.uvgrab.z, i.uvgrab.w)))

		sum += GRABXYPIXEL(0.0, 0.0);
		int measurments = 1;

		for (float range = 0.1f; range <= _Radius; range += 0.1f)
		{
			sum += GRABXYPIXEL(range, range);
			sum += GRABXYPIXEL(range, -range);
			sum += GRABXYPIXEL(-range, range);
			sum += GRABXYPIXEL(-range, -range);
			measurments += 4;
		}

		return sum / measurments;
	}
		ENDCG
	}
		GrabPass
	{
		Tags{ "LightMode" = "Always" }
	}

		Pass
	{
		Tags{ "LightMode" = "Always" }

		CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#pragma fragmentoption ARB_precision_hint_fastest
#include "UnityCG.cginc"

		struct appdata_t
	{
		float4 vertex : POSITION;
		float2 texcoord: TEXCOORD0;
	};

	struct v2f
	{
		float4 vertex : POSITION;
		float4 uvgrab : TEXCOORD0;
	};

	v2f vert(appdata_t v)
	{
		v2f o;
		o.vertex = UnityObjectToClipPos(v.vertex);
#if UNITY_UV_STARTS_AT_TOP
		float scale = -1.0;
#else
		float scale = 1.0;
#endif
		o.uvgrab.xy = (float2(o.vertex.x, o.vertex.y * scale) + o.vertex.w) * 0.5;
		o.uvgrab.zw = o.vertex.zw;
		return o;
	}

	sampler2D _GrabTexture;
	float4 _GrabTexture_TexelSize;
	float _Radius;

	half4 frag(v2f i) : COLOR
	{

		half4 sum = half4(0,0,0,0);
		float radius = 1.41421356237 * _Radius;

#define GRABXYPIXEL(kernelx, kernely) tex2Dproj( _GrabTexture, UNITY_PROJ_COORD(float4(i.uvgrab.x + _GrabTexture_TexelSize.x * kernelx, i.uvgrab.y + _GrabTexture_TexelSize.y * kernely, i.uvgrab.z, i.uvgrab.w)))

		sum += GRABXYPIXEL(0.0, 0.0);
		int measurments = 1;

		for (float range = 1.41421356237f; range <= radius * 1.41; range += 1.41421356237f)
		{
			sum += GRABXYPIXEL(range, 0);
			sum += GRABXYPIXEL(-range, 0);
			sum += GRABXYPIXEL(0, range);
			sum += GRABXYPIXEL(0, -range);
			measurments += 4;
		}

		return sum / measurments;
	}
		ENDCG
	}
	}
	}
}

二、制作水雾效果的毛玻璃

效果图: 

 工作原理:

1.获得水下物体的渲染图像作为抓屏纹理

2.计算随时间变化的正弦波

3.片段位置和(二维)时变正弦波结合,形成UV坐标

4.使用上述UV坐标对噪声纹理进行采样,取得一个畸变值

5.对抓屏纹理坐标进行畸变处理

6.用畸变后的纹理坐标访问抓屏纹理获得颜色

7.与界面颜色相乘输出最终颜色

代码:

Shader "Custom/5-2"
{
	Properties
	{

			 _NormalMap("Normal Map", 2D) = "bump" {}
			 _Distortion("Distortion", Range(0, 100)) = 50

	}
		SubShader
			 {
				 Tags {

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



					 }
						 GrabPass { "_GrabTex" }

				 LOD 200


						 pass {
		   CGPROGRAM
		   #pragma vertex vert 
		   #pragma fragment frag 
		   #include "UnityCG.cginc"


				 sampler2D _NormalMap;
		   float _Distortion;
		   sampler2D _GrabTex;
		   float4 _GrabTex_TexelSize;
	  struct appdata {
		  float4 vertex : POSITION;
		  float2 uv : TEXCOORD0;
	  };
	  struct v2f {
		  float4 pos : SV_POSITION;
		  float2 uv : TEXCOORD0;
		  float4 scrPos : TEXCOORD1;
	  };

		UNITY_INSTANCING_BUFFER_START(Props)
		UNITY_INSTANCING_BUFFER_END(Props)

			v2f vert(appdata v) {
			v2f o;
			o.pos = UnityObjectToClipPos(v.vertex);
			o.uv = v.uv;
			o.scrPos = ComputeGrabScreenPos(o.pos);
			return o;
		}
		fixed4 frag(v2f i) : SV_TARGET
		{
			 float3 bump = UnpackNormal(tex2D(_NormalMap, i.uv));
			 float2 offset = bump.xy * _GrabTex_TexelSize.xy * _Distortion;
			 fixed4 albedo = tex2D(_GrabTex, (i.scrPos.xy + offset) / i.scrPos.w);
			 return albedo;
		}

			 ENDCG
		 }

			 }
}

三、制作放大镜效果

效果图: 

参考:(162条消息) Unity Shader - 放大镜_长生但酒狂的博客-CSDN博客_unity放大镜

思路:

  1. 先实现整体放大效果;
  2. 最后在一定范围内(圆形)放大
  3. 是放大镜,就是对图像的处理, 需要用到后期处理(参考(162条消息) UnityShader 屏幕后处理效果的基类_maba007的博客-CSDN博客

在Camera上面挂一个c#脚本来捕获需要渲染的图像,然后通过shader处理后渲染。

步骤:

1.整体放大:沿着 中心点到当前像素点的方向 采样像素点即可, 采样的距离越大, 缩放率就越大。

2.限制它在一定范围内缩放:让它在一个圆的范围内缩放。

脚本代码: 

// ---------------------------【放大镜特效】---------------------------

using UnityEngine;
public class Zoom : PostEffectsBase
{
    // shader
    public Shader myShader;
    //材质 
    private Material mat = null;
    public Material material
    {
        get
        {
            // 检查着色器并创建材质
            mat = CheckShaderAndCreateMaterial(myShader, mat);
            return mat;
        }
    }

    // 放大强度
    [Range(-2.0f, 2.0f), Tooltip("放大强度")]
    public float zoomFactor = 0.4f;

    // 放大镜大小
    [Range(0.0f, 0.2f), Tooltip("放大镜大小")]
    public float size = 0.15f;

    // 凸镜边缘强度
    [Range(0.0001f, 0.1f), Tooltip("凸镜边缘强度")]
    public float edgeFactor = 0.05f;

    // 遮罩中心位置
    private Vector2 pos = new Vector4(0.5f, 0.5f);

    void Start()
    {
        //找到对应的Shader文件  
        myShader = Shader.Find("lcl/screenEffect/Zoom");
    }

    // 渲染屏幕
    void OnRenderImage(RenderTexture source, RenderTexture destination)
    {
        if (material)
        {
            // 把鼠标坐标传递给Shader
            material.SetVector("_Pos", pos);
            material.SetFloat("_ZoomFactor", zoomFactor);
            material.SetFloat("_EdgeFactor", edgeFactor);
            material.SetFloat("_Size", size);
            // 渲染
            Graphics.Blit(source, destination, material);
        }
        else
        {
            Graphics.Blit(source, destination);
        }
    }

    void Update()
    {
        if (Input.GetMouseButton(0))
        {
            Vector2 mousePos = Input.mousePosition;
            //将mousePos转化为(0,1)区间
            pos = new Vector2(mousePos.x / Screen.width, mousePos.y / Screen.height);
        }
    }
}

shader代码:

// ---------------------------【放大镜特效】---------------------------

Shader "lcl/screenEffect/Zoom"
{
    // ---------------------------【属性】---------------------------
    Properties
    {
        _MainTex("Texture", 2D) = "white" {}
    }
        // ---------------------------【子着色器】---------------------------
        SubShader
    {
        // No culling or depth
        Cull Off ZWrite Off ZTest Always
        // ---------------------------【渲染通道】---------------------------
        Pass
        {
            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag

            #include "UnityCG.cginc"
            //顶点输入结构体
            struct VertexInput
            {
                float4 vertex : POSITION;
                float2 uv : TEXCOORD0;
            };
    // 顶点输出结构体
    struct VertexOutput
    {
        float2 uv : TEXCOORD0;
        float4 vertex : SV_POSITION;
    };

    // 变量申明
    sampler2D _MainTex;
    float2 _Pos;
    float _ZoomFactor;
    float _EdgeFactor;
    float _Size;
    // ---------------------------【顶点着色器】---------------------------
    VertexOutput vert(VertexInput v)
    {
        VertexOutput o;
        o.vertex = UnityObjectToClipPos(v.vertex);
        o.uv = v.uv;
        return o;
    }
    // ---------------------------【片元着色器】---------------------------
    fixed4 frag(VertexOutput i) : SV_Target
    {

        //屏幕长宽比 缩放因子
        float2 scale = float2(_ScreenParams.x / _ScreenParams.y, 1);
        // 放大区域中心
        float2 center = _Pos;
        float2 dir = center - i.uv;

        //当前像素到中心点的距离
        float dis = length(dir * scale);
        // 是否在放大镜区域
        // fixed atZoomArea = 1-step(_Size,dis);
        float atZoomArea = smoothstep(_Size + _EdgeFactor,_Size,dis);

        fixed4 col = tex2D(_MainTex, i.uv + dir * _ZoomFactor * atZoomArea);
        return col;
    }
    ENDCG
}
    }
}

屏幕 后处理效果代码:

using UnityEngine;
using System.Collections;

[ExecuteInEditMode]                                   //编辑状态也运行
[RequireComponent(typeof(Camera))]     // 它修饰的类在需要时自动挂载在 指定的组件上
public class PostEffectsBase : MonoBehaviour
{
    protected void Start()
    {
        CheckResources();
    }

    // Called when start
    protected void CheckResources()
    {
        bool isSupported = CheckSupport();

        if (isSupported == false)
        {
            NotSupported();
        }
    }

    // Called in CheckResources to check support on this platform
    protected bool CheckSupport()
    {
        if (SystemInfo.supportsImageEffects == false || SystemInfo.supportsRenderTextures == false)
        {
            Debug.LogWarning("This platform does not support image effects or render textures.");
            return false;
        }

        return true;
    }

    // Called when the platform doesn't support this effect
    protected void NotSupported()
    {
        enabled = false;
    }


    //  子类 调用的函数
    // Called when need to create the material used by this effect
    protected Material CheckShaderAndCreateMaterial(Shader shader, Material material)
    {
        if (shader == null)
        {
            return null;
        }

        if (shader.isSupported && material && material.shader == shader)
            return material;

        if (!shader.isSupported)
        {
            return null;
        }
        else
        {
            material = new Material(shader);
            material.hideFlags = HideFlags.DontSave;
            if (material)
                return material;
            else
                return null;
        }
    }
}

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

m0_57035151

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值