Learn ComputeShader 07 Post Processing

news2024/12/24 3:14:21

这次我们将使用计算机着色器对图像进行后处理。

要进行后处理需要将渲染图像从cpu传递给gpu,并在gpu对图像进行处理然后传回cpu。

首先创建一个后处理基类BasePP

首先声明需要用到的属性。

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

[RequireComponent(typeof(Camera))]
public class BasePP : MonoBehaviour
{
    public ComputeShader shader = null;

    protected string kernelName = "CSMain";

    protected Vector2Int texSize = new Vector2Int(0,0);
    protected Vector2Int groupSize = new Vector2Int();
    protected Camera thisCamera;

    protected RenderTexture output = null;
    protected RenderTexture renderedSource = null;

    protected int kernelHandle = -1;
    protected bool init = false;

    protected virtual void Init()
    {
        if (!SystemInfo.supportsComputeShaders)
        {
            Debug.LogError("It seems your target Hardware does not support Compute Shaders.");
            return;
        }

        if (!shader)
        {
            Debug.LogError("No shader");
            return;
        }

        kernelHandle = shader.FindKernel(kernelName);

        thisCamera = GetComponent<Camera>();

        if (!thisCamera)
        {
            Debug.LogError("Object has no Camera");
            return;
        }

        CreateTextures();

        init = true;
    }

    protected void ClearTexture(ref RenderTexture textureToClear)
    {
        if (null != textureToClear)
        {
            textureToClear.Release();
            textureToClear = null;
        }
    }

    protected virtual void ClearTextures()
    {


        ClearTexture(ref output);
        ClearTexture(ref renderedSource);
    }

    protected void CreateTexture(ref RenderTexture textureToMake, int divide=1)
    {
        textureToMake = new RenderTexture(texSize.x/divide, texSize.y/divide, 0);
        textureToMake.enableRandomWrite = true;
        textureToMake.Create();
    }


    protected virtual void CreateTextures()
    {

    }

    protected virtual void OnEnable()
    {
        Init();
    }

    protected virtual void OnDisable()
    {
        ClearTextures();
        init = false;
    }

    protected virtual void OnDestroy()
    {
        ClearTextures();
        init = false;
    }

    protected virtual void DispatchWithSource(ref RenderTexture source, ref RenderTexture destination)
    {
        
    }

    protected void CheckResolution(out bool resChange )
    {
        resChange = false;
    }

    protected virtual void OnRenderImage(RenderTexture source, RenderTexture destination)
    {
        if (!init || shader == null)
        {
            Graphics.Blit(source, destination);
        }
        else
        {
            CheckResolution(out _);
            DispatchWithSource(ref source, ref destination);
        }
    }

}

初始化以后就会创建纹理,但是这个函数还没有完善。

首先设置纹理的宽度和高度,然后获取线程组的x和y的大小,这里GetKernelThreadGroupSizes的都三个参数out _表示忽略z 轴的线程组尺寸,这是 C# 语言中的一种方式,用于表示对某个输出值不感兴趣,不需要它的实际值。,然后创建两张纹理并传递给shader。

    protected virtual void CreateTextures()
    {
        texSize.x = thisCamera.pixelWidth;//返回摄像机视口的宽度和高度
        texSize.y = thisCamera.pixelHeight;

        if (shader)
        {
            uint x, y;
            shader.GetKernelThreadGroupSizes(kernelHandle, out x, out y,out _);
            groupSize.x = Mathf.CeilToInt((float)texSize.x / (float)x);
            groupSize.y = Mathf.CeilToInt((float)texSize.y / (float)y);
        }

        CreateTexture(ref output);
        CreateTexture(ref renderedSource);

        shader.SetTexture(kernelHandle, "source", renderedSource);
        shader.SetTexture(kernelHandle, "output", output);
    }

下面就是要获取到渲染的纹理并传递到GPU

 OnRenderImage(RenderTexture source, RenderTexture destination)这个函数可以获取摄像机渲染后的图像到source,并通过对原图像的一系列处理之后设置到destination上。

OnRenderImage 是 Unity 中的一个特殊回调函数,用于在摄像机完成渲染之后对图像进行后处理。它是在摄像机渲染过程的最后阶段被自动调用的。你不需要手动调用这个函数,而是由 Unity 引擎在渲染管线中自动调用。

    protected virtual void OnRenderImage(RenderTexture source, RenderTexture destination)
    {
        if (!init || shader == null)
        {
            Graphics.Blit(source, destination);
        }
        else
        {
            CheckResolution(out _);
            DispatchWithSource(ref source, ref destination);
        }
    }

接着我们继续完善checkresolution和dispatchwithsource函数。

如果没有设置texsize那么就执行createtextures函数设置纹理大小

    protected void CheckResolution(out bool resChange )
    {
        resChange = false;

        if (texSize.x != thisCamera.pixelWidth || texSize.y != thisCamera.pixelHeight)
        {
            resChange = true;
            CreateTextures();
        }
    }

首先将源纹理传递到shader,然后给shader分配线程组,然后将shader处理后的纹理传递到destination

    protected virtual void DispatchWithSource(ref RenderTexture source, ref RenderTexture destination)
    {
        Graphics.Blit(source, renderedSource);
        shader.Dispatch(kernelHandle, groupSize.x, groupSize.y, 1);
        Graphics.Blit(output, destination);
    }

接着我们书写一个简单的后处理示例

我们只是在代码中将原图像的颜色乘上一个shade调整图像的亮度

void Highlight(uint3 id : SV_DispatchThreadID)
{
    float4 srcColor = source[id.xy];
    float4 color   =srcColor*shade;
    output[id.xy] = color;
}

效果展示:

接着我们想要让角色周围高亮显示,但是其它地方仍然是变暗一些。

首先在cpu获取角色的位置并且转换到屏幕坐标,然后传递给shader。

 protected override void OnRenderImage(RenderTexture source, RenderTexture destination)
    {
        if (!init || shader == null)
        {
            Graphics.Blit(source, destination);
        }
        else
        {
            if (trackedObject && thisCamera)
            {
                Vector3 pos = thisCamera.WorldToScreenPoint(trackedObject.position);//将世界坐标转换为屏幕坐标
                center.x = pos.x;
                center.y = pos.y;
                shader.SetVector("center", center);
            }
            bool resChange =false;
            CheckResolution(out _);
            if (resChange) SetProperties();
            DispatchWithSource(ref source, ref destination);
        }
    }

在shader中检测像素是否在角色周围,然后根据和角色的距离对颜色进行插值。如果距离大于半径完全是变暗的颜色,小于半径就是高亮显示。

float inCircle( float2 pt, float2 center, float radius, float edgeWidth ){
    float len = length(pt - center);
    return 1.0 - smoothstep(radius-edgeWidth, radius, len);
}

[numthreads(8, 8, 1)]
void Highlight(uint3 id : SV_DispatchThreadID)
{
    float4 srcColor = source[id.xy];
    float4 shadedSrcColor   =srcColor*shade;
    float4 highlight = inCircle((float2)id.xy,center.xy,radius,edgeWidth);
    float4 color =lerp(shadedSrcColor,srcColor,highlight);
    output[id.xy] = color;
}

效果:

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

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

相关文章

水滴型粉碎机:轻松粉碎辣椒,小型粉碎设备之选

水滴型粉碎机有效优化了物料流动路径&#xff0c;减少了物料在粉碎过程中的阻力与死角&#xff0c;从而大幅提升了粉碎效率与均匀度。同时&#xff0c;不一样的结构还增强了设备的耐磨性和稳定性&#xff0c;延长了使用寿命&#xff0c;降低了维护成本。 粉碎机采用的粉碎技术…

【C++ 第二十章】模拟实现 shared_ptr(可以拷贝的智能指针)

本文主要讲解如果简单模拟实现库中的 shared_ptr 而不会过多的对库中的 shared_ptr 讲解 1. 初始版本 智能指针的基本框架 namespace my {template<class T>class shared_ptr{public:shared_ptr(T* ptr nullptr):_ptr(ptr){}~shared_ptr() {delete _ptr;_ptr nullptr…

信息加解密技术

一.信息加解密技术介绍 信息加解密技术是保护数据安全、防止未授权访问的重要手段。该技术主要利用数学或物理方法&#xff0c;对电子信息在传输过程和存储体中进行保护&#xff0c;确保数据的机密性、完整性和可用性。以下是对信息加解密技术的详细解析&#xff1a; 加密技术的…

三百六十行,行行用AI,AI警官助理:让文书工作不再是负担

“ 当警察在紧张的执法现场&#xff0c;AI工具能够自动转录执法记录仪中的音频&#xff0c;迅速生成警务报告&#xff0c;成为警官们的得力助手&#xff0c;极大地提高了工作效率。 ” AI警官助理&#xff1a;警务工作的革命 最近&#xff0c;一款人工智能工具在警务领域引…

C/C++ 中的算术运算及其陷阱(详解,举例分析)

在C/C编程中&#xff0c;算术运算是非常基础且常用的操作。然而&#xff0c;这些看似简单的运算背后却隐藏着一些潜在的陷阱&#xff0c;如果不加以注意&#xff0c;可能会导致程序出现难以预料的错误。本文将探讨C/C中常见的算术运算及其潜在的陷阱&#xff0c;并通过实例进行…

「Python程序设计」模块式编程:函数

​小时候&#xff0c;我们都或多或少的玩过一些积木玩具。通过把动物&#xff0c;或者是人物的各个组成部分&#xff0c;一小块&#xff0c;一小块地搭建起来&#xff0c;最终&#xff0c;就组成了我们最终想要的形状。这有点类似于乐高积木&#xff0c;通过把固定的块状物&…

Android Launcher3

一、定义与功能 Android Launcher是Android操作系统中的一个重要组件&#xff0c;它负责管理和呈现用户界面&#xff0c;包括桌面、应用程序抽屉和部件。Launcher不仅为用户提供了一个启动应用程序的入口&#xff0c;还允许用户自定义手机的主屏幕、图标、小部件布局以及一些基…

家里有宠物应该用哪款宠物空气净化器?希喂、美的真实测评

养了猫之后&#xff0c;从此我的生活开始有颜色&#xff0c;终于有声音了&#xff0c;每天下班回家终于不是直接就躺在沙发上然后洗洗就睡&#xff0c;现在有猫咪陪着我一起玩&#xff0c;甚至还会和它聊聊天&#xff0c;家里我走到哪它就跟到哪&#xff0c;身后多了一个小跟屁…

智能手机、汽车新应用,星纪魅族幸运星号”卫星即将发射

朋友们&#xff01;你想象过我们的智能手机和汽车能与卫星直接通信吗&#xff1f; 这听起来像是科幻小说里的情节&#xff0c;但很快&#xff0c;这将成为现实&#xff01;星纪魅族科技最近宣布了一个振奋人心的消息——他们将与时空道宇合作发射“星纪魅族幸运星号”卫星。这…

专业软件测试服务机构分享:小程序测试步骤和作用

在数字经济飞速发展的今天&#xff0c;小程序因其轻量、便捷的特点受到了广泛关注。作为技术服务的重要组成部分&#xff0c;软件测试成为确保小程序质量的关键环节。 一、小程序测试的定义   小程序测试是指对小程序进行系统性验证和验证的过程&#xff0c;旨在检查其功能、…

身份证实名认证-实名认证API接口文档

1、接口介绍及适用范围 身份证实名认证是指通过验证个人身份证信息的真实性&#xff0c;来确认用户身份的一种安全验证方式。这种认证方式广泛应用于各种需要身份验证的场合&#xff0c;如金融交易、社交媒体注册、网络游戏登录、电子商务平台购物等。 2、接口地址 输入姓名和…

ElasticSearch-集群读写

ES跨集群搜索&#xff08;CCS&#xff09;分片的设计和管理 算分不准 dfs_query_then_fetch如何设计分片数 ES底层读写工作原理 ES写入数据的过程ES读取数据的过程写数据底层原理 提升集群的读写性能 提升集群读取性能提升集群写入性能 ES跨集群搜索&#xff08;CCS&#xff0…

git管理历险记

本篇文章主要是记录一下公司内git管理策略的变更&#xff0c;又如何因地制宜的磨合出适合团队的方法论&#xff0c;以便未来的职业生涯遇到类似的问题可以稍微触类旁通下。 传统git策略 dev -> test -> pre -> main 这也是比较经典的一个环境对应一个分支&#xff…

[pytorch] --- pytorch基础之模型验证套路

利用已经训练好的模型&#xff0c;拿出训练集中的部分数据进行测试 下面给出完整的示例代码&#xff1a; # -*- coding: utf-8 -*- # 作者&#xff1a;小土堆 # 公众号&#xff1a;土堆碎念 import torch import torchvision from PIL import Image from torch import nnimage…

游戏行业社招上岸指南

鉴于游戏行业的蓬勃发展&#xff0c;游戏领域的各大头部企业每年仍然有大量用人需求。即将到来的“金九银十”可谓是招聘者与应聘者的双向奔赴。 然而除了校招之外&#xff0c;社招同样是秋招中不可忽视的组成部分。因此&#xff0c;这份社招求职指南也终于千呼万唤始出来&…

FPGA第 9 篇,Verilog 中的关键字和基数

前言 在 Verilog 中&#xff0c;关键字&#xff08;Keywords&#xff09;和基数&#xff08;Radix&#xff09;是语言的重要组成部分&#xff0c;它们有助于描述和定义硬件设计。上期分享了 Verilog 的基本使用&#xff0c;以及数据类型、逻辑值和算数运算符的简单应用&#x…

服务器安装pytorch-阿里云-centos7

原文阅读&#xff1a;【巨人肩膀社区专栏分享】服务器安装pytorch-阿里云-centos7 1、创建一个虚拟环境 conda create -n pytorch python3.10 安装成功&#xff1a; &#xfeff; &#xfeff;&#xfeff; 但是使用上面的命令会失败&#xff08;疑问&#xff1f;&#xf…

Apache Guacamole 安装及配置VNC远程桌面控制

文章目录 官网简介支持多种协议无插件浏览器访问配置和管理应用场景 Podman 部署 Apache Guacamole拉取 docker 镜像docker-compose.yml部署 PostgreSQL生成 initdb.sql 脚本部署 guacamole Guacamole 基本用法配置 VNC 连接 Mac 电脑开启自带的 VNC 服务 官网 https://guacam…

编程式路由跳转

点击左侧的导航栏&#xff0c;会跳转到相应的页面。可以在导航栏上定义一个点击事件&#xff0c;在vue-router中解构useRouter,把useRouter赋给router,使用***router.push()***就可以实现编程式路由跳转。 路由跳转有:to,push,replace push模式在浏览器上有历史记录&#xff…

【华为】测试工程师面试题汇总,你可知道华为的高薪技术岗有多香~

华为一直是求职者重点投递的热门企业&#xff0c;面对丰厚的薪资福利&#xff0c;无数985、211的学子挤破脑袋都想占据一席之地。 华为2021年发放工资、薪金及其他福利方面的费用达1371亿元人民币&#xff0c;按华为19.5万员工计算&#xff0c;华为员工人均年薪为70.3万&#…