win32_bios的对象编辑器 保存对象_虚幻4渲染编程(材质编辑器篇)【第十八卷:在材质编辑器中用面向对象编程重写模糊效果】...

MY BLOG DIRECTORY:

YivanLee:专题概述及目录​zhuanlan.zhihu.com
55fb9a8a92f26956c2a4e975ee65de69.png

INTRODUCTION:

前段时间在毛大的专栏里看到他总结了十种模糊算法(原文链接,我打算在材质编辑器里重写一些常用的。

因为效果有很多种,出于程序的优雅性考虑,我准备用面向对象的方式在材质编辑器里完成这些效果。为了完成这一目的我们需要对UE做一些了解和改造。

3b86f0d923fe815d9c73968ffec7c213.png

UnrealEngine4.25的CustomNode加了包含usf的功能(本来就是几行代码就能搞定的,Epic官方就是不加!),可以在这里把自己的ush文件包含进来,但是我觉得还是太不优雅了。所以我还是使用我以前修改引擎的方法:文章链接

d8804d877f35ae73688a794df6f41d25.png

这样就能优雅得把头文件搞成一个Node了。

对于shader而言我们把数据封装到Struct里其实到最后也会展开,但是这很方便维护不是吗!一个效果就一个对象,对象里自带Init和Render方法接口,比以前那种面向过程式的思维写出来的神仙shader代码好多了不是吗,可惜的是目前这种写法不是所有平台都支持比如移动端,这样写的话直接就崩溃了。

669c9eebc48c28710df01f140b635a8c.png
后面我会详细介绍这部分代码这里可以暂时作为参考

MAIN CONTENT:

首先准备一张原图

7db30f16de6173c7c0464d1d96c807be.png

我这里截图出来也是为了方便和后面的效果做对比。

【1】Directional Blur

331c805cd74f8b144df3bb0126e63840.png

代码如下:

//DirectionalBlur Obj;
//Obj.Init(SceneTex, SceneTexSampler, float2(0.5, 0.5), 5, 0.01);
//return Obj.Render(uv);
struct DirectionalBlur
{
    Texture2D SceneTex;
    SamplerState SceneTexSampler;
    float2 BlurCenter;
    int Times;
    float BlurSize;

    void Init(
        in Texture2D InSceneTex,
        in SamplerState InSceneTexSampler,
        in float2 InBlurCenter, 
        in int InTimes, 
        in float InBlurSize
        )
    {
        SceneTex = InSceneTex;
        SceneTexSampler = InSceneTexSampler;
        BlurCenter = InBlurCenter;
        Times = InTimes;
        BlurSize = InBlurSize;
    }

    float3 Render(float2 uv)
    {
        float3 RetColor = float3(0, 0, 0);
        float2 BlurVector = (BlurCenter - uv) * BlurSize;

        for(int i = 0; i < Times; i++)
        {
           RetColor += SceneTex.SampleLevel(SceneTexSampler, uv, 0).rgb;
           uv += BlurVector;
        }
        RetColor /= Times;

        return RetColor;
    }
};

径向模糊根据一个向量对采样进行偏移,把采样结果加起来然后平均一下即可。

9fd07d202d446d46a18fddf1d4299ce5.png

需要注意的是,这里其实只执行了一次模糊迭代,如果想要增加迭代次数需要做一个乒乓缓冲把结果在RT上反复画。

2cd1c1fcd6f469bc4fe31a47c86cd15c.png

DirectionalBlur怼在一个Pass里也是可以的(就是费),直接增加Times即可。

ec7f7ad654ef420490fa813002e0e0dd.png

【2】Box Blur

e899263a0d77537ea042c2de02fcf217.png

BoxBlur需要乒乓缓冲来回画,在上一帧的基础上再次模糊,不然就会出很多晶格。

//BoxBlur Obj;
//Obj.Init(SceneTex, SceneTexSampler, 0.01);
//return Obj.Render(uv);
struct BoxBlur
{
    Texture2D SceneTex;
    SamplerState SceneTexSampler;
    float2 r;
    float2 UVOffset[9];

    void Init(
        in Texture2D InSceneTex,
        in SamplerState InSceneTexSampler,
        in float2 InRadius
        )
    {
        SceneTex = InSceneTex;
        SceneTexSampler = InSceneTexSampler;
        r = InRadius;

        UVOffset[0] = float2(-r.x, r.y);
        UVOffset[1] = float2(0, r.y);
        UVOffset[2] = float2(r.x, r.y);
        UVOffset[3] = float2(-r.x, 0);
        UVOffset[4] = float2(0, 0);
        UVOffset[5] = float2(r.x, 0);
        UVOffset[6] = float2(-r.x, -r.y);
        UVOffset[7] = float2(0, -r.y);
        UVOffset[8] = float2(r.x, -r.y);
    }

    float3 Render(float2 uv)
    {
        float3 RetColor = float3(0, 0, 0);
        RetColor += SceneTex.SampleLevel(SceneTexSampler, uv + UVOffset[0], 0).rgb;
        RetColor += SceneTex.SampleLevel(SceneTexSampler, uv + UVOffset[1], 0).rgb;
        RetColor += SceneTex.SampleLevel(SceneTexSampler, uv + UVOffset[2], 0).rgb;
        RetColor += SceneTex.SampleLevel(SceneTexSampler, uv + UVOffset[3], 0).rgb;
        RetColor += SceneTex.SampleLevel(SceneTexSampler, uv + UVOffset[4], 0).rgb;
        RetColor += SceneTex.SampleLevel(SceneTexSampler, uv + UVOffset[5], 0).rgb;
        RetColor += SceneTex.SampleLevel(SceneTexSampler, uv + UVOffset[6], 0).rgb;
        RetColor += SceneTex.SampleLevel(SceneTexSampler, uv + UVOffset[7], 0).rgb;
        RetColor += SceneTex.SampleLevel(SceneTexSampler, uv + UVOffset[8], 0).rgb;

        return RetColor / 9;
    }

};

BP:

46cc4c36ebbb6ed24fe3306ff2559f94.png

35b5859460bc5999f055d7c8146bee29.png

【3】GaussBlur

高斯模糊就是把卷积核的权重按照高斯分布计算即可

72af6ea0f8e1c31adff38ac41ae5e62b.png
#define PI 3.1415927
float Gaussian(float2 pos)
{
	float sigma = 1.5;
	float x = pos.x;
	float y = pos.y;
	
	return 1 / (2 * PI * sigma * sigma) * exp(-(x * x + y * y) / (2 * sigma * sigma));

}

高斯模糊的卷积核可以事先离线算好

const float r = 0.002;
float4 BlurData_00 = Texture2DSampleLevel(NoiseResult, NoiseResultSampler, UVAndScreenUV.xy + float2(0.0, 0), 0).rgba;
float Alpha = BlurData_00.a;
BlurData_00 = Gaussian(float2(0.0, 0.0)) * BlurData_00;
float4 BlurData_01 = Gaussian(float2( r, 0)) * Texture2DSampleLevel(NoiseResult, NoiseResultSampler, UVAndScreenUV.xy + float2( r, 0), 0).rgba;
float4 BlurData_02 = Gaussian(float2(-r, 0)) * Texture2DSampleLevel(NoiseResult, NoiseResultSampler, UVAndScreenUV.xy + float2(-r, 0), 0).rgba;
float4 BlurData_03 = Gaussian(float2(0,  r)) * Texture2DSampleLevel(NoiseResult, NoiseResultSampler, UVAndScreenUV.xy + float2(0,  r), 0).rgba;
float4 BlurData_04 = Gaussian(float2(0, -r)) * Texture2DSampleLevel(NoiseResult, NoiseResultSampler, UVAndScreenUV.xy + float2(0, -r), 0).rgba;

float4 BlurData_05 = Gaussian(float2(-r, -r)) * Texture2DSampleLevel(NoiseResult, NoiseResultSampler, UVAndScreenUV.xy + float2(-r, -r), 0).rgba;
float4 BlurData_06 = Gaussian(float2(r, -r)) * Texture2DSampleLevel(NoiseResult, NoiseResultSampler, UVAndScreenUV.xy + float2(r, -r), 0).rgba;
float4 BlurData_07 = Gaussian(float2(-r, r)) * Texture2DSampleLevel(NoiseResult, NoiseResultSampler, UVAndScreenUV.xy + float2(-r, r), 0).rgba;
float4 BlurData_08 = Gaussian(float2(r, r)) * Texture2DSampleLevel(NoiseResult, NoiseResultSampler, UVAndScreenUV.xy + float2(r, r), 0).rgba;
		
OutColor.rgb = BlurData_00 + BlurData_01 + BlurData_02 + BlurData_03 + BlurData_04 + BlurData_05 + BlurData_06 + BlurData_07 + BlurData_08;
OutColor.a = Alpha;

SUMMARY AND OUTLOOK:

没事写着玩儿,在shader里写结构体还是有点意思,但是现在的shader语言的确有点落后。希望这么low的文章不要被大佬看到。


NEXT:

todo...


By YivanLee 2020/4/30

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值