Learn ComputeShader 11 Star Glow Effect

news2024/11/14 14:59:00

这次要使用到顶点和片段着色器。同样是制作屏幕后处理效果。

下面是一开始的效果,只是一个循环播放的粒子系统。

我们首先要对源图像的亮部区域进行提亮,然后进行模糊添加光芒。然后进行混合,最后进行一次合成

我们需要创建一些临时纹理来存储渲染过程的中间阶段,之后先通过第一个pass将原图像提亮,下面是关键代码, Graphics.Blit(source, brightnessTex, material, 1)这个函数的就是通过material的第二个pass对图像进行处理,

 void OnRenderImage(RenderTexture source, RenderTexture destination)
    {
        RenderTexture brightnessTex = RenderTexture.GetTemporary(source.width / divide, source.height / divide, source.depth, source.format);
        RenderTexture blurredTex1 = RenderTexture.GetTemporary(brightnessTex.descriptor);
        RenderTexture blurredTex2 = RenderTexture.GetTemporary(brightnessTex.descriptor);
        RenderTexture compositeTex = RenderTexture.GetTemporary(brightnessTex.descriptor);

        material.SetVector(brightnessSettingsID, new Vector3(threshold, intensity, attenuation));

        // 进行渲染操作

        Graphics.Blit(source, brightnessTex, material, 1);
        Graphics.Blit(brightnessTex, destination, material, 0);
        //Graphics.Blit(source, destination, material, 0);

        // 释放临时RenderTextures
        RenderTexture.ReleaseTemporary(brightnessTex);
        RenderTexture.ReleaseTemporary(blurredTex1);
        RenderTexture.ReleaseTemporary(blurredTex2);
        RenderTexture.ReleaseTemporary(compositeTex);
    }

下面是shader代码

            fixed4 frag(v2f_img input) : SV_Target
            {
               float4 color = tex2D(_MainTex,input.uv ) ;
                
               return max(color - BRIGHTNESS_THRESHOLD,0)* INTENSITY;

            }

 然后下一步就是为星星添加光芒条纹。

要以特定角度模糊上一步的图像,然后迭代多次

创建一个新的pass,_MainTex_TexelSize.xy就是图像宽度的倒数。计算颜色之后每次对uv进行偏移并对颜色进行衰减

 Pass
        {
            CGPROGRAM

            #pragma vertex vert
            #pragma fragment frag

            int _Iteration;
            float2 _Offset;
            struct v2f_starglow {
                float4 pos : SV_POSITION;   // 变换后的屏幕空间坐标
                half2 uv : TEXCOORD0;       // 纹理坐标
                half power : TEXCOORD1;     
                half2 offset : TEXCOORD2;   // 偏移量
            };

            v2f_starglow vert(appdata_img v) 
            {
                v2f_starglow o;
    
                // 计算顶点位置
                o.pos = UnityObjectToClipPos(v.vertex);

                // 传递纹理坐标
                o.uv = v.texcoord;

                o.power = pow(4.0, _Iteration - 1.0);

                // 计算偏移量
                o.offset = _MainTex_TexelSize.xy * _Offset * o.power;

                return o;
             }


            float4 frag(v2f_starglow input) : SV_Target 
            {
                half4 color = half4(0, 0, 0, 0); // 初始化颜色为黑色
                half2 uv = input.uv;
    
                // 遍历4个样本
                for (int j = 0; j < 4; j++) {
                    // 采样纹理并应用衰减
                    color += saturate(tex2D(_MainTex, uv) * pow(ATTENUATION, input.power * j));
                    // 更新纹理坐标
                    uv += input.offset;
                }
    
                return color;
            }


            ENDCG
        }

C#代码:

 float angle = 360f / numOfStreaks;

        for (int x = 1; x <= numOfStreaks; x++)
        {
            // 计算每个条纹的偏移量
            Vector2 offset = (Quaternion.AngleAxis(angle * x + angleOfStreak, Vector3.forward) * Vector2.down).normalized;

            // 设置材质的偏移量和迭代次数
            material.SetVector(offsetID, offset);
            material.SetInt(iterationID, 1);

            // 使用材质进行图像处理
            Graphics.Blit(brightnessTex, blurredTex1, material, 2);

            for (int i = 2; i <= iteration; i++)
            {
                // 设置当前迭代次数
                material.SetInt(iterationID, i);

                // 进行图像处理,将 blurredTex1 处理并输出到 blurredTex2
                Graphics.Blit(blurredTex1, blurredTex2, material, 2);

                // 交换纹理,准备下一次迭代
                RenderTexture temp = blurredTex1;
                blurredTex1 = blurredTex2;
                blurredTex2 = temp;
            }

        }

然后要进行一次混合

 //  STEP:3
                Pass
        {
            // 设置混合模式
            Blend OneMinusDstColor One

            CGPROGRAM
            #pragma vertex vert_img
            #pragma fragment frag

            #include "UnityCG.cginc"

            // 定义片元着色器
            fixed4 frag(v2f_img input) : SV_Target
            {
                // 从 _MainTex 采样颜色并返回
                return tex2D(_MainTex, input.uv);
            }

            ENDCG
        }

最后将源图像与上一步中得到的图像进行叠加

最终效果:

完整代码:

starglow.shader

Shader "ImageEffect/StarGlow"
{
    Properties
    {
        [HideInInspector]
        _MainTex("Texture", 2D) = "white" {}
        _BrightnessSettings("(Threshold, Intensity, Attenuation, -)", Vector) = (0.8, 1.0, 0.95, 0.0)
    }
    SubShader
    {
        CGINCLUDE

        #include "UnityCG.cginc"

        sampler2D _MainTex;
        float4    _MainTex_ST;
        float4    _MainTex_TexelSize;
        float4    _BrightnessSettings;

        #define BRIGHTNESS_THRESHOLD _BrightnessSettings.x
        #define INTENSITY            _BrightnessSettings.y
        #define ATTENUATION          _BrightnessSettings.z

        ENDCG

        // STEP:0
        // Debug.

        Pass
        {
            CGPROGRAM

            #pragma vertex vert_img
            #pragma fragment frag

            fixed4 frag(v2f_img input) : SV_Target
            {
                return tex2D(_MainTex, input.uv);
            }

            ENDCG
        }
        // STEP:1
           Pass
        {
            CGPROGRAM

            #pragma vertex vert_img
            #pragma fragment frag

            fixed4 frag(v2f_img input) : SV_Target
            {
               float4 color = tex2D(_MainTex,input.uv ) ;
                
               return max(color - BRIGHTNESS_THRESHOLD,0)* INTENSITY;

            }

            ENDCG
        }

          // STEP:2
           Pass
        {
            CGPROGRAM

            #pragma vertex vert
            #pragma fragment frag

            int _Iteration;
            float2 _Offset;
            struct v2f_starglow {
                float4 pos : SV_POSITION;   // 变换后的屏幕空间坐标
                half2 uv : TEXCOORD0;       // 纹理坐标
                half power : TEXCOORD1;     
                half2 offset : TEXCOORD2;   // 偏移量
            };

            v2f_starglow vert(appdata_img v) 
            {
                v2f_starglow o;
    
                // 计算顶点位置
                o.pos = UnityObjectToClipPos(v.vertex);

                // 传递纹理坐标
                o.uv = v.texcoord;

                o.power = pow(4.0, _Iteration - 1.0);

                // 计算偏移量
                o.offset = _MainTex_TexelSize.xy * _Offset * o.power;

                return o;
             }


            float4 frag(v2f_starglow input) : SV_Target 
            {
                half4 color = half4(0, 0, 0, 0); // 初始化颜色为黑色
                half2 uv = input.uv;
    
                // 遍历4个样本
                for (int j = 0; j < 4; j++) {
                    // 采样纹理并应用衰减
                    color += saturate(tex2D(_MainTex, uv) * pow(ATTENUATION, input.power * j));
                    // 更新纹理坐标
                    uv += input.offset;
                }
    
                return color;
            }


            ENDCG
        }
       //  STEP:3
                Pass
        {
            // 设置混合模式
            Blend OneMinusDstColor One

            CGPROGRAM
            #pragma vertex vert_img
            #pragma fragment frag

            #include "UnityCG.cginc"

            // 定义片元着色器
            fixed4 frag(v2f_img input) : SV_Target
            {
                // 从 _MainTex 采样颜色并返回
                return tex2D(_MainTex, input.uv);
            }

            ENDCG
        }

        // Step 4 Pass
        Pass
        {
            CGPROGRAM
            #pragma vertex vert_img
            #pragma fragment frag

            sampler2D _CompositeTex;
            float4 _CompositeColor;

            fixed4 frag(v2f_img input) : SV_Target
            {
                // 从 _MainTex 采样颜色
                float4 mainColor = tex2D(_MainTex, input.uv);

                // 从 _CompositeTex 采样颜色
                float4 compositeColor = tex2D(_CompositeTex, input.uv);

                // 计算 compositeColor 的灰度,并乘以 _CompositeColor
                compositeColor.rgb = (compositeColor.r + compositeColor.g + compositeColor.b) * 0.3333 * _CompositeColor.rgb;

                // 将 mainColor 和 compositeColor 叠加,并限制在 [0,1] 范围
                return saturate(mainColor + compositeColor);
            }

            ENDCG
        }


    }
}

starglow.cs

using System.Collections.Generic;
using UnityEngine;

public class StarGlow : MonoBehaviour
{
    #region Field

    [Range(0, 1)]
    public float threshold = 1;

    [Range(0, 10)]
    public float intensity = 1;

    [Range(1, 20)]
    public int divide = 3;

    [Range(1, 5)]
    public int iteration = 5;

    [Range(0, 1)]
    public float attenuation = 1;

    [Range(0, 360)]
    public float angleOfStreak = 0;

    [Range(1, 16)]
    public int numOfStreaks = 4;

    public Material material;

    public Color color = Color.white;

    private int compositeTexID   = 0;
    private int compositeColorID = 0;
    private int brightnessSettingsID   = 0;
    private int iterationID      = 0;
    private int offsetID         = 0;

    #endregion Field

    #region Method

    void Start()
    {
        compositeTexID   = Shader.PropertyToID("_CompositeTex");
        compositeColorID = Shader.PropertyToID("_CompositeColor");
        brightnessSettingsID   = Shader.PropertyToID("_BrightnessSettings");
        iterationID      = Shader.PropertyToID("_Iteration");
        offsetID         = Shader.PropertyToID("_Offset");
    }

    void OnRenderImage(RenderTexture source, RenderTexture destination)
    {
        RenderTexture brightnessTex = RenderTexture.GetTemporary(source.width / divide, source.height / divide, source.depth, source.format);
        RenderTexture blurredTex1 = RenderTexture.GetTemporary(brightnessTex.descriptor);
        RenderTexture blurredTex2 = RenderTexture.GetTemporary(brightnessTex.descriptor);
        RenderTexture compositeTex = RenderTexture.GetTemporary(brightnessTex.descriptor);

        material.SetVector(brightnessSettingsID, new Vector3(threshold, intensity, attenuation));

        // 进行渲染操作

        Graphics.Blit(source, brightnessTex, material, 1);

        float angle = 360f / numOfStreaks;

        for (int x = 1; x <= numOfStreaks; x++)
        {
            // 计算每个条纹的偏移量
            Vector2 offset = (Quaternion.AngleAxis(angle * x + angleOfStreak, Vector3.forward) * Vector2.down).normalized;

            // 设置材质的偏移量和迭代次数
            material.SetVector(offsetID, offset);
            material.SetInt(iterationID, 1);

            // 使用材质进行图像处理
            Graphics.Blit(brightnessTex, blurredTex1, material, 2);

            for (int i = 2; i <= iteration; i++)
            {
                // 设置当前迭代次数
                material.SetInt(iterationID, i);

                // 进行图像处理,将 blurredTex1 处理并输出到 blurredTex2
                Graphics.Blit(blurredTex1, blurredTex2, material, 2);

                // 交换纹理,准备下一次迭代
                RenderTexture temp = blurredTex1;
                blurredTex1 = blurredTex2;
                blurredTex2 = temp;
            }
            Graphics.Blit(blurredTex1, compositeTex, material, 3);

        }


        material.SetColor(compositeColorID, color);
        material.SetTexture(compositeTexID,compositeTex);
        Graphics.Blit(source, destination,material,4);
        //Graphics.Blit(source, destination, material, 0);

        // 释放临时RenderTextures
        RenderTexture.ReleaseTemporary(brightnessTex);
        RenderTexture.ReleaseTemporary(blurredTex1);
        RenderTexture.ReleaseTemporary(blurredTex2);
        RenderTexture.ReleaseTemporary(compositeTex);
    }

    #endregion Method
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2115682.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

基于Java+SpringBoot+Vue+MySQL的智能菜谱推荐管理系统

作者&#xff1a;计算机学姐 开发技术&#xff1a;SpringBoot、SSM、Vue、MySQL、JSP、ElementUI等&#xff0c;“文末源码”。 专栏推荐&#xff1a;前后端分离项目源码、SpringBoot项目源码、SSM项目源码 系统展示 基于SpringBootVue的智能菜谱推荐管理系统【附源码文档】、…

ML18_EM(Expectation-Maximization)算法详解

1. 梯度上升法和坐标上升法的比较 “梯度上升法”&#xff08;Gradient Ascent Method&#xff09;和“坐标上升法”&#xff08;Coordinate Ascent Method&#xff09;都是优化算法的一部分&#xff0c;用于求解优化问题中的最大值。它们分别基于不同的思路来更新参数以达到目…

51单片机的倒车雷达测距设计【proteus仿真+程序+报告+原理图+演示视频】

1、主要功能 该系统由AT89C51/STC89C52单片机LCD1602显示模块温度传感器模块超声波模块按键等模块构成。适用于倒车雷达测距、超声波测距、汽车防撞报警等相似项目。 可实现功能: 1、LCD1602实时显示环境温度和距离&#xff1b; 2、温度传感器DS18B20采集温度信息&#xff1…

【扇贝编程】使用Selenium模拟浏览器获取动态内容笔记

文章目录 selenium安装 selenium下载浏览器驱动 获取数据处理数据查找一个元素查找所有符合条件的元素 控制浏览器 selenium selenium是爬虫的好帮手&#xff0c; 可以控制你的浏览器&#xff0c;模仿人浏览网页&#xff0c;从而获取数据&#xff0c;自动操作等。 我们只要让…

Bitvise——进入服务器的快捷方式

第一步&#xff1a;在连接进服务器后&#xff0c;点击左侧的保存配置文件&#xff0c;保存至桌面。 第二步&#xff1a;将保存的配置文件&#xff08;后缀为 .tlp&#xff09;打开方式改为bitvise。 第三步&#xff1a;双击配置文件&#xff08;后缀为 .tlp&#xff09;&#…

Redis Sentinel(哨兵)详解

目录 一&#xff1a;什么是Sentinel&#xff08;哨兵&#xff09; 二&#xff1a;Sentinel有什么用 1.监控 2.故障转移 3通知 4.配置提供 三&#xff1a;Sentinel如何检测master节点宕机 1.主观下线 2.客观下线 四&#xff1a;Sentinel是如何选举出新的master 1.s…

树莓派3B串口通信

树莓派3B串口通信 文章目录 树莓派3B串口通信一、串口的基本认知1.1 关于电器标准和协议&#xff1a;RS232RS422RS485 1.2 关于串口的电平&#xff1a;UARTRS232电平TTL电平 1.3 串口通信引脚接线&#xff1a;1.4 串口的通信协议&#xff1a; 二、树莓派串口通信开发2.1 树莓派…

乐凡北斗 | 手持北斗智能终端的作用与应用场景

在科技日新月异的今天&#xff0c;北斗智能终端作为一项融合了北斗导航系统与现代智能技术的创新成果&#xff0c;正悄然改变着我们的生活方式和工作模式。 ​北斗智能终端&#xff0c;是以北斗卫星导航系统为核心&#xff0c;集成了高精度定位、导航、授时等功能的智能设备。它…

JavaEE:多线程进阶(JUC [java.util.concurrent] 的常见类)

文章目录 JUC什么是JUCCallable 接口理解 Callable理解FutureTask ReentrantLock信号量 SemaphoreCountDownLatch JUC 什么是JUC JUC的全称为: java.util.concurrent. JUC是Java并发工具包的一部分。它提供了一组并发编程工具和类&#xff0c;用于处理多线程编程和并发任务。…

SprinBoot+Vue校园数字化图书馆系统的设计与实现

目录 1 项目介绍2 项目截图3 核心代码3.1 Controller3.2 Service3.3 Dao3.4 application.yml3.5 SpringbootApplication3.5 Vue 4 数据库表设计5 文档参考6 计算机毕设选题推荐7 源码获取 1 项目介绍 博主个人介绍&#xff1a;CSDN认证博客专家&#xff0c;CSDN平台Java领域优质…

Linux 操作系统 进程(1)

什么是进程 想要了解什么是进程&#xff0c;或者说&#xff0c;为什么会有进程这个概念&#xff0c;我们就需要去了解现代计算机的设计框架(冯诺依曼体系)&#xff1a; 计算机从设计之初就以执行程序为核心任务&#xff0c;也就是运算器从内存中读取&#xff0c;也只从内存中…

24款奔驰CLE升级原厂360全景影像效果怎么样

24款奔驰 CLE 轿跑&#xff1a;全景视野&#xff0c;驾驭无忧 24款奔驰 CLE 轿跑&#xff0c;以其优雅的线条和卓越的性能&#xff0c;成为道路上的一道亮丽风景。而升级原厂 360 全景影像&#xff0c;将为您的驾驶增添更多安全与便利。 原厂 360 全景影像的升级&#xff0c;…

算法分享——《双指针》

文章目录 ✅[《移动零》](https://leetcode.cn/problems/move-zeroes/)&#x1f339;题目描述&#xff1a;&#x1f697;代码实现&#xff1a;&#x1f634;代码解析&#xff1a; ✅[《复写零》](https://leetcode.cn/problems/duplicate-zeros/)&#x1f339;题目描述&#xf…

心觉:潜意识是一个免费的“超级工作狂”,你居然不会用

我们常听说&#xff1a;潜意识的力量是意识到3万倍以上 你信吗 估计很多人不相信&#xff0c;不相信当然用不好 不相信的原因核心有两个&#xff1a; 没有体验过 寻求绝对的科学验证 这两个原因会让你对潜意识不相信&#xff0c;或者半信半疑 今天我也不会给你绝对的科学…

基于 Unet-MobileNet 网络实现的腹部肝脏语义分割

1、MobileUnet 网络 Unet是一种卷积神经网络&#xff08;CNN&#xff09;架构&#xff0c;通常用于图像分割任务 Unet架构由编码器和解码器组成。编码器负责捕获上下文并从输入图像中提取特征&#xff0c;而解码器负责上采样并生成分割掩模。 Unet中的编码器由多个卷积层组成…

汽车免拆诊断案例 | 捷豹 E-type怠速不稳定

故障现象 一辆3.8E型直列6缸的捷豹&#xff0c;该车的故障原因表现为怠速不稳定&#xff0c;转速不均匀&#xff0c;以及在节气门全开&#xff08;WOT工况&#xff09;时“回火”和加速踏板不能及时提速。这是该车型一个值得关注的典型案例。车主表示&#xff0c;几年前&#…

Python条形码生成

条形码基础知识 在开始编码之前&#xff0c;让我们先了解一下条形码的基本概念。条形码本质上是一种将数据编码成可视模式的方法&#xff0c;通常由一系列平行的黑色条和白色空格组成。常见的条形码类型包括&#xff1a; UPC&#xff08;通用产品代码&#xff09; EAN&#x…

828华为云征文|华为云Flexus X实例部署k3s与kuboard图形化管理工具

828华为云征文&#xff5c;华为云Flexus X实例部署k3s与kuboard图形化管理工具 华为云最近正在举办828 B2B企业节&#xff0c;Flexus X实例的促销力度非常大&#xff0c;特别适合那些对算力性能有高要求的小伙伴。如果你有自建MySQL、Redis、Nginx等服务的需求&#xff0c;一定…

数据结构(邓俊辉)学习笔记】排序 6——希尔排序:框架 + 实例

文章目录 1. 策略2.实例3.循秩访问4. 插入排序5.Shell序列 1. 策略 来学习一种非常别致的排序算法&#xff0c;也就是希尔排序。 希尔排序算法既有着悠久的历史&#xff0c;同时也仍然不失活力。该算法的别致之处在于&#xff0c;它不再是将输入视作为一个一维的序列&#x…

SpringTest框架JUnit单元测试用例获取ApplicationContext实例的方法

JUnit单元测试用例中使用Spring框架&#xff0c;之前我的使用方式很直接。 /*** 用于需要用到Spring的测试用例基类* * author lihzh* alia OneCoder* blog http://www.coderli.com*/ RunWith(SpringJUnit4ClassRunner.class) ContextConfiguration(locations { "/sprin…