原文|《Unreal Engine 4 Paint Filter Tutorial》 作者|Tommy Tran May 1 2018 | 翻译 开发游戏的老王 阅读时长|25分钟 内容难度|入门级 本教程将会教你通过实现桑原滤镜(Kuwahara Filter)让游戏具有手绘风格
- 开始吧
- 桑原滤镜
- 桑原滤镜的工作原理
- 桑原滤镜的例子
- 创建桑原滤镜
- 像素抽样
- 计算平均值和方差
时光流逝,电子游戏的视觉效果越来越好。在这个画面惊艳的游戏层出不穷的时代,让自己的游戏脱颖而出是件很困难的事情。然而有一种方法可以使你的游戏在视觉美学上与众不同,那就是非真实渲染(non-photorealistic rendering)。
非真实渲染的技术范畴非常广,它包含但不仅限于卡通着色,卡通描边以及交叉线。你甚至可以让你的游戏看起来更具手绘风。技术之一就是实现桑原滤镜(Kuwahara Filter)。
要实现桑原滤镜,你将会学到:
- 如何为多核(Kernel)计算平均值(mean)和方差(variance)
- 输出具有最小方差的核的平均值
- 使用索贝尔算子(Sobel)获取像素的局部朝向(local orientation)
- 基于像素的局部朝向旋转采样核(sampling kernel)
注:本文假定读者已经熟悉Unreal Engine的基础知识。因为本文将使用HLSL,所以你应该熟悉HLSL或至少熟悉一种诸如C#的语言。
本文是Unreal Engine着色器教程四部曲之一:
- 第一部分: 卡通着色(Cel Shading)
- 第二部分:卡通轮廓线(Toon Outline)
- 第三部分:使用HLSL自定义着色器(Custom Shaders Using HLSL)
- 第四部分:手绘风滤镜(Paint Filter)(当前位置!)
译者注: 本教程提供了范例工程,如果需要可以到原文网站免费注册并下载
下载工程文件并解压缩,找到PaintFilterStarter文件夹,打开PaintFilter.uproject,你就会看到下面的场景:
为了节省大家的时间,这个场景已经包含了自定义节点PP_Kuwahara的Post Process Volume ,这个材质(以及其着色器),就是我们要编辑的。
那么,我们先来了解一下桑原滤镜和它的工作原理吧。
照相的时候,我们有时会在照片表面发现一种颗粒状的纹理。就如同来自我们吵闹的邻居家中的噪声一样,我们往往不喜欢它。
常用的去噪方法就是使用诸如模糊之类的低通滤镜(low-pass filter ),下图就是使用半径为5的矩形模糊算法处理过的图片。
如上图所示,噪声基本被消除了,但是所有的边缘也变得模糊了。有没有一种方法能再平滑图像的同时保持边缘呢。
如你猜测的那样,桑原滤镜就能够满足这个需求,让我们看看它是如何工作的。
桑原滤镜的工作原理和卷积运算一样,桑原滤镜也要使用核(kernel),不同的是它不是使用1个而是4个。4个核如下图(5×5的桑原滤镜)所示布局,每两个核之间会有1个像素重叠(当前像素)
首先,计算每一个核中颜色的平均值,这步是为了后面要通过模糊来降噪。
对于每个核,还要计算方差,这主要是测量每个核中颜色值的变化大小。如果一个核中的颜色很相近,那么这个方差会很小;反之,如果颜色不相近,那么方差会很大。
最后,我们找到方差最低的核,并输出它的颜色平均值。这种基于方差的选择就是桑原滤镜保持边缘的方法。让我们看几个例子。
桑原滤镜的例子下面是个10×10的灰度图,我们可以看到一条从左下到右上的边缘,以及某些区域存在的噪声。
首先,选择一个像素并计算出方差最小的核。下图为本例所选的一个边缘附近的像素以及其相关的核:
如你所见,在边缘上的核,其颜色是抖动的,这意味着高方差因此它们也不会被选择。也正因此,桑原滤镜防止了边缘的模糊。
本例中,滤镜会选择绿色框框的那个核,因为它最稳定。于是输出的结果就是这个核中颜色的平均值(有点接近黑色)。
下面为另一个像素的以及它的核:
这次,黄色框框的核拥有最低的方差,因此它是唯一一个不在边缘的。所以本次输出结果为黄色核中颜色的平均值,这次结果有点接近白色。
下图为矩形模糊核桑原滤镜的对比,它们的半径都是5.
如你所见,桑原滤镜在平滑且保持边缘方面做的相当不错,本例中它让边缘依然保持清晰!
同时,这个边缘保持的平滑特性还给图像带来了一种手绘风。因为,绘画的笔刷通常就是边缘较硬而且不会产生很大(画面)噪声的。于是,桑原滤镜就是一个将写实风转换成手绘风的不错的选择。
以下就是一个使用不同大小桑原滤镜处理照片的效果图
本教程中,滤镜将被分割成两个着色器文件:Global.usf 和 Kuwahara.usf。第一个文件要存储计算核平均值以及方差的函数;第二个文件要存储滤镜的入口并且将会为每个核调用上述函数。
首先,我们来定义计算平均值和方差的函数。在范例工程中找到Shaders文件夹,然后打开其中的 Global.usf。我们可以看到其中名为GetKernelMeanAndVariance()
的函数。
开始构建函数之前,我们需要添加几个参数。修改后的函数如下:
float4 GetKernelMeanAndVariance(float2 UV, float4 Range)
我们需要两重循环对一个网格进行采样:一个循环负责垂直方向另一个负责水平方向。Range参数的前两个通道存储水平循环的边界,后两个通道存储垂直循环的边界。例如:我们正在对坐上角的核进行采样且核大小为2,那么它的Range即为:
Range = float4(-2, 0, -2, 0);
好,现在开始抽样。
像素抽样先创建2重循环,在GetKernelMeanAndVariance()
函数中添加如下代码:
for (int x = Range.x; x
关注
打赏
最近更新
- 深拷贝和浅拷贝的区别(重点)
- 【Vue】走进Vue框架世界
- 【云服务器】项目部署—搭建网站—vue电商后台管理系统
- 【React介绍】 一文带你深入React
- 【React】React组件实例的三大属性之state,props,refs(你学废了吗)
- 【脚手架VueCLI】从零开始,创建一个VUE项目
- 【React】深入理解React组件生命周期----图文详解(含代码)
- 【React】DOM的Diffing算法是什么?以及DOM中key的作用----经典面试题
- 【React】1_使用React脚手架创建项目步骤--------详解(含项目结构说明)
- 【React】2_如何使用react脚手架写一个简单的页面?