Unity_Shader高级篇_12.1_Unity Shader入门精要

本文深入探讨Unity Shader的高级技术,包括12.4章节的高斯模糊原理和优化,12.5章节的Bloom特效实现,以及12.6章节的运动模糊模拟。通过高斯滤波实现图像模糊,Bloom效模仿真真实摄像机的朦胧效果,运动模糊则利用像素运动速度模拟现实世界的运动模糊现象。详细介绍了每个效果的实现步骤和关键技巧。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

12.4 高斯模糊
高斯滤波
高斯模糊同样利用了卷积计算,它使用的卷积核名为高斯核。高斯核是一个正方形大小的滤波核,其中每个元素的计算都是基于下面的高斯方程:
这里写图片描述
其中,σ是标准方差(一般取值为1),x和y分别对应了当前位置到卷积核中心的整数距离。要构建一个高斯核,我们只需要计算告诉核内各个位置对应的高斯值。为了保证滤波后的图像不会变暗,我们需要对高斯核中的权重进行归一化,即让每个权重除以所有权重的和,这样可以保证所有权重的和为1。因此,高斯函数中e前面的系数实际不会对结果有任何影响。下图显示了一个标准方差为1的5×5大小的高斯核。
高斯方程很好地模拟了领域每个像素对当前处理像素的影响程度——距离越近,影响越大。高斯核的维数越高,模糊程度越大。使用一个N×N的高斯核对图像进行卷积滤波,就需要N×N×W×H(W和H分别是图像的宽和高)次纹理采样。当N的大小不断增加时。采样次数会变得非常巨大。于是我们可以把这个二维高斯函数拆分成两个一维函数。也就是说,我们可以使用两个一维的高斯核先后对图像进行滤波,这样的采样次数只需要2×N×W×H。进一步观察到,两个一维高斯核中包含了很多重复的权重。对于一个大小为5的一维高斯核,我们实际只需要记录3个权重值。
我们先后调用两个Pass,第一个Pass将会使用竖直方向的一维高斯核对图像进行滤波,第二个Pass再使用水平方向的一维高斯核对图像进行滤波,得到最终的目标图像。在实现中,我们还将利用图像缩放来进一步提高性能,并通过调整高斯滤波的应用次数来控制模糊程度(次数越多,图像越模糊)。
实现流程
(1)新建场景(Scene_12_4)。
(2)把Sakural.jpg拖拽到场景中(纹理类型为Sprite)。
(3)新建一个脚本(GaussianBlur.cs),拖拽到摄像机上。
(4)新建Unity SHader(Chapter12-GaussianBlur)

using UnityEngine;
using System.Collections;

//依旧继承12.1节中创建的基类:
public class GaussianBlur : PostEffectsBase {

    //指定的Shader,将会实现的Chapter12-GaussianBlur
    public Shader gaussianBlurShader;

    private Material gaussianBlurMaterial = null;

    public Material material {  
        get {
            gaussianBlurMaterial = CheckShaderAndCreateMaterial(gaussianBlurShader, gaussianBlurMaterial);
            return gaussianBlurMaterial;
        }  
    }

    // 模糊迭代——更大的数字意味着更多的模糊
    [Range(0, 4)]
    public int iterations = 3;

    // 每个迭代的模糊扩展——更大的值意味着更多的模糊
    [Range(0.2f, 3.0f)]
    public float blurSpread = 0.6f;

    [Range(1, 8)]
    public int downSample = 2;
    //blurSpread和downSample都是出于性能的考虑。在高斯核维数不变的情况下,_BlurSize越大,模糊程度
    //越高,但采样数却不会受到影响。但过大的_BlurSize值会造成虚影,这并不是我们希望的。而downSample越大,
    //需要处理的像素越少,同时也能进一步提高模糊程度,但过大的downSample可能会使图像像素化。

    /// 第1版:应用模糊
    //  void OnRenderImage(RenderTexture src, RenderTexture dest) {
   
   
    //      if (material != null) {
   
   
    //          int rtW = src.width;
    //          int rtH = src.height;
    //          RenderTexture buffer = RenderTexture.GetTemporary(rtW, rtH, 0);
    //
    //          // Render the vertical pass
    //          Graphics.Blit(src, buffer, material, 0);
    //          // Render the horizontal pass
    //          Graphics.Blit(buffer, dest, material, 1);
    //
    //          RenderTexture.ReleaseTemporary(buffer);
    //      } else {
   
   
    //          Graphics.Blit(src, dest);
    //      }
    //  } 
    ///与上两节的实现不同,我们这里利用RenderTexture.GetTemporary函数分配了一块与屏幕图像大小
    ///相同的缓冲区。这是因为,高斯模糊需要调用两个Pass,我们需要使用一块中间缓存来存储第一个Pass执行
    ///完毕后得到的模糊结果。如代码所示,我们首先调用Graphics.Blit(src, buffer, material, 0);,使用
    ///Shader中的第一个Pass(即使用竖直方向的一维高斯核进行滤波)对src进行处理,并将结果存储在了
    ///buffer中。然后再调用Graphics.Blit(buffer, dest, material, 1),使用Shader中的第二个Pass(即
    ///使用水平方向的一维高斯核进行滤波)对buffer进行处理,返回最终的屏幕图像。最后,我们还需要
    ///调用RenderTexture.ReleaseTemporary来释放之前分配的缓存。


    /// 第二版:缩放渲染纹理 
    //  void OnRenderImage (RenderTexture src, RenderTexture dest) {
   
   
    //      if (material != null) {
   
   
    //          int rtW = src.width/downSample;
    //          int rtH = src.height/downSample;
    //          RenderTexture buffer = RenderTexture.GetTemporary(rtW, rtH, 0);
    //          buffer.filterMode = FilterMode.Bilinear;
    //
    //          // Render the vertical pass
    //          Graphics.Blit(src, buffer, material, 0);
    //          // Render the horizontal pass
    //          Graphics.Blit(buffer, dest, material, 1);
    //
    //          RenderTexture.ReleaseTemporary(buffer);
    //      } else {
   
   
    //          Graphics.Blit(src, dest);
    //      }
    //  }
    ///将利用缩放对图像进行降采样,从而减少需要处理的像素个数,提高性能。
    ///与第一个版本代码不同,我们在声明缓冲区的大小时,使用了小于原屏幕分辨率的尺寸,并将该临时
    ///渲染纹理的滤波模式设置为双线性。这样,在调用第一个Pass时,我们需要处理的像素个数就是原来
    ///的几分之一。对图像进行降采样不仅可以减少需要处理的像素个数,提高性能,而且适当的降采样往往还可以
    
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值