Unity 引擎做残影效果——2、屏幕后处理方式

这篇具有很好参考价值的文章主要介绍了Unity 引擎做残影效果——2、屏幕后处理方式。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

Unity实现残影效果


  大家好,我是阿赵。
  这里继续介绍Unity里面做残影的方法。之前介绍了BakeMesh的方法做残影,这一期介绍的是用屏幕后处理的方法做残影。

一、原理

  之前的BakeMesh方法,是真的生成了很多个网格模型在场景里面。如果用后处理做,就没有这个过程。
unity shader 实现残影效果,Unity引擎Shader效果,unity,游戏引擎,残影,屏幕后处理
unity shader 实现残影效果,Unity引擎Shader效果,unity,游戏引擎,残影,屏幕后处理

  可以看到,虽然Game视图里面看到了残影,但实际上场景里面只有原理的一个角色的网格模型。
  其实用后处理做残影的方法非常的简单。首先复制一个和主摄像机一样的子摄像机,然后这个摄像机只看角色层,最后,给这个摄像机设置一个RenderTexture作为targetTexture。
unity shader 实现残影效果,Unity引擎Shader效果,unity,游戏引擎,残影,屏幕后处理

  这样,我们就可以在主摄像机渲染完整的画面的同时,拿到了一个只有角色的RenderTexture。
  然后我们维护一个队列,这个队列保存着过去几帧里面的渲染角色的RenderTexture。至于需要保存多少帧,多久保存一帧,就看各位自己的需要了。
  得到了这个RenderTexture队列之后,剩下的事情就非常简单了。把这个队列传入到后处理的材质里面。
unity shader 实现残影效果,Unity引擎Shader效果,unity,游戏引擎,残影,屏幕后处理

  这个时候,这几张RenderTexture实际上是下面这样的:
unity shader 实现残影效果,Unity引擎Shader效果,unity,游戏引擎,残影,屏幕后处理

  后处理的Shader很简单,就是把这几张Texture按照先后顺序,用过不同的透明度去合成在一起:
unity shader 实现残影效果,Unity引擎Shader效果,unity,游戏引擎,残影,屏幕后处理

  这样,残影的效果就做出来了。如果想修改残影的颜色,也是直接在后处理的时候,给残影的Texture乘以一个颜色就行了。

二、优缺点

1、优点

  对比起BakeMesh方法,这个后处理的方式,并不需要渲染多很多个角色的网格,只是需要多一个摄像机渲染多一次所有需要残影的角色而已。我们可以做一个优化,当某个角色需要做残影,就把它设置为专门的Layer,让这个残影摄像机能渲染到。平时没有需要残影的角色的时候,这个摄像机是什么都看不到。
  然后,场景里面就算有非常多的角色同时残影,最多也就是每个角色多渲染一次就够了,对于渲染方面的性能消耗还是很友好的。就是牺牲点内存,把这张RenderTexture复制并保存在内存里面。这个消耗我觉得并不是很大。
  如果想在这个基础上做其他效果,也是很轻松的,比如想对残影做模糊,或者Bloom,或者校色,其实就是对保存的这几张Texture做处理就行了,可以实现的效果非常多。

2、缺点

  由于是保存多张Texture作为合成残影的基础,所以究竟保存多少张合适,是一个问题。如果保存得少,那么残影的效果不是很明显,如果保存得多,内存的占用也会比较多。

三、代码

由于是Demo,所以写得比较简单一点,没有做优化,大家看个原理吧。文章来源地址https://www.toymoban.com/news/detail-799226.html

1、C#

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class MoveImageEffectCtrl : MonoBehaviour
{
    // Start is called before the first frame update
    private List<Texture> rtList;
    public Camera subCam;
    public bool isMove = false;
    private Texture2D blackTex;
    public Material mat;
    public int spaceTime = 10;
    private int countTime = 0;
    private Vector3 oldPos;
    public GameObject role;
    void Start()
    {
        CreateBlackTexture();
    }

    // Update is called once per frame
    void Update()
    {
        countTime++;
        if (countTime % spaceTime == 0)
        {
            CheckMove();
        }
    }

    private void CheckMove()
    {
        if (Vector3.Distance(oldPos, role.transform.position) > 0)
        {
            isMove = true;
            RenderTexture camTarget = subCam.targetTexture;
            RenderTexture rt = RenderTexture.GetTemporary(camTarget.width, camTarget.height);
            CopyRender(camTarget, rt);
            AddToRTList(rt);
            oldPos = role.transform.position;
        }
        else
        {
            isMove = false;
        }
    }
    private void CopyRender(RenderTexture source, RenderTexture destination)
    {
        Graphics.Blit(source, destination);
    }
    private void CreateBlackTexture()
    {
        blackTex = new Texture2D(128, 128);
        for (int i = 0; i < 128; i++)
        {
            for (int j = 0; j < 128; j++)
            {
                blackTex.SetPixel(i, j, Color.clear);
            }
        }
        blackTex.Apply();
    }

    private void AddToRTList(Texture rt)
    {
        if (rtList == null)
        {
            rtList = new List<Texture>();
        }
        rtList.Add(rt);
        if (rtList.Count > 5)
        {
            for (int i = 0; i < rtList.Count - 5; i++)
            {
                Texture tex = rtList[0];
                rtList.RemoveAt(0);
                if (tex is RenderTexture)
                {
                    RenderTexture.ReleaseTemporary((RenderTexture)tex);
                }
            }
        }
    }

    private void SetTexToMat()
    {
        if (isMove == false)
        {
            mat.SetFloat("_isMove", 0);
        }
        else
        {
            mat.SetFloat("_isMove", 1);
            for (int i = 0; i < 5; i++)
            {
                string key = "_Tex" + (i + 1);
                Texture tex = GetTexById(i);
                mat.SetTexture(key, tex);
            }
        }
    }

    private Texture GetTexById(int id)
    {
        if (rtList == null || rtList.Count <= id)
        {
            return blackTex;
        }
        else
        {
            return rtList[id];
        }
    }

    private void OnRenderImage(RenderTexture source, RenderTexture destination)
    {
        SetTexToMat();
        if(isMove)
        {
            Graphics.Blit(source, destination, mat);
        }
        else
        {
            Graphics.Blit(source, destination);
        }
        
    }
}

2、Shader

Shader "Unlit/MoveEffectCom"
{
    Properties
    {
        _MainTex ("Texture", 2D) = "white" {}
		_Tex1("Tex1",2D) = "black"{}
		_Tex2("Tex2",2D) = "black"{}
		_Tex3("Tex3",2D) = "black"{}
		_Tex4("Tex4",2D) = "black"{}
		_Tex5("Tex5",2D) = "black"{}
		_isMove("isMove",Float) = 0
    }
    SubShader
    {
        Tags { "RenderType"="Opaque" }
        LOD 100

        Pass
        {
            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag

            #include "UnityCG.cginc"

            struct appdata
            {
                float4 vertex : POSITION;
                float2 uv : TEXCOORD0;
            };

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

            sampler2D _MainTex;
            float4 _MainTex_ST;
			sampler2D _Tex1;
			sampler2D _Tex2;
			sampler2D _Tex3;
			sampler2D _Tex4;
			sampler2D _Tex5;
			float _isMove;
            v2f vert (appdata v)
            {
                v2f o;
                o.vertex = UnityObjectToClipPos(v.vertex);
                o.uv = TRANSFORM_TEX(v.uv, _MainTex);
                UNITY_TRANSFER_FOG(o,o.vertex);
                return o;
            }

            half4 frag (v2f i) : SV_Target
            {
                // sample the texture
				half4 col = tex2D(_MainTex, i.uv);
				if (_isMove > 0)
				{
					half4 addTex1 = tex2D(_Tex1, i.uv);
					half4 addTex2 = tex2D(_Tex2, i.uv);
					half4 addTex3 = tex2D(_Tex3, i.uv);
					half4 addTex4 = tex2D(_Tex4, i.uv);
					half4 addTex5 = tex2D(_Tex5, i.uv);
					half3 rgb = col.rgb + saturate(addTex1.rgb*addTex1.a*0.6f + addTex2.rgb*addTex2.a*0.5f + addTex3.rgb*addTex3.a*0.3f + addTex4.rgb*addTex4.a*0.2f + addTex5.rgb*addTex5.a*0.1f)*(1-col.a)*float3(1,0,0);
					rgb = saturate(rgb);
					col = half4(rgb, col.a);
				}


                return col;
            }
            ENDCG
        }
    }
}

到了这里,关于Unity 引擎做残影效果——2、屏幕后处理方式的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • Unity 之 使用后处理的方式实现暗角效果

    在Hierarchy界面,创建空物体 GameObject ,右键选择 Volume 菜单下的 Global Volume 。 创建后的结果: 设置Volume的Profile,点击右侧的New新创建一个配置文件,或者新建文件夹右键选择 Create - Volume Profile : 创建完成后赋值过去: 添加边角压暗效果:Vignette组件, Add Override - Post- proc

    2024年02月09日
    浏览(37)
  • Unity实现屏幕淡入淡出效果

    预期效果:为实现在进入新场景时的淡入淡出效果 编译器版本:2021.3.19f1c1 使用组件:UI -- RawImage 在Unity场景切换的时候,使用RawImage制作场景的淡入淡出效果。 添加RawImage,覆盖全屏,将脚本添加上去

    2024年02月12日
    浏览(91)
  • unity制作游戏,点击鼠标左键,展示屏幕震动效果

    在Unity中实现点击鼠标左键展示屏幕震动效果可以通过以下步骤进行: 创建一个新的C#脚本,例如\\\"ScreenShake.cs\\\",并将其附加到想要添加屏幕震动效果的游戏对象上。 在脚本中定义一个变量来控制震动的幅度,例如 public float shakeAmount = 0.1f; 。 在Update函数中检测鼠标左键点击事

    2024年02月12日
    浏览(43)
  • Unity中Shader抓取屏幕并实现扭曲效果(优化)

    对上一篇中实现的shader进行优化 1、定义结构体用于传入顶点坐标系 struct appdata { float4 vertex : POSITION; //从应用程序阶段的输入,多加一个uv,用于对扭曲纹理的采样 float2 uv : TEXCOORD; }; 2、因为UnityObjectToClipPos是从本地空间转换到裁剪空间,但是没有进行透视除法,所以需要对其

    2024年02月03日
    浏览(51)
  • 【Unity Shader】屏幕后处理3.0:均值模糊和高斯模糊

    发现之前学习记录的太过详细,导致整理的过程占用太长的时间了,这篇之后博客重要的是掌握实现过程,关于基础的理论会更多的放上别人写得更好的文章。 参考:【Unity Shader编程】之十五 屏幕高斯模糊(Gaussian Blur)后期特效的实现 高斯模糊只是各种模糊方式中的一种。模

    2023年04月08日
    浏览(43)
  • 【Unity Shader】屏幕后处理4.0:基于高斯模糊的Bloom

    原本打算写高斯模糊和双重模糊两个实现Bloom方法的对比,但两个加在一起篇幅过长,于是拆成两篇文章来进行。 学习前建议应先搞清楚的几个概念 HDR LDR ToneMapping 几种模糊算法 最近一直在学习Unity Shader实现各种后处理效果,Bloom效果就是其中之一,它也是游戏中最常见的效

    2023年04月11日
    浏览(44)
  • Unity自定义后处理——模糊效果

      大家好,我是阿赵。   继续介绍后处理的做法,这一期介绍的是模糊效果的做法。 我们还是用这个角色作为背景来实现模糊效果 这是模糊后的效果 根据不同的参数,可以调整不同的模糊程度。   在介绍做法之前,首先要明确一个基本的认知,模糊效果是非常消耗

    2024年02月03日
    浏览(44)
  • Unity Shader学习记录(11) ——透明效果的实现方式

    1 透明效果的两种方法 透明是游戏中经常要使用的一种效果。在实时渲染中要实现透明效果,通常会在渲染模型时控制它的透明通道(Alpha Channel)。当开启透明混合后,当一个物体被渲染到屏幕上时,每个片元除了颜色值和深度值之外,它还有另一个属性一一透明度。 当透明度

    2024年02月07日
    浏览(45)
  • 【工具篇】Unity翻书效果的三种方式

    目录 一.工具介绍 1.基础说明 2.使用说明 二.模式一手动翻页(UGUI)

    2023年04月08日
    浏览(98)
  • DOTS Unity.Physics物理引擎碰撞事件处理

    最近DOTS发布了正式的版本,同时基于DOTS的理念实现了一套高性能的物理引擎,今天我们给大家分享和介绍一下这个物理引擎的碰撞事件处理以及核心相关概念。 Unity.Physics 物理引擎的主要流程与P ipeline   Unity.Physics物理引擎做仿真迭代计算的时候主要通过以下步骤来执行:   

    2024年01月18日
    浏览(51)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包