Unity Shader后处理-搜索灰度效果

摘要:
Unity将当前渲染的图像存储在对应于第一个参数的源渲染纹理中。它通常使用Graphics.Blit函数来完成渲染纹理的处理。src纹理将传输到MainTex的着色器named_texture属性。我们将实现OnRenderImage函数以获得当前屏幕的渲染纹理。然后调用Graphics.Blit函数,使用特定的UnityShader处理当前图像。

如U3D中Hierarchy面板下的搜索效果:

Unity Shader后处理-搜索灰度效果第1张

讲解分析:

1.这种PostEffect效果其实就是指Unity shader的后处理,即游戏中实现屏幕特效的常见方法。顾名思义屏幕后处理就是指在渲染完整个场景得到屏幕图像后,再对这个图像进行一系列操作,实现各种屏幕特效。

2.要实现这种屏幕后处理的基础在于得到渲染后的屏幕图像,即抓取屏幕,Unity中提供给我们一个方便接口——OnRenderImage函数。

3.OnRenderImage函数定义为MonoBehaviour.OnRenderImage (RenderTexture  src, RenderTexture dest); Unity会把当前渲染得到的图像存储在第一个参数对应的源渲染纹理中,通过该函数一系列操作后,再把目标渲染纹理,即第二个参数对应的渲染纹理显示到屏幕上。在OnRenderImage函数中,通常利用Graphics.Blit函数来完成对渲染纹理的处理。(若dest为null,就会直接将结果显示到屏幕上)。

Unity Shader后处理-搜索灰度效果第2张

src纹理是源纹理,在屏幕后处理技术中,该参数就是当前屏幕的渲染纹理或者是上一步处理后得到的渲染纹理。参数mat是材质,此材质使用的Unity Shader将会进行各种屏幕后处理操作,而src纹理将会被传递给材质的shader中名为_MainTex的纹理属性。参数pass的默认值为-1,即依次执行shader中的所有Pass,否则 仅会调用给定索引的Pass。

4.整个过程如下:

首先在摄像机中添加一个用于屏幕后处理的脚本。在该脚本中,我们会实现OnRenderImage函数来获取当前屏幕的渲染纹理。其次,再调用Graphics.Blit函数使用特定的Unity Shader来对当前图像进行处理,再把返回的渲染纹理显示到屏幕上。对于一些复杂的屏幕特效,可能多次调用Graphics.Blit函数对上一步输出结果进行下一步处理。

详细代码:

PostEffect.cs

 1 using System.Collections;
 2 using System.Collections.Generic;
 3 using UnityEngine;
 4 using UnityEngine.Rendering;
 5 
 6 
 7 [ExecuteInEditMode]
 8 public class PostEffect : MonoBehaviour
 9 {
10  
11     #region Variables
12     public float grayScaleAmout = 1.0f;
13 
14     //主相机
15     public Camera sourceCamera;
16 
17     //操作相机(为了结合另一个PostEffect,(OutlineEffect操作的相机))
18     public Camera outlineCamera;
19 
20     //渲染纹理
21     RenderTexture renderTexture;
22 
23     //开始灰色渲染效果标志
24     public bool isStart = false;
25 
26     //材质
27     Material material = null;
28     
29     #endregion
30 
31     void Start()
32     {
33         if (material == null)
34         {
35             material = new Material(Resources.Load<Shader>("NewUnlitShader"));
36         }
37     }
38 
39     void OnPreRender()
40     {
41         if (renderTexture == null || renderTexture.width != sourceCamera.pixelWidth || renderTexture.height != sourceCamera.pixelHeight)
42         {
43             renderTexture = new RenderTexture(sourceCamera.pixelWidth, sourceCamera.pixelHeight, 16, RenderTextureFormat.Default);
44             outlineCamera.targetTexture = renderTexture;
45         }
46         outlineCamera.Render();
47     }
48 
49     void OnRenderImage(RenderTexture source, RenderTexture target)
50     {
51         if (isStart)
52         {
53             if (material != null)
54             {
55                 material.SetTexture("_OutLine", outlineCamera.targetTexture);
56                 material.SetFloat("_LuminosityAmount", grayScaleAmout);
57                 Graphics.Blit(source, target, material);
58             }
59         }
60         else
61         {
62             Graphics.Blit(source, target);
63         }
64     }
65 
66     void OnDisable()
67     {
68         if (material)
69         {
70             DestroyImmediate(material);
71         }
72     }
73 }

shader部分:

Shader "Custom/GrayScale" {
    Properties {
        _MainTex ("Base (RGB)", 2D) = "white" {}
        _LuminosityAmount ("GrayScale Amount", Range(0.0, 1)) = 1.0
    }
    SubShader {
        Pass
        {
            CGPROGRAM
            #pragma vertex vert_img
            #pragma fragment frag
            #pragma fragmentoption ARB_precision_hint_fastest
            #include "UnityCG.cginc"
            
            uniform sampler2D _MainTex;
            fixed _LuminosityAmount;

            uniform sampler2D _OutLine;
            fixed _NumPixelH;
            fixed _NumPixelV;
            
            fixed4 frag(v2f_img i) : COLOR
            {   
                fixed4 outlineTex = tex2D(_OutLine, i.uv);
                fixed4 renderTex = tex2D(_MainTex, i.uv);

                if((outlineTex.r+outlineTex.b+outlineTex.g+outlineTex.a)<0.1f)
                {
                    float luminosity = 0.299 * renderTex.r + 0.587 * renderTex.g + 0.114 * renderTex.b;
                    fixed4 finalColor = lerp(renderTex, luminosity, _LuminosityAmount);
                    return finalColor;
                }
                else
                {
                    return renderTex;
                }
            }
    
            ENDCG
            }
    } 
    FallBack "Diffuse"
}

注释:

Unity Shader后处理-搜索灰度效果第3张

判断纹理顶点色值,我的源纹理初始色为黑色,所以搜索的物体附上色值,判断rgba的和是否为0,0为黑色,1为白色,黑色部分置灰(没选中的物体及场景其他部分),有色差的部分为选中部分返回当前color。

这效果结合上一篇的Outline效果,源纹理为上一篇处理的纹理,即_OutLine  ,_MainTex为主纹理,即当前屏幕纹理。

测试代码:

Unity Shader后处理-搜索灰度效果第4张Unity Shader后处理-搜索灰度效果第5张
 1 using cakeslice;
 2 using System.Collections;
 3 using System.Collections.Generic;
 4 using System.Text;
 5 using UnityEngine;
 6 using UnityEngine.UI;
 7 
 8 public class test : MonoBehaviour
 9 {
10     public InputField Txt;
11 
12     GameObject go = null;
13 
14     public void OnClick()
15     {
16         var chr = Txt.text.ToCharArray();
17         StringBuilder stringBuilder = new StringBuilder();
18         for (int i = 0; i < chr.Length; i++)
19         {
20             if (i == 0)
21             {
22                 stringBuilder.Append(chr[0].ToString().ToUpper());
23             }
24             else
25             {
26                 stringBuilder.Append(chr[i].ToString().ToLower());
27             }
28         }
29         Debug.Log(stringBuilder.ToString());
30 
31          go = GameObject.Find(stringBuilder.ToString());
32         if (go != null)
33         {
34             go.GetComponent<cakeslice.Outline>().Add();
35             Camera.main.GetComponent<PostEffect>().isStart = true;
36         }
37         else
38         {
39             Debug.Log("根据  "+ Txt.text + "  未找到搜索物体,请查看是否输入错误");
40         }
41     }
42 
43     public void UnDo()
44     {
45         if (go!=null)
46         {
47             go.GetComponent<cakeslice.Outline>().Remove();
48             Camera.main.GetComponent<PostEffect>().isStart = false;
49             go = null;
50         }
51     }
52 }
View Code

实现效果如下:

Unity Shader后处理-搜索灰度效果第6张

免责声明:文章转载自《Unity Shader后处理-搜索灰度效果》仅用于学习参考。如对内容有疑问,请及时联系本站处理。

上篇Apple推送通知服务教程vmware vcsa安装下篇

宿迁高防,2C2G15M,22元/月;香港BGP,2C5G5M,25元/月 雨云优惠码:MjYwNzM=

相关文章

微信小程序全屏背景图适配

需求:一张全屏背景图适配不同手机屏幕,图片不变形不裁剪 方案:填充色+图片。其他方案不太行。其他方案参考微信社区:https://developers.weixin.qq.com/community/develop/doc/000eee514f8908ed7d5aef55e51400 #EF1739是填充色,背景图片大小按照设计图写死,布局从上往下,区中...

解决自定义相机分辨率适配、扭曲的问题

在自定义相机和扫码的时候,如果不设置相机的默认分辨率,有可能导致相机用的是最小的分辨率,照出来的照片很模糊。 所以自定义相机的时候,需要获取屏幕分辨率,相机的预览分辨率,进行最佳的匹配。 由于相机的预览分辨率几乎都是 按照横屏的来描述的,eg 1920*1080 而手机一般是竖屏的,如果自定义的相机是竖屏的,匹配相机预览分辨率的时候,如果直接传入当前的屏幕...

前端解决移动端适配的五种方法

移动端适配的五种方法所谓移动端适配,就是WebApp在不同尺寸的屏幕上等比显示 推荐: 1.使用rem单位来做网页适配,这个是我比较推荐的一种,效果很好,浏览器的兼容性也不错 只要一行代码就能适配多个分辨率终端  (function(doc,win){ var docEl =doc.documentElement,...

Oracle条件分支查询

  Oracle的条件分支查询其实跟java的条件分支语法没啥太大的区别,只不过java多了一个switch关键字而已。看例子: SQL> SELECT CASE WHEN SUM(t1.TOTALTICKET) is null THEN 0 ELSE SUM(t1.TOTALTICKET) END totalTicket 2 FROM T...

mysql 查询字段为空显示默认值

     IFNULL() 函数用于判断第一个表达式是否为 NULL,如果为 NULL 则返回第二个参数的值,如果不为 NULL 则返回第一个参数的值。   IFNULL() 函数语法格式为:  IFNULL(expression, alt_value)   SELECT IFNULL(NULL, "zs"); 结果为 zs   SELECT IFNUL...

【Mybatis-Plus】使用updateById()、update()将字段更新为null或者空

问题背景: 最近测试同学给我提了个bug,字段不能置空,我查看了下项目配置发现是字段级别被设置为NOT_EMPTY导致的。 mybatis-plus FieldStrategy 有三种策略: 1.IGNORED:0 忽略 2.NOT_NULL:1 非 NULL,默认策略 3.NOT_EMPTY:2 非空 而默认更新策略是NOT_NULL:非 NULL;即通...