Unity Shader-热空气扭曲效果
简介
实现原理
GrabPass
//Grabpass shader
//by: puppet_master
//2017.4.23
Shader "ApcShader/GrabPass"
{SubShader{ZWrite Off//GrabPassGrabPass{//此处给出一个抓屏贴图的名称,抓屏的贴图就可以通过这张贴图来获取,而且每一帧不管有多个物体使用了该shader,只会有一个进行抓屏操作//如果此处为空,则默认抓屏到_GrabTexture中,但是据说每个用了这个shader的都会进行一次抓屏!"_GrabTempTex"}Pass{Tags{ "RenderType" = "Transparent""Queue" = "Transparent+1"}CGPROGRAMsampler2D _GrabTempTex;float4 _GrabTempTex_ST;#include "UnityCG.cginc"struct v2f{float4 pos : SV_POSITION;float4 grabPos : TEXCOORD0;};v2f vert(appdata_base v){v2f o;o.pos = mul(UNITY_MATRIX_MVP, v.vertex);//计算抓屏的位置,其中主要是将坐标从(-1,1)转化到(0,1)空间并处理DX和GL纹理反向的问题o.grabPos = ComputeGrabScreenPos(o.pos);return o;}fixed4 frag(v2f i) : SV_Target{//根据抓屏位置采样Grab贴图,tex2Dproj等同于tex2D(grabPos.xy / grabPos.w)fixed4 color = tex2Dproj(_GrabTempTex, i.grabPos);return 1 - color;}#pragma vertex vert#pragma fragment fragENDCG}}
}
我们找个面片,附上这个shader的材质。为了更方便的看一下效果,我们就参照官网的写法,直接将最终输出的颜色反向,也就是1-原颜色作为输出(这个颜色不禁让我想起了宇智波鼬的月读........)
inline float4 ComputeGrabScreenPos (float4 pos) {#if UNITY_UV_STARTS_AT_TOPfloat scale = -1.0;#elsefloat scale = 1.0;#endiffloat4 o = pos * 0.5f;o.xy = float2(o.x, o.y*scale) + o.w;
#ifdef UNITY_SINGLE_PASS_STEREOo.xy = TransformStereoScreenSpaceTex(o.xy, pos.w);
#endifo.zw = pos.zw;return o;
}
我们传递进来的参数是经过mvp变换后的顶点坐标,传入之后这个函数主要做了两件事情,第一个是处理DX和OpenGL纹理坐标差异导致的问题,这个之前的文章有记录过。第二件事主要就是将转化到标准裁剪空间(-1,1)区间的顶点转化到(0,1)区间。按照Unity的写法,本人推测,这个GrabPass获取的屏幕贴图应该是基于视空间的,而在这个信息传递到fragment shader后,用了tex2Dproj函数进行采样,tex2Dproj(i.xy)应该等同于tex2D(i.xy/i.w),也就是说这个采样点坐标进行了一次投影变换。
扭曲效果的实现
fixed4 frag(v2f i) : SV_Target{i.grabPos.x += _DistortStrength * sin(_Time.y * 10);i.grabPos.y += _DistortStrength * sin(_Time.y);fixed4 color = tex2Dproj(_GrabTempTex, i.grabPos);return 1 - color;}
那么所有的顶点就都会按照一致的方向进行偏移:
//Distort shader
//by: puppet_master
//2017.4.24
Shader "ApcShader/Distort"
{Properties{_DistortStrength("DistortStrength", Range(0,1)) = 0.2_DistortTimeFactor("DistortTimeFactor", Range(0,1)) = 1_NoiseTex("NoiseTexture", 2D) = "white" {}}SubShader{ZWrite OffCull Off//GrabPassGrabPass{//此处给出一个抓屏贴图的名称,抓屏的贴图就可以通过这张贴图来获取,而且每一帧不管有多个物体使用了该shader,只会有一个进行抓屏操作//如果此处为空,则默认抓屏到_GrabTexture中,但是据说每个用了这个shader的都会进行一次抓屏!"_GrabTempTex"}Pass{Tags{ "RenderType" = "Transparent""Queue" = "Transparent + 100"}CGPROGRAMsampler2D _GrabTempTex;float4 _GrabTempTex_ST;sampler2D _NoiseTex;float4 _NoiseTex_ST;float _DistortStrength;float _DistortTimeFactor;#include "UnityCG.cginc"struct v2f{float4 pos : SV_POSITION;float2 uv : TEXCOORD0;float4 grabPos : TEXCOORD1;};v2f vert(appdata_base v){v2f o;o.pos = mul(UNITY_MATRIX_MVP, v.vertex);o.grabPos = ComputeGrabScreenPos(o.pos);o.uv = TRANSFORM_TEX(v.texcoord, _NoiseTex);return o;}fixed4 frag(v2f i) : SV_Target{//首先采样噪声图,采样的uv值随着时间连续变换,而输出一个噪声图中的随机值,乘以一个扭曲快慢系数float4 offset = tex2D(_NoiseTex, i.uv - _Time.xy * _DistortTimeFactor);//用采样的噪声图输出作为下次采样Grab图的偏移值,此处乘以一个扭曲力度的系数i.grabPos.xy -= offset.xy * _DistortStrength;//uv偏移后去采样贴图即可得到扭曲的效果fixed4 color = tex2Dproj(_GrabTempTex, i.grabPos);return color;}#pragma vertex vert#pragma fragment fragENDCG}}
}
基于后处理的优化效果
/********************************************************************FileName: DistortEffect.csDescription: 屏幕扭曲效果Created: 2017/04/27by: puppet_master
*********************************************************************/
using System.Collections;
using System.Collections.Generic;
using UnityEngine;public class DistortEffect : PostEffectBase {//扭曲的时间系数[Range(0.0f, 1.0f)]public float DistortTimeFactor = 0.15f;//扭曲的强度[Range(0.0f, 0.2f)]public float DistortStrength = 0.01f;//噪声图public Texture NoiseTexture = null;public void OnRenderImage(RenderTexture source, RenderTexture destination){if (_Material){_Material.SetTexture("_NoiseTex", NoiseTexture);_Material.SetFloat("_DistortTimeFactor", DistortTimeFactor);_Material.SetFloat("_DistortStrength", DistortStrength);Graphics.Blit(source, destination, _Material);}else{Graphics.Blit(source, destination);}}
}
然后shader部分,扭曲的原理与上面一样,只是处理的对象变了一下,直接处理OnRenderImage传来的MainTex即可:
//全屏幕扭曲Shader
//by:puppet_master
//2017.4.28Shader "Custom/DistortPostEffect"
{Properties{_MainTex("Base (RGB)", 2D) = "white" {}_NoiseTex("Base (RGB)", 2D) = "black" {}//默认给黑色,也就是不会偏移}CGINCLUDE#include "UnityCG.cginc"uniform sampler2D _MainTex;uniform sampler2D _NoiseTex;uniform float _DistortTimeFactor;uniform float _DistortStrength;fixed4 frag(v2f_img i) : SV_Target{//根据时间改变采样噪声图获得随机的输出float4 noise = tex2D(_NoiseTex, i.uv - _Time.xy * _DistortTimeFactor);//以随机的输出*控制系数得到偏移值float2 offset = noise.xy * _DistortStrength;//像素采样时偏移offsetfloat2 uv = offset + i.uv;return tex2D(_MainTex, uv);}ENDCGSubShader{Pass{ZTest AlwaysCull OffZWrite OffFog{ Mode off }CGPROGRAM#pragma vertex vert_img#pragma fragment frag#pragma fragmentoption ARB_precision_hint_fastest ENDCG}}Fallback off
}
//Mask图生成shader
//by:puppet_master
//2017.5.3Shader "ApcShader/MaskObjPrepass"
{//子着色器 SubShader{Pass{ Cull OffCGPROGRAM#include "UnityCG.cginc"struct v2f{float4 pos : SV_POSITION;};v2f vert(appdata_full v){v2f o;o.pos = mul(UNITY_MATRIX_MVP, v.vertex);return o;}fixed4 frag(v2f i) : SV_Target{//这个Pass直接输出颜色return fixed4(1,1,1,1);}//使用vert函数和frag函数#pragma vertex vert#pragma fragment fragENDCG}}
}
/********************************************************************FileName: DistortEffect.csDescription: 屏幕扭曲效果Created: 2017/04/27by: puppet_master
*********************************************************************/
using System.Collections;
using System.Collections.Generic;
using UnityEngine;public class DistortEffect : PostEffectBase {//扭曲的时间系数[Range(0.0f, 1.0f)]public float DistortTimeFactor = 0.15f;//扭曲的强度[Range(0.0f, 0.2f)]public float DistortStrength = 0.01f;//噪声图public Texture NoiseTexture = null;//渲染Mask图所用的shaderpublic Shader maskObjShader = null;//降采样系数public int downSample = 4;private Camera mainCam = null;private Camera additionalCam = null;private RenderTexture renderTexture = null;public void OnRenderImage(RenderTexture source, RenderTexture destination){if (_Material){_Material.SetTexture("_NoiseTex", NoiseTexture);_Material.SetFloat("_DistortTimeFactor", DistortTimeFactor);_Material.SetFloat("_DistortStrength", DistortStrength);_Material.SetTexture("_MaskTex", renderTexture);Graphics.Blit(source, destination, _Material);}else{Graphics.Blit(source, destination);}}void Awake(){//创建一个和当前相机一致的相机InitAdditionalCam();}private void InitAdditionalCam(){mainCam = GetComponent<Camera>();if (mainCam == null)return;Transform addCamTransform = transform.FindChild("additionalDistortCam");if (addCamTransform != null)DestroyImmediate(addCamTransform.gameObject);GameObject additionalCamObj = new GameObject("additionalDistortCam");additionalCam = additionalCamObj.AddComponent<Camera>();SetAdditionalCam();}private void SetAdditionalCam(){if (additionalCam){additionalCam.transform.parent = mainCam.transform;additionalCam.transform.localPosition = Vector3.zero;additionalCam.transform.localRotation = Quaternion.identity;additionalCam.transform.localScale = Vector3.one;additionalCam.farClipPlane = mainCam.farClipPlane;additionalCam.nearClipPlane = mainCam.nearClipPlane;additionalCam.fieldOfView = mainCam.fieldOfView;additionalCam.backgroundColor = Color.clear;additionalCam.clearFlags = CameraClearFlags.Color;additionalCam.cullingMask = 1 << LayerMask.NameToLayer("Distort");additionalCam.depth = -999;//分辨率可以低一些if (renderTexture == null)renderTexture = RenderTexture.GetTemporary(Screen.width >> downSample, Screen.height >> downSample, 0);}}void OnEnable(){SetAdditionalCam();additionalCam.enabled = true;}void OnDisable(){additionalCam.enabled = false;}void OnDestroy(){if (renderTexture){RenderTexture.ReleaseTemporary(renderTexture);}DestroyImmediate(additionalCam.gameObject);}//在真正渲染前的回调,此处渲染Mask遮罩图void OnPreRender(){//maskObjShader进行渲染if (additionalCam.enabled){additionalCam.targetTexture = renderTexture;additionalCam.RenderWithShader(maskObjShader, "");}}
}
还是上面的测试场景,我们将面片改为Distort层级,然后可以直接给这个面片设置一个透明的材质,比如最简单的粒子的shader,让它正常渲染不可见即可:
//全屏幕扭曲Shader
//by:puppet_master
//2017.5.3Shader "Custom/DistortPostEffect"
{Properties{_MainTex("Base (RGB)", 2D) = "white" {}_NoiseTex("Noise", 2D) = "black" {}//默认给黑色,也就是不会偏移_MaskTex("Mask", 2D) = "black" {}//默认给黑色,权重为0}CGINCLUDE#include "UnityCG.cginc"uniform sampler2D _MainTex;uniform sampler2D _NoiseTex;uniform sampler2D _MaskTex;uniform float _DistortTimeFactor;uniform float _DistortStrength;fixed4 frag(v2f_img i) : SV_Target{//根据时间改变采样噪声图获得随机的输出float4 noise = tex2D(_NoiseTex, i.uv - _Time.xy * _DistortTimeFactor);//以随机的输出*控制系数得到偏移值float2 offset = noise.xy * _DistortStrength;//采样Mask图获得权重信息fixed4 factor = tex2D(_MaskTex, i.uv);//像素采样时偏移offset,用Mask权重进行修改float2 uv = offset * factor.r + i.uv;return tex2D(_MainTex, uv);}ENDCGSubShader{Pass{ZTest AlwaysCull OffZWrite OffFog{ Mode off }CGPROGRAM#pragma vertex vert_img#pragma fragment frag#pragma fragmentoption ARB_precision_hint_fastest ENDCG}}Fallback off
}
扭曲效果动态图如下:
Unity Shader-热空气扭曲效果相关推荐
- unityShader热空气扭曲效果
本文转载自http://blog.csdn.net/puppet_master/article/details/70199330?locationNum=2&fps=1 简介 千等万等终于等到 ...
- 10.热空气扭曲效果
Shader "Study/10_Distortion" {Properties{_NoiseTex("絮乱图", 2D) = "white" ...
- Unity Shader-热空气扭曲效果(多种实现方案,包括移动平台)
原文地址:https://blog.csdn.net/puppet_master/article/details/70199330 简介 千等万等终于等到了<耻辱2>打折,本以为可以爽一发 ...
- Unity Shader · 科技感矩阵效果
Unity Shader · 科技感矩阵效果 前言 最近想要做一个次世代卡通渲染(伪),选的是崩崩崩的小八(我最喜欢小八了). 先放几张截图,等全部做完之后再分享用到的一些技术叭. 赶紧做完发B站,等 ...
- Unity Shader·屏幕抖音效果
Unity Shader·屏幕抖音效果 前言 最近在做一个新的MMD(用Unity来实现),其中用到了一些好看的渲染技术在这里分享一下. 视频链接 https://www.bilibili.com/v ...
- Unity Shader学习:油画效果
Unity Shader学习:油画效果 油画效果在学习浅墨大神的文章时看到的比较有趣,但是原文中也没详细的算法介绍如何实现,这里就先直接拿来用吧,UI和屏幕后处理都可以用,算法也看的不是很明白,好像是 ...
- Unity Shader 实现透明护盾效果
这是大致的效果图,图片压得有点糊.我参考了本篇博客 Unity shader护盾特效. 这是原博客展示的图片: 本例采用了特殊的模型与贴图,原博客里有视频链接的教程,从模型到贴图. 以下是代码 // ...
- Unity Shader 实现卡通渲染效果
本文参考博客Unity Toon Shader 卡通着色器(一):卡通着色 这是我实现的最后效果 我们先一步一步来 最开始我们实现一个只有漫反射效果的Shader,效果和代码如下 Shader &qu ...
- unity Shader模拟ps渐变映射效果
美术要求程序实现一个类似photo中"渐变映射"的效果. 记录一下用unity完成的shader. 放一张路易斯 那么渐变映射的原理是什么?以下是百度的结果: 在使用时,渐变映射首 ...
- Unity Shader之燃烧消散效果
这种效果已经很多例子了,但是各种算法区别还是挺大的,不同的噪点图也有不同的效果,可以自己调整算法试试效果 注意几点 1:需要cull off双面渲染 2:燃烧时间的不同有不同的颜色,本文仅用了两个颜色 ...
最新文章
- [codeforces 339]D. Xenia and Bit Operations
- BZOJ3393 [Usaco2009 Jan]Laserphones 激光通讯
- python虚拟环境 windows环境搭建_windows 下搭建python虚拟环境(示例代码)
- Python学习之共享引用
- 深度学习-线性回归基础-02
- vb获取textbox数字_Spectrum仪器PCIe数字化仪可额外扩展8个数字输入
- 江苏计算机信息录入技师选拔考试题,2010年江苏省机关事业单位工人技师资格选拔考试试卷...
- 进阶– Java EE 7前端5强
- Luogu P3975 [TJOI2015]弦论
- foxmail地址簿怎么添加分组 foxmail地址簿新建分组的教程
- 比Postman更好用!在国产接口调试工具Apipost中使用Mock
- zend反编译-dezender 使用
- node创建新html页面,node创建服务器之展示html页面
- cas5.3 → 连接mysql数据库
- 使命召唤为啥显示新服务器玩家,《使命召唤8》建立服务器和加入自己、别人服务器方法...
- javascript正则表达式---正向预查
- cocopod升级1.6.0bate问题
- 加载八叉树索引文件_mysql innodb索引原理
- linux中U盘用fdisk等命令查询不到
- 微博舆情挖掘需求分析