利用深度纹理实现运动模糊

运动模糊效果 运动模糊效果,是一种用于 模拟真实世界中快速移动物体产生的模糊现象 的图像处理技术,当一个物体以较高速度移动时,由于人眼或摄像机的曝光时间过长,该物体会在图像中留下模糊的运动轨迹。这种效果游戏、动画、电影中被广泛应用,以增加视觉真实性和动感。 阅读详情

利用 深度纹理实现运动模糊效果 的这种方式有以下两点需要注意:

  • 这种实现方式 只适合 场景静止,即摄像机快速移动的情况,

它不太适用于物体快速移动产生的运动模糊效果,只有摄像机移动时才能看到运动模糊效果

  • 这种实现方式 并不是基于真实的物理运动规律来计算的,只是一种近似计算!

它符合图形学基本规则:看起来对那么就是对的
虽然它使用上有局限性,并且实现上也不符合物理计算规则,
但是由于它实现出来的效果和性能消耗都还不错,因此它也是一种常用的运动模糊处理方案。

1、基本原理

得到像素当前帧和上一帧中在裁剪空间下的位置,利用两个位置计算出物体的运动方向,从而模拟出运动模糊的效果。
其中的关键点:

  1. 如何得到像素当前帧和上一帧在裁剪空间下的位置
  2. 如何得到运动方向
  3. 如何模拟运动模糊效果

如何得到像素当前帧和上一帧在裁剪空间下的位置

关键步骤:

  1. 利用UV坐标和深度值组合成一个裁剪空间下的组合坐标 nowClipPos
  2. 利用 这一帧 世界空间—>裁剪空间 的变换矩阵 nowM 的逆矩阵,将刚才裁剪空间下的组合坐标nowClipPos转换到世界空间中
  3. 利用 上一帧的 世界空间—>裁剪空间 的变换矩阵oldM得到,上一帧该世界空间下的组合坐标oldClipPos在裁剪空间下的位置

步骤一:

利用UV坐标和深度值组合成一个裁剪空间下的组合坐标 nowClipPos

  • float4 clipPos = float4(uv.x, uv.y, depth, 1);

uv坐标空间下的值是0~1,通过宏取出来的深度值也是0~1,而裁剪空间下的坐标范围是-1~1
因此,我们需要将它利用简单的公式转换到裁剪空间坐标系下

  • float4 clipPos = float4(uv.x * 2 - 1, uv.y * 2 - 1, depth * 2 - 1, 1);

可以认为这一步是把带有深度值的uv坐标转换到了裁剪空间下,之所以加入深度值是为了让之后的裁剪空间转到世界空间或其他坐标空间更合理,相当于是把UV的2D坐标系转换到了3D坐标系中

步骤二:

利用 世界空间—>裁剪空间 的变换矩阵的逆矩阵,将刚才裁剪空间下的nowClipPos转换到世界坐标中

只需要利用上面的这个裁剪空间到世界空间的变换矩阵,就可以将刚才得到的裁剪空间下的组合坐标变换到世界空间下了

步骤三:

利用上一帧的世界坐标—>裁剪空间的变换矩阵得到上一帧该世界空间下的组合坐标在裁剪空间下位置

如何得到运动方向

得到像素当前帧和上一帧在裁剪空间下的位置后,直接用 当前位置.xy – 上一帧位置.xy 便可以得到移动方向

如何模拟运动模糊效果

有了像素在裁剪空间的移动方向,相当于知道了像素在“uv纹理空间的移动方向”吗,那么只需要利用这个方向在纹理中进行多次uv坐标偏移采样后,将得到的颜色累加起来,最后进行算数平均值计算即可,会加入一个 模糊偏移量 来控制模糊程度,只需要在每次采样时进行 方向 * 模糊偏移量 的偏移采样即可

2、实现

Shader "ShaderProj/13/MotionBlurWithDepthTexture"
{
    Properties
    {
        _MainTex ("Texture", 2D) = "white" {}
        // 用于控制模糊程度的模糊偏移量
        _BlurSize ("BlurSize", Float) = 0.5 
    }

    SubShader
    {
        Pass
        {
            ZTest Always
            ZWrite Off
            Cull Off

            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag

            #include "UnityCG.cginc"


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

            sampler2D _MainTex;
            float4 _MainTex_ST;
            float4 _MainTex_TexelSize;
            sampler2D _CameraDepthTexture;
            float4x4 _ClipToWorldMatrix;          // 裁剪空间到世界空间的变换矩阵
            float4x4 _FrontWorldToClipMatrix;   // 上一帧世界空间到裁剪空间的变换矩阵
            float _BlurSize;

            v2f vert (appdata_base v)
            {
                v2f o;
                o.vertex = UnityObjectToClipPos(v.vertex);
                o.uv = v.vertex;
                o.uv_depth = v.vertex;
                #if UNITY_UV_STARTS_AT_TOP
                    if (_MainTex_TexelSize.y < 0) 
                    { 
                        o.uv_depth.y = 1 - o.uv_depth.y;
                    }
                #endif

                return o;
            }

            fixed4 frag (v2f i) : SV_Target
            {
                // 得到裁剪空间下的两个点
                float depth = SAMPLE_DEPTH_TEXTURE(_CameraDepthTexture, i.uv_depth);
                float4 nowClipPos = float4(i.uv * 2 - 1, depth * 2 - 1, 1);
                float4 worldPos = mul(_ClipToWorldMatrix, nowClipPos);
                worldPos /= worldPos.w;

                float4 oldClipPos = mul(_FrontWorldToClipMatrix, worldPos);
                oldClipPos /= oldClipPos.w;

                // 得到运动方向
                // 注意事项:让移动方向向量除以2,从而降低运动模糊效果的强度,不要过于强烈
                float2 moveDir = (nowClipPos.xy - oldClipPos.xy) / 2;

                // 进行模糊处理
                float2 uv = i.uv;
                float4 color = float4(0, 0, 0, 0);
                for (int it = 0; it < 3; it++)
                {
                    color += tex2D(_MainTex, uv);
                    uv += moveDir * _BlurSize;
                }
                color /= 3;
                return fixed4(color.rgb, 1);
            }
            ENDCG
        }
    }
    Fallback Off
}
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class MotionblurWithDepthTexture : PostEffectBase
{
    [Range(0, 1)]
    public float blurSize = .5f;
    private Matrix4x4 frontWorldToClipMatrix;

    // Start is called before the first frame update
    void Start()
    {
        Camera.main.depthTextureMode = DepthTextureMode.Depth;
    }

    private void OnEnable() 
    {
        // 每次脚本激活时 初始化一次
        frontWorldToClipMatrix = Camera.main.projectionMatrix * Camera.main.worldToCameraMatrix;
    }

    protected override void OnRenderImage(RenderTexture source, RenderTexture destination) {
        if (material != null) {
            material.SetFloat("_BlurSize", blurSize);
            material.SetMatrix("_FrontWorldToClipMatrix", frontWorldToClipMatrix);
            frontWorldToClipMatrix = Camera.main.projectionMatrix * Camera.main.worldToCameraMatrix;
            material.SetMatrix("_ClipToWorldMatrix", frontWorldToClipMatrix.inverse);
            Graphics.Blit(source, destination, material);
        }
        else
            Graphics.Blit(source, destination);
    }
}

Unity Shader使用深度纹理实现运动模糊 原理 利用深度纹理在片元着色器中为每个像素计算其在世界空间下的位置,使用前一阵的视角*投影矩阵对其进行变换,得到该位置在前一阵中的NDC坐标。然后,计算前一阵和当前帧的位置差,生成该像素的速度. 脚本实现: using UnityEngine; using System.Collections; public class MotionBlurWithDepthTexture : PostEffe... 阅读详情

相关推荐

图像处理中的运动模糊与去模糊技术

在数字图像处理中,运动模糊是由于拍摄期间相机或物体的移动导致图像出现模糊的现象。这种模糊效果与移动速度、方向和曝光时间有直接关系。理解运动模糊的基本概念是进行图像清晰处理的第一步。OpenCV(Open Source Computer Vision Library)是一个开源的计算机视觉和机器学习软件库,它提供了大量常用的图像处理功能,是进行图像模糊处理的重要工具。对于开发者来说,安装和配置OpenCV通常包括以下步骤:选择合适的安装包。

weixin_36238982的博客 1500

《Unity Shader入门精要》学习--高级篇--深度和法线纹理:“我来助你”

本文介绍了Unity中深度与法线纹理的原理及应用方法。主要内容包括:1. 深度和法线纹理的获取原理,包括纹理生成方式、采样解码方法;2. 基于深度纹理的运动模糊实现,通过计算前后帧像素位移速度来混合颜色;3. 使用深度纹理制作全局雾效,利用世界空间坐标计算雾强度并进行颜色插值;4. 利用深度+法线纹理进行边缘检测,采用Roberts算子比较对角线像素差异;5. 总结了深度纹理的空间转换、平台差异处理等核心技术要点。这些技术为屏幕后处理效果提供了重要实现手段,具有广泛的应用价值。

misco43的博客 1837

运动模糊的去除

这个是运动模糊的去除研究 包括代码 希望对大家有用

运动模糊/拖影的原因分析

目录原因一:曝光时间过长原因二:手抖导致运动模糊原因三:时域去噪过大原因四:多帧导致原因五:果冻效应原因六:AF失焦 在常见项目调试过程中,经常会遇见拍摄运动模糊和拖影问题,这其中是由多种原因导致的,接下来简要分析下,在遇见不同的问题时采取不同的处理方法。 静止拍摄运动物体时,曝光时间足够快,那么就相对在cmos上是静止的;曝光时间过慢,根据行曝光,就在cmos上就是相对运动的,拍出来的图片就容易模糊和有拖影。方法:1.首先减少该场景下的曝光时间,看是否有明显改善。 2.

kzzyf的博客 1万+

CentOS7 安装天气分型软件cost733过程详解

cost733是一款天气分型软件,其内置的一些算法可以帮助气象工作者进行天气类型划分等(我也是初学者,仅仅知道一些皮毛),但是网上找到的安装办法比较少,并且总会出现一些报错,试了一晚上,终于将安装办法调通了,希望可以帮助到大家

weixin_62573024的博客 3562

Ubuntu 24.04 搭建 Squid 代理服务器终极指南:从入门到 HTTPS 缓存AI模型

本文详细指导在Ubuntu 24.04系统部署Squid代理服务器,实现AI大模型文件的高效缓存。重点内容包括:1) 安装squid及必备的squid-openssl扩展包;2) 配置HTTPS拦截(SSL-Bumping)功能,创建CA证书和SSL数据库;3) 优化缓存策略,设置4TB存储空间并强制缓存常见大文件格式;4) 结合华为防火墙实现透明代理。文章特别强调实际部署中的关键注意事项和常见错误解决方案,如证书路径配置、权限设置等问题,帮助用户快速搭建企业级缓存代理服务。

zlt315的博客 1921

运动模糊综述

原因 运动模糊是相机,物体,背景间相对运动造成的效果,可以借助移动镜头追踪移动的物体来避免 影响因素 影响模糊的参数主要是:1,角度,0~360度,不同角度会造成不同模糊类型,2,长度,长度为移动多少间隔的像素 动态模糊类型:1,线性,动态模糊发生在单一方向,长度越长越模糊。2,旋转,产生物体在旋转的环状动态模糊,此类型的模糊 以镜头对准的点为中心,角度为主要影响因素,角度变化越大越模糊...

Cutepingping的博客 1万+

ubuntu20.04开机黑屏卡在/dev/sda1:clean,***files,***blocks,解决心得记录

这个问题如果你百度,会发现目前有很多种解决方法。 有更新显卡驱动的,有卸载上一次安装软件的,还有各种奇奇怪怪的故障原因。 如果你是属于上述情况,那么按照百度和论坛的各种指引操作一般都能解决。 但我这里主要说一种特殊情况,就是我什么也没有操作,我什么也没干。就是正常使用系统关了机突然就报错了。 这也是自己亲自遇到的问题,做个小记录方便以后自己回顾。 上一次出现这种情况我重装系统了,这次用了两个月又出现了,重装成本太高,我接受不了,于是找到解决办法。 首先找个终端进入,进入终端的方法很多,用安装u盘

qq_41517017的博客 2万+

UnityShader入门精要——运动模糊(2)

适用于场景静止、摄像机快速运动的情况

weixin_51327051的博客 4085

airodump-ng、aircrack-ng使用教程

wifi破解、airodump-ng、aircrack-ng脚本

ssmbyss的博客 2233

Windows11+VS2022驱动开发环境搭建实战:从零到编译(避坑指南)

本文详细介绍了在Windows11系统下使用VS2022搭建驱动开发环境的完整流程,包括版本匹配、工具安装、环境配置及常见问题解决。重点强调了WDK与系统版本的严格匹配,以及VS2022中驱动开发组件的正确配置方法,帮助开发者高效避坑并成功编译第一个驱动程序。

weixin_29251337的博客 527

Shader笔记十六 利用深度纹理实现更多特效

利用深度纹理实现运动模糊之前实现的运动模糊是通过混合多张屏幕图像来模拟运动模糊。另一种实现运动模糊的方式是通过速度映射图,而且该方式应用更加广泛。速度映射图中存储每个像素的速度,使用该速度决定模糊的方向和大小。生成速度缓冲可以将场景中所有物体的速度渲染到一张纹理中,不过该方法需要修改场景中所有物体的Shader代码,使其添加计算速度的代码并输出到下一个渲染纹理中。有一种方法是通过深度纹理在片元着色...

O213的博客 1141

DeepLabv3+改进专栏

🔥【DeepLabv3+改进专栏!探索语义分割新高度】🌟 你是否在为图像分割的精度与效率发愁?📢 本专栏重磅推出:✅ 独家改进策略:融合注意力机制、轻量化设计与多尺度优化✅ 即插即用模块:ASPP+升级、解码器。

AIcurator的博客 2576

使用深度和法线纹理 -- Shader入门精要学习(12)

很多时候我们不仅需要当前屏幕的颜色信息,还希望得到深度和法线信息。例如,在进行边缘检测时,直接利用颜色信息会使检测到的边缘信息受物体纹理和光照等外部因素的影响,得到很多我们不需要的边缘点。一种更好的方法是,我们可以在深度纹理和法线纹理上进行边缘检测,这些图像不会受纹理和光照的影响,而仅仅保存了当前渲染物体的模型信息,通过这样的方式检测出来的边缘更加可靠。

m0_52941834的博客 625

【腾讯小龙虾WorkBuddy专栏04】一文搞懂WorkBuddy的「专家」和「专家团」

WorkBuddy专家与专家团:专业级AI协作解决方案 WorkBuddy的专家(Expert)与专家团(Expert Team)功能颠覆了通用AI的局限性,提供角色化、可交付的专业服务。 核心优势 专家:深度垂直领域的AI顾问,具备人设、方法论、工具链,如全栈开发专家能直接交付完整项目,而非代码片段。 专家团:多智能体协作,自动拆解复杂任务(如竞品分析、全栈开发)并分发给对应角色,并行执行后整合输出,效率提升显著。 使用场景 单专家:解决专业问题(如SQL优化、UI设计)。

AI人人懂 2028

网络安全系列-四十三:使用Suricata分析恶意流量pcap文件

本文基于[网络安全系列-三十六:使用Suricata IDS分析pcap文件]和 [网络安全系列-四十二: Suricata之rulesets的激活、更新及动态加载]的基础上,使用suricata针对包含恶意流量的pcap文件进行分析,触发事件告警,并对suricata输出的日志进行逐个分析,让你掌握针对恶意流量的分析步骤,及怎么查看suricata输出的日志。

penriver的博客 2889

深度纹理

深度纹理定义:深度纹理实际上是一种渲染纹理,纹理中的每一个像素值分别存储的是高精度的深度值,而该深度值又是由NDC(统一设备坐标系)中的z分量值来提供,具体的计算公式如下: 深度纹理实现方式:实现方式如下: 1.通过设置渲染路径为延迟渲染路径,将深度信息存储在几何缓冲区中,从而通过直接访问深度缓存来实现。 2.通过在单独的pass中利用着色器替换技术,将满足渲染类型为Opaque,渲染队列小于

zjz 3849

文档:亲测可用解决vnc灰屏,黑屏,鼠标大黑叉情况

主要解决vnc-viewer灰屏,黑屏,鼠标大黑叉等现象,详细见文档。

shader入门精要读书笔记35 使用深度纹理获取像素速度来控制运动模糊

一、运动模糊 之前说的两种方式:运动模糊实现 一种是累积缓存,来混和多张连续的图像,消耗性能。 还有一种是采用速度缓存,这个缓存存储了各个像素当前的运动速度,然后使用该值决定模糊的方向和大小。 速度缓存就是通过深度纹理逆运算得出NDC坐标再乘以逆矩阵从而还原出世界空间中的坐标,再使用上一帧的变换矩阵乘以坐标来得到上一帧的NDC坐标,然后根据两个NDC坐标计算像素速度,从而使用速度对主纹理进行相邻像...

Chgmaker的博客 357

大中型超市收银系统(可直接运行)

光步前台收银系统系统功能:商品销售、商品退货、挂单、收银员权限、会员销售、单品取消、整单取消、商品查询、脱机销售、脱机数据上传,基本资料下载,开钱箱、小票打印、收款结算,支持多币种付款方式(现金、储值卡、礼券、微信等),支持多种促销。运行环境:.net 4.0登陆信息用户名:1001 密码:123456内置商品信息,商品编码可输入00001000 - 00010000,测试效果相关功能键F5 结算 F9挂单 F11商品查询 F8退货 Insert单品取消 Del整单取消 F12开钱箱F2 会员 Ctrl+Z退出系统 Home 锁屏 相关源码待公开

廖雪峰Python教程[完整版]

廖雪峰的python教程整理的,已经排好版了,而且还是完整的,适合小白

Unity Shader 屏幕后效果——摄像机运动模糊(速度映射图实现)

速度映射图主要是为了得到每个像素相对于前一帧的运动矢量,其中一种方法是使用摄像机的深度纹理来推导。 推导过程如下: 先由深度纹理逆推出NDC(归一化的设备坐标)下的顶点坐标,利用VP矩阵(视角*投影矩阵)的逆矩阵反向变换出每个像素在世界空间中的位置, 再利用世界空间下的坐标与前一帧的VP矩阵顺向变换出前一帧的NDC坐标,利用NDC下前一帧和相当帧的坐标差来确定速度的方向, 最后...

weixin_30689307的博客 550

复分析 阿尔福斯(Ahlfors) 第三版答案 英文

答案分为十章,有部分习题没有答案,全英文复分析阿尔福斯(Ahlfors) 第三版答案

《Unity Shader 入门精要》 第十三章 使用深度法线和纹理 笔记

使用深度法线和纹理 获取深度和法线纹理 原理 深度纹理 就是一张渲染纹理,存储的像素值是高精度的深度值。 范围是[0,1],通常是非线性分布的。 深度值来自于顶点变换后得到的归一化的设备坐标 顶点转换到齐次裁剪空间后,z坐标就是它的深度值。但是z分量的范围是[-1,1]所以我们为了能将其存储在图像中,使用: d = 0.5*z + 0.5 将其变为[0,1]范围中。 Unity中深度纹理可以来自...

qq_43486639的博客 432

UnityShader学习笔记 使用深度和法线纹理

获取深度和法线纹理 背后的原理 深度纹理实际上就是一张渲染纹理,只不过它里面存储的像素值不是颜色值,而是一个高精度的深度值。这些深度值来源于顶点变换后的归一化的设备坐标(NDC)。 如何获取 设置摄像机的depthTextureMode来完成, camera.depthTextureMode = DepthTextureMode.Depth; 设置完相机模式后,我们就可以在Shader中通过声明_CameraDepthTexture来访问它 同理,如果想要获取深度+法线纹理..

漫漫无期的博客 788

后处理——运动模糊-基于速度映射图

// Upgrade NOTE: replaced 'mul(UNITY_MATRIX_MVP,*)' with 'UnityObjectToClipPos(*)' Shader "Unity Shaders Book/Chapter 13/Motion Blur With Depth Texture" {     Properties {         _MainTex ("Base (RG...

weixin_42045212的博客 523

《Unity Shader入门精要》读书笔记第九章——基于深度的运动模糊

基于深度的运动模糊 运动模糊的基本实现就是连续一段时间的像素叠加 在用后处理实现的时候,比较麻烦的就是拿世界坐标下的顶点信息 然后再基于此,去计算点的速度矢量 最后拿到矢量方向的一段时间的颜色信息,取平均值可以达到模糊效果 思路很简单,主要难点是uv空间转换到世界空间 首先是uv空间到齐次空间,这一步很简单,(uv.x*2-1,uv.y*2-1,depth*2-1) 然后就是拿到齐次...

Last Order 425

【Shader入门精要】第十三章——使用深度和法线纹理

一、利用深度纹理进行运动模糊 原理:摄像机传递深度纹理_CameraDepthTexture,通过SAMPLE_DEPTH_TEXTURE方法从深度纹理中采样深度值,在片元着色器中先进行获取到NDC坐标(i.uv.x * 2 -1, i.ux.y * 2 - 1, SAMPLE_DEPTH_TEXTURE(_CameraDepthTexture, i.uv_depth) * 2 - 1),再使用...

两水先木示的博客 875

UnityShader_屏幕后处理之运动模糊

思路: 1、先介绍第一种运动模糊 2、介绍深度图 3、介绍第二种运动模糊 4、对比

weixin_40301728的博客 937

UnityShader高级篇——运动模糊(使用速度映射图实现)

原理:像素的当前帧的NDC坐标(x,y值由uv映射而来,z值由深度值映射而来)——(使用_CurrentViewProjectionInverseMartix变换,并除以w分量)—— 像素的世界坐标 ——(使用_PreviousViewProjectionMatrix变换,并除以w分量)—— 像素的前一帧的NDC坐标 —— (当前帧NDC-前一帧NDC)—— 速度1.此代码挂在摄像机上,使摄像机运...

weixin_37994402的博客 6657
上一篇: 深度和法线纹理
下一篇: Unity全局雾效
Go_Accepted
博客等级 码龄10年 601粉丝 334原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值