unity屏幕后处理Bloom优化(光晕)

2023-11-15

前言:前几天看米哈游的技术总监说:《崩坏3》的bloom效果的实现是
(1)高亮像素过滤
(2)向下采样(降采样)
(3)向上采样
(4)将模糊后的图像和原图像混合

经过上面的步骤,能高效的实现bloom效果


常规的bloom是使用: 提取高亮+ 卷积滤波横向和纵向+ 混合高亮模糊图和原图(这种实现方式和原理介绍,网上一大堆,这里就不再细说了)



一.效果图:
在这里插入图片描述在这里插入图片描述

话不多说,直接上代码:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

[ExecuteInEditMode]
[ImageEffectAllowedInSceneView]
public class Bloom : MonoBehaviour
{
    #region constData
    const int firstPass = 0;
    const int downPass = 1;
    const int upPass = 2;
    const int mixPass = 3;
    #endregion


    public Shader bloom;
    private Material material;
    [Range(0,8)]
    public int Interations;
    [Range(1,10)]// 已经限定从1开始, 只有开启HDR的才会开启bloom
    public float Threshold =1;
    [Range(0,1)]
    public float SoftThreshold = 0.5f;
    [Range(0,10)]
    public float Intensity = 1;
    RenderTexture[] textures = new RenderTexture[8];
    private void OnRenderImage(RenderTexture source, RenderTexture destination)
    {
        if (!material)
        {
            material = new Material(bloom);
            material.hideFlags = HideFlags.HideAndDontSave;
        }
        material.SetFloat("_Threshold", Threshold);
        material.SetFloat("_Intensity", Intensity);
        float knee = Threshold - SoftThreshold;
        Vector4 filter;
        filter.x = Threshold;
        filter.y = Threshold - knee;
        filter.z = 2 * knee;
        filter.w = 4 * knee + 0.00001f;
        // 将参数,以V4的形式传递进shader,将计算量留在CPU,减少GPU的计算
        material.SetVector("_Filter", filter);


        int width = source.width;
        int height = source.height;
        width /= 2;
        height /= 2;
        RenderTextureFormat format = source.format;
        RenderTexture currentDestination = textures[0] = RenderTexture.GetTemporary(width, height, 0, format);
        Graphics.Blit(source, currentDestination,material,firstPass);
        RenderTexture currentSource = currentDestination;
        int i = 1;
        // 向下采样
        for (; i < Interations; i++)
        {
            width /= 2;
            height /= 2;
            if (height<2)
            {
                break;
            }
            currentDestination = textures[i] = RenderTexture.GetTemporary(width, height, 0, format);
            Graphics.Blit(currentSource, currentDestination,material,downPass);
            currentSource = currentDestination;
        }
        //向上采样
        for (i-=2; i>=0; i--)
        {
            currentDestination = textures[i];
            textures[i] = null;            
            Graphics.Blit(currentSource, currentDestination,material,upPass);
            RenderTexture.ReleaseTemporary(currentSource);
            currentSource = currentDestination;
        }
        material.SetTexture("_SourceTex", source);
        //混合
        Graphics.Blit(currentDestination, destination,material,mixPass);
        RenderTexture.ReleaseTemporary(currentDestination);
    }
}

Shader "custom/Bloom"
{
    Properties
    {
        _MainTex ("Texture", 2D) = "white" {}
        //_SourceTex("SourceTex",2D) = "white"{}
        //_Threshold("_Threshold",float) = 1
        //_Filter("_Filter",Vector) = (0,0,0,0)
    }

	CGINCLUDE
            #include "UnityCG.cginc"
            float _Threshold;
            struct appdata
            {
                float4 vertex : POSITION;
                float2 uv : TEXCOORD0;
            };

            struct v2f
            {
                float2 uv : TEXCOORD0;
                float4 vertex : SV_POSITION;
            };

            v2f vert (appdata v)
            {
                v2f o;
                o.vertex = UnityObjectToClipPos(v.vertex);
                o.uv = v.uv;
                return o;
            }

            sampler2D _MainTex;
            float4 _MainTex_TexelSize;
            sampler2D _SourceTex;
            float4 _SourceTex_ST; 
            vector _Filter;  
			float _Intensity;
            half3 Sample(float2 uv)
            {
                return tex2D(_MainTex,uv).rgb;
            }
            //
            half3 SampleBox(float2 uv,float detail)
            {
                float4 o = _MainTex_TexelSize.xyxy * float4(-detail,-detail,detail,detail);
                half3 c = Sample(uv+ o.xy) + Sample(uv + o.xz) + Sample(uv+o.zw) +Sample(uv+o.zx);
                return c*0.25;
            }

            // half3 Prefilter(half3 c)
            // {
            //     half brightness = max(c.r,max(c.g,c.b));
            //     half contribution = max(0,brightness - _Threshold);
            //     contribution /= max(brightness,0.00001);
            //     return contribution;
            // }
            half3 Prefilter(half3 c)
            {
                half brightness = max(c.r,max(c.g,c.b));
                half soft = brightness - _Filter.y;
                soft = clamp(soft,0,_Filter.z);
                soft = soft * soft/_Filter.w;
                half contribution = max(soft,brightness- _Filter.x);
                contribution /= max(brightness,0.00001);
                return contribution*c;
            }

	ENDCG
    SubShader
    {
        // No culling or depth
        Cull Off ZWrite Off ZTest Always
        Pass
        {        //像素的预筛选
            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag        
            fixed4 frag (v2f i) : SV_Target
            {
                half3 col = Prefilter(SampleBox(i.uv,1));
                return fixed4(col,1);
            }
            ENDCG
        }

        Pass
        {
            //下采样
            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag          

            fixed4 frag (v2f i) : SV_Target
            {
                
                half3 col = SampleBox(i.uv,1);
                return fixed4(col,1);
            }
            ENDCG
        }
        Pass
        {
            Blend One One
            // 上采样
            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag          

            fixed4 frag (v2f i) : SV_Target
            {
                
                half3 col = SampleBox(i.uv,0.5);
                return fixed4(col,1);
            }
            ENDCG
        }
        Pass
        {
            //混合
            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag  
            
                 

            fixed4 frag (v2f i) : SV_Target
            {
                
                half3 col = SampleBox(i.uv,0.5) + tex2D(_SourceTex,i.uv).rgb * _Intensity;
                //half3 col = SampleBox(i.uv,1);
                return fixed4(col,1);
            }
            ENDCG
        }
    }
}

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

unity屏幕后处理Bloom优化(光晕) 的相关文章

  • 修复 Nvidia 和 AMD 的 GLSL 着色器

    我在让 GLSL 着色器在 AMD 和 Nvidia 硬件上工作时遇到问题 我并不是在寻求修复特定着色器的帮助 而是寻求如何避免出现这些问题 是否可以检查着色器是否可以在 AMD Nvidia 驱动程序上编译 而无需在具有相应硬件的计算机上
  • 将阴影添加到视差遮挡贴图

    我已经通过实现视差遮挡贴图学习OpenGL https learnopengl com Advanced Lighting Parallax Mapping 现在我想添加自阴影 以便片段挤压在表面上投射阴影 我读过一些关于这个主题的论文 但
  • 移动物体的漫射照明

    当计算移动物体的漫射照明时 我必须将光源与物体本身一起移动 Override public void draw draw frame Move object GLES20 glVertexAttribPointer aPositionLin
  • Android 中图像的填充图案

    下面给出了两个图像 我将第一个图像称为帧图像 将第二个图像称为帧图像 这里 fst 是我的线性布局 我将帧图像设置为它的背景图像 现在我想在帧图像的白色区域中填充图案图像 帧图像的外部区域是透明的 内部区域是白色的 我如何在我的框架图像中填
  • openGL:带有着色器的线条

    如何使用着色器创建一条线 可能是彩色的 我正在使用可编程管道 并且我是 openGL 的初学者 我找不到有关如何使用着色器绘制线条的示例 我想我必须将 VAO 顶点数组对象 加载到着色器中 但是然后呢 我应该使用哪些功能以及如何使用 首先
  • 用于几何入口点的 SceneKit 着色器修改器适用于 iOS,但不适用于 OS X

    我正处于制作 SceneKit 着色器修改器 用于几何入口点 的早期阶段 该修改器根据高度图纹理置换平面的几何形状 计划是用它来创建地形 在 iOS 编辑 iOS 模拟器 中 着色器按其应有的方式工作 但会将此警告打印到控制台 SceneK
  • Unity3D Sprite ...但是单面的?

    团结优秀Sprites Unity优秀的新精灵 http docs unity3d com ScriptReference Sprite html 除其他有价值的优点外 实际上是双面的 在 2D 或 3D 用例中 您可以翻转这些小混蛋 但仍
  • 使用GL着色器语言的相机帧yuv到rgb转换

    我从字节数组中的 android 相机预览回调获取相机帧并将其传递给 jni 代码 由于我们不能在 C 中使用字节 因此我将其转换为整数数组 如下所示 JNIEXPORT void JNICALL Java com omobio armad
  • 处理中点/笔划的景深着色器

    最近我一直在使用下面的景深着色器 最初来自ofx后处理 https github com neilmendoza ofxPostProcessing blob master src DofPass cppOpenFrameworks 库 用
  • 使用 texelFetch() 进行纹理化

    当我将非最大值传递到纹理缓冲区时 在渲染时它会绘制具有最大值颜色的几何图形 我在使用 glTexBuffer API 时发现了这个问题 例如 假设我的纹理数据是GLubyte 当我传递任何小于255的值时 那么颜色与用255绘制的颜色相同
  • 为什么我不能使用uniform1f而不是uniform4f来设置vec4制服?

    我通过以下方式逐步学习WebGL这本书 https sites google com site webglbook 我尝试通过使用缓冲区来绘制三个点 gl ARRAY BUFFER 而不是循环 正如我之前在本书的其他示例中所做的那样 var
  • 如何将shadershop公式转换成glsl

    我最近一直在学习着色器的一些基础知识 并且想出了一个很棒的视觉工具 着色器商店 http www cdglabs org Shadershop 但我无法将我在此站点中创建的公式转换为 glsl 一个简单的例子 我在此网站中创建了一个公式 我
  • OpenGL 统一缓冲区 std140 布局

    我正在尝试通过 GeForce 8600 GT 上的统一块将整数数组传递给片段着色器 一切均根据 GLSL version 330 在应用程序方面我有 int MyArray 7102 filling binding etc glBuffe
  • OpenGL - 固定管线着色器默认值(使用着色器模仿固定管线)

    谁能给我提供类似于固定功能管道的着色器 我最需要默认的片段着色器 因为我在网上找到了类似的顶点着色器 但如果你有一双应该没问题 我想使用固定管道 但具有着色器的灵活性 因此我需要类似的着色器 以便我能够模仿固定管道的功能 非常感谢 我是新来
  • OpenGL ES 2.0 多个程序或多着色器还是什么?它是如何工作的?

    问题 TL DR 我的问题从根本上来说是我不知道 OpenGL ES 2 0 期望我如何编写和使用多个着色器 或者如果甚至建议 期望一个人会这样做 这里的基本问题是 如果我有一个苹果 一块发光的岩石和一个模糊网格 它们都在同一个 3D 世界
  • 如何使用鼠标改变OpenGL相机

    我正在尝试在 OpenGL 中设置一个相机来查看 3 维中的一些点 为了实现这一点 我不想使用旧的 固定的功能样式 glMatrixMode glTranslate 等 而是自己设置模型视图投影矩阵并在我的顶点着色器中使用它 正交投影就足够
  • Unity 后处理 PostProcessEffectRenderer 在编辑器中显示,但在构建中不显示

    将 PostProcessEffectRenderer 的实现添加到 Unity 后处理堆栈后 效果在 Unity 编辑器中完美运行 但不会在构建的游戏中显示 对构建质量的更改没有效果 使用针对 Windows x86 64 构建的最高质量
  • 使用 GLSL 着色器在同一片段着色器中定义的多个子例程类型无法正常工作

    我正在开发一个使用 GLSL 着色器的程序 我编写了 2 种不同的方法来用 2 种不同的方法计算 ADS 环境光 漫反射 镜面反射 着色 为了正确完成这项工作 我使用子例程来使用一种或另一种方法来计算 ADS 着色 这是片段着色器代码的一部
  • 更改 Qt OpenGL 窗口示例以使用 OpenGL 3.3

    我正在尝试更改 Qt OpenGL 示例以使用更现代的 opengl 版本 330 似乎合适 所以我做了 在 main cpp 上设置版本和配置文件 设置着色器版本 更改着色器以使用统一 它现在构建没有任何错误 但我只看到一个空白窗口 我错
  • 按像素值偏移 gl_Position 或 gl_Vertex

    我的属性包含像素值 我想用这个属性值来偏移我的 gl vertex 问题是我的 gl vertex 以世界单位为单位 而 offset attribute 以像素为单位 如果我将屏幕尺寸作为统一发送 然后将像素转换为 1 到 1 值 并将其

随机推荐

  • mysql查询json字段中value值,mysql查询字段不包含某个字符串

    工作中遇到问题 需要查询表中某个字段不包含某个指定字符串的问题 以及查询json数据中某个key对应的value值 问题1 查询 user id 不包含 字符的数据 数据如下 id user id 51 jingi ctfo com 52
  • 逻辑思维三大定律

    逻辑思维三大定律 同一律 矛盾律 排中律 同一律 A 是 A 前后思维中 概念要同一 白马非马论违反同一律 商家的买一赠一 前后两个一不是同一个概念 违反同一律 同一律是逻辑思维的基础 矛盾律 A 是 B A 不是B 这两句话矛盾 对同一事
  • c盘那些文件可以删除

    c盘那些文件可以删除 http www xitongzhijia net xtjc 20150507 47691 html
  • OSPF笔记(一):OSPF基本特点、自治系统、区域、RID冲突

    一 OSPF基本特点 1 1 支持无类域间路由 CIDR 1 2 无环路 1 区域内 100 无环 2 区域间 不一定无环 1 3 收敛速度快 1 4 使用组播收发协议数据 224 0 0 5 224 0 0 6 1 5 支持多条等价路由
  • MySQL数据库 学习笔记 零基础入门 面试 整理

    一 MySQL基础篇 1 数据库技术的基本概念和方法 1 1 数据库基本概念 1 数据 数据 Data 指对客观事物进行描述并可以鉴别的符号 这些符号是可识别的 抽象的 不仅仅指狭义上的数字 而是有多种表现形式 字母 文字 文本 图形 音频
  • 【笔试强训选择题】Day32.习题(错题)解析

    作者简介 大家好 我是未央 博客首页 未央 303 系列专栏 笔试强训选择题 每日一句 人的一生 可以有所作为的时机只有一次 那就是现在 文章目录 前言 一 Day32习题 错题 解析 总结 前言 今天是笔试强训第32天 一 Day32习题
  • React Native API

    Dimensions 面对现代手机五花八门的屏占比 不知道宽度的情况下可以使用 import Dimensions from react native const DimenStyle Dimensions get window 屏幕宽度
  • 深度学习研究思路

    研究思路 一 数字图像 基础研究 图像的文件格式 图片有常见的bmp jpg png 等 三种图像之间的差别 位图和矢量图区别 矢量图又叫向量图 是用一系列计算机指令来描述和记录一幅图 一幅图可以解为一系列由点 线 面等到组成的子图 它所记
  • Vue ECharts y轴设置固定分段 + makerline设置为不同的样式作为区分 - 附完整示例

    echarts 一个基于 JavaScript 的开源可视化图表库 官方文档 Apache ECharts Apache EChartsApache ECharts 一款基于JavaScript的数据可视化图表库 提供直观 生动 可交互 可
  • JS_随机选取指定数组中的颜色值

    思路 定义需要的颜色 生成已定数组长度范围内的随机数 随机数与i对比 let colorList 1882f8 f95757 FFBF11 11BBEC FB7C26 46BE1A let colorMath Math floor Math
  • 使用命令行编译和运行java程序

    前言 现在很多IDE都可以自动编译和运行java程序了 但是我觉得还是有必要学会用命令行编译和运行java程序 这样就能更好理解java程序运行的机制 为了不依赖IDE 我用记事本作为编辑器 1 安装JDK 安装过程我就不仔细讲了 网上很多
  • C++ 中 static 静态对象的使用总结

    背景 全局 静态数据区主要用于存放全局变量和静态变量 在程序启动时 全局 静态数据已经分配了存储空间 全局 静态数据区中的数据在程序结束后由操作系统释放 未初始化的静态变量会被程序自动初始化为 0 静态局部变量在程序执行到该对象的声明处时被
  • 回文串(algorithm)

    题目 回文子串的个数 中心扩展 给你一个字符串 s 请你统计并返回这个字符串中 回文子串 的数目 回文字符串 是正着读和倒过来读一样的字符串 子字符串 是字符串中的由连续字符组成的一个序列 具有不同开始位置或结束位置的子串 即使是由相同的字
  • Nacos简单使用及相关配置注意点

    1 Nacos安装 本文采用 docker 方式进行安装 docker 安装较为简单便捷 自己学习推荐采用此方式进行 docker 基本命令就不再赘述了 此处附上主要命令 此处nacos安装版本采用2 0 3 拉取 2 0 3 版本的 na
  • 【极验黑科技】文生图大模型在极验人机对抗领域的应用

    自极验于2013年开创性地提出新一代的智能验证码概念开始 就始终在人机对抗领域不停地升级迭代 极验全球首创的 行为式验证 在十多年来 为全球近40万的开发者使用 如小米 新浪微博 东方航空 国家工商局等企业携手极验验证码进行升级 使得现在传
  • Python数据分析之对一个游戏的运营情况进行分析

    Python数据分析之对一个游戏的运营情况进行分析 文章目录 Python数据分析之对一个游戏的运营情况进行分析 一 分析目标 二 数据介绍 三 结论 1 新增用户分析 2 玩家活跃度分析 3 玩家付费情况分析 4 玩家游戏习惯分析 四 详
  • 稳健回归-鲁棒回归

    稳健回归 稳健回归 robust regression 是统计学稳健估计中的一种方法 其主要思路是将对异常值十分敏感的经典最小二乘回归中的目标函数进行修改 经典最小二乘回归以使误差平方和达到最小为其目标函数 稳健回归 robust regr
  • 如何将项目提交到别人的仓库

    大纲 1 在gitee中克隆 clone 别人仓库的代码 首先 进入别人的仓库 点击 克隆 下载 2 在你存放项目的文件夹下克隆你刚刚复制的代码 右键点击Git Clone即可 点击OK 就开始克隆了 克隆成功之后 文件上会出现一个绿色的
  • 了解预训练以及在自编码器中的应用

    预训练是一种机器学习技术 在这种技术中 模型被训练以在标注数据少或不存在的情况下自动从未标记的数据中学习 预训练可以为模型提供先验知识 使其能够在特定任务上更好地泛化 预训练过程通常分为两个阶段 无监督预训练和有监督微调 无监督预训练 模型
  • unity屏幕后处理Bloom优化(光晕)

    前言 前几天看米哈游的技术总监说 崩坏3 的bloom效果的实现是 1 高亮像素过滤 2 向下采样 降采样 3 向上采样 4 将模糊后的图像和原图像混合 经过上面的步骤 能高效的实现bloom效果 常规的bloom是使用 提取高亮 卷积滤波