自言自语
这次回家继续复习白天学习的乐乐女神的 简易motionblur效果实现。 很简单 代码很快就码完了。但没效果。。。 检查shader没问题 又检查C# 发现几句代码的顺序错了 造成没有报错 但是没效果。于是按照逻辑理了一下顺序 效果呈现。
但是本着好奇的心 又按照自己的理解 过了一遍代码 发现。。。不按照乐乐女神的写法 只要一个pass 也不用进行ColorMask 操作 以及C#中的 *RenderTexture.MarkRestoreExpected();*操作也一样能实现相同的效果,就很不明白 为什么乐乐女神要做这么多操作。。。
可能还是没真正理解原理。 求各位大佬指教 如果这篇笔记有幸被大佬们看到的话
效果
实现步骤及疑惑都写在代码注释里了
C#部分
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
[ExecuteInEditMode]
public class MotionBlurWang : PostProcessWangBase
{
[Range(0f, 0.9f)]
public float BlurFactor = 0f;
public Shader motionShader;
private Material motionMaterial = null;
public Material Omaterial
{
get
{
motionMaterial = CheckShaderAndMaterial(motionShader, motionMaterial);
return motionMaterial;
}
}
private RenderTexture motionTex = null;
//不运行的时候 就销毁这个图 免得重影..
private void OnDisable()
{
DestroyImmediate(motionTex);
}
protected void OnRenderImage(RenderTexture source, RenderTexture destination)
{
if(Omaterial == null )
{
Graphics.Blit(source, destination);
}
else
{
//这里边执行顺序不能乱 之前写的乱了没有出现效果
//判断如果没有 或者 尺寸不对 则执行销毁 并重新给他一个现在的图源
if (motionTex == null || motionTex.width != source.width || motionTex.height != source.height)
{
DestroyImmediate(motionTex);
motionTex = new RenderTexture(source.width, source.height, 0);
//手动销毁 无需出现在面板和场景中 不随场景保存
motionTex.hideFlags = HideFlags.HideAndDontSave;
//初始化完成后把现在的图源给 motion图
Graphics.Blit(source, motionTex);
}
//如果都本身就有符合条件的motion图则直接进行 恢复操作
//其实没明白为啥要做这一步..因为我注释掉这一步 效果也是正常的...
//有知道的大佬请指导下
motionTex.MarkRestoreExpected();
//设置好需要融合的也就是shader中的Alpha值 进行一个取反 使数值从小到大的变化对应 模糊效果的从弱到强
Omaterial.SetFloat("_MotionBlur", 1.0f - BlurFactor);
//利用shader的混合把新图源处理后叠加在motion上 处理叠加都在shader中进行
Graphics.Blit(source, motionTex, Omaterial);
//然后把处理好的图 渲染到目标图像上 完成!@
Graphics.Blit(motionTex, destination);
}
}
}
Shader部分
Shader "TNShaderPractise/ShaderPractise_MotionBlur"
{
Properties
{
_MainTex ("Texture", 2D) = "white" {}
}
SubShader
{
Tags { "RenderType"="Opaque" "Queue" ="Transparent" }
//两个Pass 要公用一个顶点着色器 所以就直接还是CGINCLUDE的起步
CGINCLUDE
sampler2D _MainTex;
//模糊强度 就是叠加图层的alpha值
float _MotionBlur;
struct a2v
{
float4 vertex : POSITION;
float4 texcoord : TEXCOORD0;
};
struct v2f
{
float4 pos : SV_POSITION;
float4 uv : TEXCOORD1;
};
v2f vert (a2v v)
{
v2f o;
o.pos = UnityObjectToClipPos(v.vertex);
o.uv = v.texcoord;
return o;
}
//叠加的模糊图 也就是画好的 虚掉的第一张图 可以理解为上一张图,其 Alpha值用参数控制,代表虚化程度,Alpha值越大则虚化越小 模糊效果越大
//由于C#中进行了OneMinus操作 所以则C#面板上 数值越大 则Alpha越小 则虚化越大,模糊效果越大
fixed4 fragRGB (v2f i) : SV_Target
{
fixed4 motionTex = fixed4 (tex2D (_MainTex,i.uv).rgb,_MotionBlur);
return motionTex;
}
//理解为现在正在呈现的这张图 其Alpah为其本身状态
fixed4 fragA (v2f i) : SV_Target
{
//此pass只是把现在这在渲染的图渲染出来且保留其自身Alpha
fixed4 motionTex = tex2D (_MainTex,i.uv);
return motionTex;
}
ENDCG
ZWrite Off ZTest Always Cull Off
//pass 0 进行虚化效果渲染
Pass
{
//由于要混合两个pass 所以开启blend 且基于alpha混合 blend模式设置为透明度混合
Blend SrcAlpha OneMinusSrcAlpha
//这里 用 ColorMask 只写入RGB的通道信息
//经过测试 不按乐乐女神写法 直接全通道写入也是一样的效果 因为这里的A通道已经被我们参数设置好了值 所以可以和下边的全图进行混合了
//ColorMask rgb
CGPROGRAM
#pragma vertex vert
#pragma fragment fragRGB
ENDCG
}
//Pass
//{
// //这个pass需要渲染出现在图像的Alpha值 保证现在图像叠加上一张虚化的图像
// //所以混合模式为实打实的混合
// //经测试 这个PASS混合模式可以不开启。。。 也一样的效果。。为啥要专门开启一下没明白
// //Blend One Zero
// //但写入的通道只是Alpha通道 两个Pass合一起 就是理解为 前一张图 我只写入RGB通道 A通道是自定义的所以等于全部写入一个虚影 来和 下一张图的Alpha 混合一下
// //呈现的效果叠加效果就是 当前图的实心加上上一张图的剩下的一点虚影边界
// ColorMask A
// 但是当我尝试进行不写入通道操作的时候...也能生效. 所以什么都不写入 就靠一个空Pass叠加 也能有用? 那我是不是不用多一个pass?
// //ColorMask 0
// CGPROGRAM
// #pragma vertex vert
// #pragma fragment fragA
// ENDCG
//}
//事实证明...真的一个pass就够用了.. 为啥要写俩??? 好难受..
}
FallBack Off
}
总结
不能理解乐乐女神为什么要写更多的操作来实现这个简易的motionblur效果。本来照着他的思路来 貌似已经接近理解的边缘了。但随着自己的理解更加深入我心,我尝试做了修改 去掉了我认为不必要的代码,竟然也能实现同样的效果我就不是很懂了。。。 还求有缘人能给我指点一二啊。。乐乐女神这么做总归是有原因的吧。学习的内容还是太少。所以自己不敢做判断 只能是简单尝试。 哎 。继续学习吧。
这两天有点懈怠了。。 进度慢了下来。。 要鞭策下自己了。看在牛年到来之前能把这第一本书啃完不!加油吧 艰难爬行的 我