Unity中Shader抓取屏幕并实现扭曲效果

news2025/1/20 3:45:52

文章目录

  • 前言
  • 一、屏幕抓取,在上一篇文章已经写了
  • 二、实现抓取后的屏幕扭曲
    • 实现思路:
      • 1、屏幕扭曲要借助传入 UV 贴图进行扭曲
      • 2、传入贴图后在顶点着色器的输入参数处,传入一个 float2 uv : TEXCOORD,用于之后对扭曲贴图进行采样
      • 3、最后在片元着色器阶段使用lerp(screenUV,distortTex,_Distort);进行线性插值对扭曲程度进行控制
  • 三、在扭曲的效果上实现流动效果
    • 实现思路:
  • 四、为了节省性能,把_Distort 、_SpeedX 和 _SpeedY三个变量用一个四维变量存储


前言

Unity中Shader抓取屏幕并实现扭曲效果实现


一、屏幕抓取,在上一篇文章已经写了

二、实现抓取后的屏幕扭曲

实现思路:

1、屏幕扭曲要借助传入 UV 贴图进行扭曲

2、传入贴图后在顶点着色器的输入参数处,传入一个 float2 uv : TEXCOORD,用于之后对扭曲贴图进行采样

3、最后在片元着色器阶段使用lerp(screenUV,distortTex,_Distort);进行线性插值对扭曲程度进行控制

代码实现:

Shader "MyShader/P0_10_4"
{
    Properties
    {
        //实现扭曲,就需要传入贴图来实现扰度
        _DistortTex("DistortTex",2D) = "white"{}
        _Distort("Distort",Range(0,1)) = 0
    }
    SubShader
    {
        Tags{"Queue" = "Transparent"}
        //屏幕抓取需要单独使用一个Pass —— GrabPass{} 里面什么都不写,或者GrabPass{"_GrabTex"}
        GrabPass{"_GrabTex"}
        
        Pass
        {
            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag
            #include "UnityCG.cginc"
            
            struct v2f
            {
                float2 uv : TEXCOORD0;
            };

            //在使用抓取的屏幕前,需要像使用属性一样定义一下,_GrabTexture这个名字是Unity定义好的
            sampler2D _GrabTex;
            sampler2D _DistortTex;float4 _DistortTex_ST;
            fixed _Distort;
            
            //在顶点着色器的输入处,不用appdata,直接使用用到的参数,防止 SV_POSITION 重复定义
            v2f vert (
                float4 vertex : POSITION,
                //从应用程序阶段的输入,多加一个uv,用于对扭曲纹理的采样
                float2 uv : TEXCOORD,
                out float4 pos : SV_POSITION
            )
            {
                v2f o;
                pos = UnityObjectToClipPos(vertex);
                o.uv = uv;
                return o;
            }

            fixed4 frag (v2f i,UNITY_VPOS_TYPE screenPos : VPOS) : SV_Target
            {
                
                fixed2 screenUV = screenPos.xy / _ScreenParams.xy;

                fixed4 distortTex = tex2D(_DistortTex,i.uv);

                //使用线性插值来控制UV的扭曲程度
                float2 uv = lerp(screenUV,distortTex,_Distort);
                //对抓取的屏幕进行采样
                fixed4 grabTex = tex2D(_GrabTex,uv);
                return grabTex;
            }
            ENDCG
        }
    }
}


三、在扭曲的效果上实现流动效果

实现思路:

在顶点着色器处,使用扭曲贴图的Tiling 及 offset 后与_Time相乘即可,流动速度,暴露两个float变量控制流速即可

代码实现:

Shader "MyShader/P0_10_4"
{
    Properties
    {
        //实现扭曲,就需要传入贴图来实现扰度
        _DistortTex("DistortTex",2D) = "white"{}
        _Distort("Distort",Range(0,1)) = 0
        _SpeedX("SpeedX",float) = 0
        _SpeedY("SpeedY",float) = 0
    }
    SubShader
    {
        Tags{"Queue" = "Transparent"}
        //屏幕抓取需要单独使用一个Pass —— GrabPass{} 里面什么都不写,或者GrabPass{"_GrabTex"}
        GrabPass{"_GrabTex"}
        //使用Cull off 让两面都有扭曲
        Cull Off
        Pass
        {
            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag
            #include "UnityCG.cginc"
            
            struct v2f
            {
                float2 uv : TEXCOORD0;
            };

            //在使用抓取的屏幕前,需要像使用属性一样定义一下,_GrabTexture这个名字是Unity定义好的
            sampler2D _GrabTex;
            sampler2D _DistortTex;float4 _DistortTex_ST;
            fixed _Distort;
            float _SpeedX,_SpeedY;
            
            //在顶点着色器的输入处,不用appdata,直接使用用到的参数,防止 SV_POSITION 重复定义
            v2f vert (
                float4 vertex : POSITION,
                //从应用程序阶段的输入,多加一个uv,用于对扭曲纹理的采样
                float2 uv : TEXCOORD,
                out float4 pos : SV_POSITION
            )
            {
                v2f o;
                pos = UnityObjectToClipPos(vertex);
                o.uv = TRANSFORM_TEX(uv,_DistortTex) + float2(_SpeedX,_SpeedY) * _Time.y;
                return o;
            }

            fixed4 frag (v2f i,UNITY_VPOS_TYPE screenPos : VPOS) : SV_Target
            {
                
                fixed2 screenUV = screenPos.xy / _ScreenParams.xy;

                fixed4 distortTex = tex2D(_DistortTex,i.uv);

                //使用线性插值来控制UV的扭曲程度
                float2 uv = lerp(screenUV,distortTex,_Distort);
                //对抓取的屏幕进行采样
                fixed4 grabTex = tex2D(_GrabTex,uv);
                return grabTex;
            }
            ENDCG
        }
    }
}


效果:
请添加图片描述

四、为了节省性能,把_Distort 、_SpeedX 和 _SpeedY三个变量用一个四维变量存储

优化后:

Shader "MyShader/P0_10_4"
{
    Properties
    {
        //实现扭曲,就需要传入贴图来实现扰度
        _DistortTex("DistortTex",2D) = "white"{}
        
        _Distort("SpeedX(X) SpeedY(y) Distort(Z)",vector) = (0,0,0,0)
    }
    SubShader
    {
        Tags{"Queue" = "Transparent"}
        //屏幕抓取需要单独使用一个Pass —— GrabPass{} 里面什么都不写,或者GrabPass{"_GrabTex"}
        GrabPass{"_GrabTex"}
        //使用Cull off 让两面都有扭曲
        Cull Off
        Pass
        {
            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag
            #include "UnityCG.cginc"
            
            struct v2f
            {
                float2 uv : TEXCOORD0;
            };

            //在使用抓取的屏幕前,需要像使用属性一样定义一下,_GrabTexture这个名字是Unity定义好的
            sampler2D _GrabTex;
            sampler2D _DistortTex;float4 _DistortTex_ST;
            float4 _Distort;
            
            
            //在顶点着色器的输入处,不用appdata,直接使用用到的参数,防止 SV_POSITION 重复定义
            v2f vert (
                float4 vertex : POSITION,
                //从应用程序阶段的输入,多加一个uv,用于对扭曲纹理的采样
                float2 uv : TEXCOORD,
                out float4 pos : SV_POSITION
            )
            {
                v2f o;
                pos = UnityObjectToClipPos(vertex);
                o.uv = TRANSFORM_TEX(uv,_DistortTex) + _Distort.xy * _Time.y;
                return o;
            }

            fixed4 frag (v2f i,UNITY_VPOS_TYPE screenPos : VPOS) : SV_Target
            {
                
                fixed2 screenUV = screenPos.xy / _ScreenParams.xy;

                fixed4 distortTex = tex2D(_DistortTex,i.uv);

                //使用线性插值来控制UV的扭曲程度
                float2 uv = lerp(screenUV,distortTex,_Distort.z);
                //对抓取的屏幕进行采样
                fixed4 grabTex = tex2D(_GrabTex,uv);
                return grabTex;
            }
            ENDCG
        }
    }
}


本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/997196.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

SAP 创建动态内表

创建动态内表 一、根据表名创建内表 程序代码: "复杂方式 SELECTION-SCREEN BEGIN OF BLOCK b1 WITH FRAME TITLE TEXT-001. PARAMETERS:p_tab TYPE string. SELECTION-SCREEN END OF BLOCK b1.DATA:lr_struct TYPE REF TO data,lr_table TYPE REF TO data. …

【云原生系列】Docker学习

目录 一、Docker常用命令 1 基础命令 2 镜像命令 2.1 docker images 查看本地主机的所有镜像 2.2 docker search 搜索镜像 2.3 docker pull 镜像名[:tag] 下载镜像 2.4 docker rmi 删除镜像 2.5 docker build 构建镜像 3 容器命令 3.1 如拉取一个centos镜像 3.2 运行…

.env文件详解

.env配置文件 vue会根据 process.env.NODE_ENV 的值,自动加载对应的环境配置文件 .env 全局默认配置文件,在所有的环境中被载入;.env.production 生产环境文件 production;.env.development 开发环境文件 development;.env.test/.env.stagi…

从零开始完整实现-循环神经网络RNN

一 简介 使用 pytorch 搭建循环神经网络RNN,循环神经网络(Recurrent Neural Network,RNN)是一类用于 处理序列数据的神经网络架构。与传统神经网络不同,RNN 具有内部循环结构,可以在处理序列数据时保持状态…

MySQL基础篇:掌握数据库基本操作,轻松上手

查看和指定现有的数据库 mysql> show databases; -------------------- | Database | -------------------- | information_schema | | bjpowernode | | eladmin | | mysql | | performance_schema | | sqlalchemy | | s…

makefile之使用函数wildcard和patsubst

Makefile之调用函数 调用makefile机制实现的一些函数 $(function arguments) : function是函数名,arguments是该函数的参数 参数和函数名用空格或Tab分隔,如果有多个参数,之间用逗号隔开. wildcard函数:让通配符在makefile文件中使用有效果 $(wildcard pattern) 输入只有一个参…

Qt串口基本设置与协议收发

前言 1.一直都想要做一个Qt上位机,趁着这个周末有时间,动手写一下 2.comboBox没有点击的信号,所以做了一个触发的功能 3.Qt的数据类型很奇怪,转来转去的我也搞得很迷糊 4.给自己挖个坑,下一期做一个查看波形的上位…

Java输入-a,-b,geek,-c,888,-d,[hello,world]字符之后,如何将[hello,world]这个不分开

Java输入-a,-b,geek,-c,888,-d,[hello,world]字符之后,如何将[hello,world]这个不分开? 你可以使用命令行参数解析库来处理Java输入中的各个参数。在这种情况下,你可以使用Apache Commons CLI库来解析命令行参数。以下是一个示例代码片段&am…

MATLAB遗传算法求解生鲜货损制冷时间窗碳排放多成本车辆路径规划问题

MATLAB遗传算法求解生鲜货损制冷时间窗碳排放多成本车辆路径规划问题实例 1、问题描述 已知配送中心和需求门店的地理位置,并且已经获得各个门店的需求量。关于送货时间的要求,门店都有规定的时间窗,对于超过规定时间窗外的配送时间会产生相应的惩罚成本。为保持生鲜农产品的…

2023.09.10 学习周报

文章目录 摘要文献阅读1-1 题目1-2 创新点1-3 本文工作2-1 题目2-2 什么是图2-3 图神经网络2-4 信息传递3-1 题目3-2 创新点3-3 本文工作 深度学习1.GNN的构建步骤2.构建图的方法3.GNN的简单样例 总结 摘要 本周阅读了三篇文章,第一篇是基于物理信息深度学习和激光…

【LeetCode题目详解】第九章 动态规划part11 ● 123.买卖股票的最佳时机III ● 188.买卖股票的最佳时机IV (day50补)

本文章代码以c为例! 一、力扣第123题:买卖股票的最佳时机 III 题目: 给定一个数组,它的第 i 个元素是一支给定的股票在第 i 天的价格。 设计一个算法来计算你所能获取的最大利润。你最多可以完成 两笔 交易。 注意&#xff1…

基于springboot+vue的在线课程学习网站(前后端分离)

博主主页:猫头鹰源码 博主简介:Java领域优质创作者、CSDN博客专家、公司架构师、全网粉丝5万、专注Java技术领域和毕业设计项目实战 主要内容:毕业设计(Javaweb项目|小程序等)、简历模板、学习资料、面试题库、技术咨询 文末联系获取 项目介绍…

unity实现Perlin噪声

Perlin噪声目的是为了生成连续变化的随机值。这里推荐一个使用unity实现的perlin噪声插件,包含源码,源码下载地址:https://download.csdn.net/download/hulinhulin/88323641https://download.csdn.net/download/hulinhulin/88323641 插件界面…

vscode 下载安装

vscode 下载安装常用插件 vscode 官网: https://code.visualstudio.com/ 点击右上角 Download 进入下载选择页面 选择自己使用操作对应 CPU 架构 下载 本文使用 x86 架构 64位 windows 系统为例 跳转下载页面 自动 开始下载 下载不开始?试试这个直…

关于黑马hive课程案例FineBI中文乱码的解决

文章目录 问题描述情况一的解决情况二的解决 ETL数据清洗知识社交案例参考代码结果展示 问题描述 情况1:FineBI导入表名中文乱码,字段内容正常情况2:FineBI导入表字段中文乱码,表名内容正常 情况一的解决 使用navcat等工具连接…

第九章 Linux实际操作——Linux磁盘分区、挂载

第九章 Linux实际操作——Linux磁盘分区、挂载 9.1 Linux分区9.1.1原理介绍9.1.2 硬盘说明9.1.3 查看所有设备搭载情况 9.2 挂载的经典案例9.2.1 说明9.2.2 如何增加一块硬盘9.2.3 虚拟机增加硬盘步骤 9.3 磁盘情况查询9.3.1 查询系统整体磁盘使用情况9.3.2 查询指定目录的磁盘…

TypeScript对象类型

废话不多说,还是挑点有营养的讲。 对象类型 1、匿名对象 匿名对象类型是在定义变量时直接使用花括号{},来定义一个对象类型。 const person: { name: string, age: number } { name: John, age: 25 }; 2、接口类型 使用接口来定义对象类型&#x…

二叉树的顺序结构以及堆的实现——【数据结构】

W...Y的主页 😊 代码仓库分享 💕 上篇文章,我们认识了什么是树以及二叉树的基本内容、表示方法……接下来我们继续来深入二叉树,感受其中的魅力。 目录 二叉树的顺序结构 堆的概念及结构 堆的实现 堆的创建 堆的初始化与…

LeetCode(力扣)455. 分发饼干Python

LeetCode20. 有效的括号 题目链接代码 题目链接 https://leetcode.cn/problems/assign-cookies/ 代码 从大遍历 class Solution:def findContentChildren(self, g: List[int], s: List[int]) -> int:g.sort()s.sort()index len(s) - 1result 0for i in range(len(g) -…

老胡的周刊(第107期)

老胡的信息周刊[1],记录这周我看到的有价值的信息,主要针对计算机领域,内容主题极大程度被我个人喜好主导。这个项目核心目的在于记录让自己有印象的信息做一个留存以及共享。 🎯 项目 open-interpreter[2] 基于 LLM 为你提供一种…