Unity3D URP 仿蜘蛛侠风格化BloomAO

Unity3D URP 仿蜘蛛侠风格化Bloom&AO

  • Bloom
    • Bloom效果流程:
    • 制作控制面板VolumeComponent.CS
    • Custom Renderer Feather
    • Custom Renderer Pass
      • Bloom Shader
      • Composite Shader
    • 完善Custom Feather
    • 风格化AO
  • 总结

本篇文章介绍在URP中如何进行风格化后处理,使用Renderer Feather 和自定义 Render Pass 实现。这种做法比起使用PostProcessing具有很大的自由度,能够自由控制渲染时机,减少束缚。

本教程使用Unity2022.3.5f1 版本。较低版本Shader Graph 没有Full Screen Sample Buffer。

以下两张图是蜘蛛侠动画剧照,高光Bloom部分很多是点阵的方式表现,一些AO使用混合平行斜线来表现。
在这里插入图片描述
在这里插入图片描述

类似的卡通渲染方案也被游戏 HiFi Rush 所使用。
在这里插入图片描述

Bloom

Bloom效果流程:

Composite Shader
Bloom
Texture
Screen

先制作Bloom效果,将Bloom渲染到一张Texture上,再将这个Texture通过我们的风格化Shader最后渲染到屏幕上

原始Bloom基本参照Unity的做法,在Packages/com.unity.render-pipelines.core/Runtime 文件夹中可找到相关代码

制作控制面板VolumeComponent.CS

  1. 直接复制Unity Bloom需要的控制参数。
  2. 添加我们风格化点阵需要的控制参数。
[VolumeComponentMenuForRenderPipeline("CustomBloomEffect", typeof(UniversalRenderPipeline))]
public class CustomBloomEffectComponent : VolumeComponent, IPostProcessComponent
{//bloom settings copy from Unity default Bloom[Header("Bloom Settings")]public FloatParameter threshold = new FloatParameter(0.9f,true);public FloatParameter intensity = new FloatParameter(1,true);public ClampedFloatParameter scatter = new ClampedFloatParameter(0.7f,0,1,true);public IntParameter clamp = new IntParameter(65472,true);public ClampedIntParameter maxIterations = new ClampedIntParameter(6,0,10);public NoInterpColorParameter tint = new NoInterpColorParameter(Color.white);//Custom Bloom Dots[Header("Dots")] public IntParameter dotsDensity = new IntParameter(10,true);public ClampedFloatParameter dotsCutoff = new ClampedFloatParameter(0.4f,0,1, true);public Vector2Parameter scrollDirection = new Vector2Parameter(new Vector2());[Header("AOLines")]public ClampedFloatParameter linesWidth = new ClampedFloatParameter(0.001f,0.001f,0.01f, true);public ClampedFloatParameter linesIntensity = new ClampedFloatParameter(0.05f,0,0.05f, true);public ColorParameter linesColor = new ColorParameter(Color.black, true, true, true);public FloatParameter linesAngle = new FloatParameter(30f, true);public bool IsActive(){return true;}public bool IsTileCompatible(){return false;}
}
  1. 将这个脚本挂载到场景中,我们就得到了一个和Unity原生很相识的一个控制面板,并且有新增的Dots控制功能:
    在这里插入图片描述

Custom Renderer Feather

参照Unity自带的Renderer Feather 我们可仿写一个我们自己的Renderer Feather
Unity自带Renderer Feather 目录:
在这里插入图片描述

Custom Renderer Pass

先创建一个简单的自定义Pass,这是渲染Pass,在FrameDebugger中这些根节点都是一个Pass,如图:
在这里插入图片描述
最简代码如下:

[System.Serializable]
public class CustomPostProcessPass : ScriptableRenderPass{public override void Execute(ScriptableRenderContext context,ref RenderingData renderingData)}}
}

然后我们再创建一个Custom Renderer Feather
代码:

[System.Serializable]
public class CustomPostProcessRendererFeature : ScriptableRendererFeature{private CustomPostProcessPass m_customPass;public override void AddRenderPasses(ScriptableRenderer renderer,ref RenderingData renderingData){renderer.EnqueuePass(m_customPass);}public override void Create(m_customPass = new CustomPostProcessPass()}
}

有了这两个后,我们就能在Renderer Data 面板中添加这个新Feather了
在这里插入图片描述

Bloom Shader

这个为了方便直接复制Unity自带的Bloom。地址:Packages/com.unity.render-pipelines.universal/Shaders/PostProcessing/Bloom.shader

Composite Shader

  1. 使用Shader Graph 制作用于风格化Bloom后的Texture。创建一个FullscreenShaderGraph(Unity 2022以上)
    在这里插入图片描述
  2. 创建SampleTexture2D 节点,并且修改名称,注意Reference名称,我们需要通过这个名称向shader传入bloom texture
    在这里插入图片描述
  3. 使用Voronoi Node输 设置AngleOffset为0, 使用Screen Position 作为UV 得到一组排列整齐的圆点格子,创建Density属性,用于控制格子密度(大小)
    在这里插入图片描述
  4. 再通过一个Comparision Node 这样得到1,0分明的圆点,并创建Cutoff属性进行圆点占据格子比例大小控制
    在这里插入图片描述
  5. 使用URP Sample Buffer(这个就是当前屏幕渲染图像Screen Texture) 和点阵相加。
    在这里插入图片描述
  6. 完整的shader graph:
    在这里插入图片描述

完善Custom Feather

这个主要参考Unity URP的Bloom PostProcession写法。
CustomPostProcessRenderFeature 完整代码:

public class CustomPostProcessRenderFeature : ScriptableRendererFeature
{[SerializeField]private Shader m_bloomShader;[SerializeField]private Shader m_compositeShader;private Material m_bloomMaterial;private Material m_compositeMaterial;private CustomPostProcessPass m_customPass;public override void Create(){m_bloomMaterial = CoreUtils.CreateEngineMaterial(m_bloomShader);m_compositeMaterial = CoreUtils.CreateEngineMaterial(m_compositeShader);m_customPass = new CustomPostProcessPass(m_bloomMaterial, m_compositeMaterial);}public override void AddRenderPasses(ScriptableRenderer renderer, ref RenderingData renderingData){renderer.EnqueuePass(m_customPass);}public override void SetupRenderPasses(ScriptableRenderer renderer, in RenderingData renderingData){if (renderingData.cameraData.cameraType == CameraType.Game){m_customPass.ConfigureInput(ScriptableRenderPassInput.Depth);m_customPass.ConfigureInput(ScriptableRenderPassInput.Color);m_customPass.SetTarget(renderer.cameraColorTargetHandle, renderer.cameraDepthTargetHandle);}}protected override void Dispose(bool disposing){CoreUtils.Destroy(m_bloomMaterial);CoreUtils.Destroy(m_compositeMaterial);}
}

CustomPostProcessingPass 完整代码:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Experimental.Rendering;
using UnityEngine.Rendering;
using UnityEngine.Rendering.Universal;
using UnityEngine.Rendering.Universal.Internal;public class CustomPostProcessPass : ScriptableRenderPass
{private Material m_bloomMaterial;private Material m_compositeMaterial;//RTHandles 是一种特殊RenderTexture,它可以在运行时动态调整大小,而不是在编辑器中预先分配固定大小的RenderTexture。private RTHandle m_CameraColorTarget;private RTHandle m_CameraDepthTarget;const int k_MaxPyramidSize = 16;private int[] _BloomMipUp;private int[] _BloomMipDown;private RTHandle[] m_BloomMipUp;private RTHandle[] m_BloomMipDown;private GraphicsFormat hdrFormat;private CustomBloomEffectComponent m_BloomEffect;private RenderTextureDescriptor m_Descriptor;private static readonly int ScreenSpaceOcclusionTexture = Shader.PropertyToID("_ScreenSpaceOcclusionTexture");public void SetTarget(RTHandle cameraColorTarget, RTHandle cameraDepthTarget){this.m_CameraColorTarget = cameraColorTarget;this.m_CameraDepthTarget = cameraDepthTarget;}public override void OnCameraSetup(CommandBuffer cmd, ref RenderingData renderingData){m_Descriptor = renderingData.cameraData.cameraTargetDescriptor;}public CustomPostProcessPass(Material bloomMaterial, Material compositeMaterial){this.m_bloomMaterial = bloomMaterial;this.m_compositeMaterial = compositeMaterial;renderPassEvent = RenderPassEvent.BeforeRenderingPostProcessing;_BloomMipUp = new int[k_MaxPyramidSize];_BloomMipDown = new int[k_MaxPyramidSize];m_BloomMipUp = new RTHandle[k_MaxPyramidSize];m_BloomMipDown = new RTHandle[k_MaxPyramidSize];for (int i = 0; i < k_MaxPyramidSize; i++){_BloomMipUp[i] = Shader.PropertyToID("_BloomMipUp" + i);_BloomMipDown[i] = Shader.PropertyToID("_BloomMipDown" + i);m_BloomMipUp[i] = RTHandles.Alloc(_BloomMipUp[i], name: "_BloomMipUp" + i);m_BloomMipDown[i] = RTHandles.Alloc(_BloomMipDown[i], name: "_BloomMipDown" + i);}const FormatUsage usage = FormatUsage.Linear | FormatUsage.Render;if (SystemInfo.IsFormatSupported(GraphicsFormat.B10G11R11_UFloatPack32, usage)) //判断是否支持HDR格式{hdrFormat = GraphicsFormat.B10G11R11_UFloatPack32;}else{hdrFormat = QualitySettings.activeColorSpace == ColorSpace.Linear ? GraphicsFormat.R8G8B8_SRGB : GraphicsFormat.R8G8B8_UNorm;}}public override void Execute(ScriptableRenderContext context, ref RenderingData renderingData){VolumeStack stack = VolumeManager.instance.stack;m_BloomEffect = stack.GetComponent<CustomBloomEffectComponent>();CommandBuffer cmd = CommandBufferPool.Get();//使用ProfilingScope 才能在FrameDebugger中看到using (new ProfilingScope(cmd, new ProfilingSampler("Custom Post Process Effect"))){Texture ssaoTex = Shader.GetGlobalTexture(ScreenSpaceOcclusionTexture);m_compositeMaterial.SetTexture("_SSAOTexture", ssaoTex);//Shader.SetGlobalTexture("_SSAOTexture", ssaoTex);SetupBloom(cmd, m_CameraColorTarget);m_compositeMaterial.SetFloat("_Cutoff", m_BloomEffect.dotsCutoff.value);m_compositeMaterial.SetFloat("_Density", m_BloomEffect.dotsDensity.value);m_compositeMaterial.SetVector("_Direction", m_BloomEffect.scrollDirection.value);m_compositeMaterial.SetFloat("_LineWidth", m_BloomEffect.linesWidth.value);m_compositeMaterial.SetFloat("_LineIntensity", m_BloomEffect.linesIntensity.value);m_compositeMaterial.SetColor("_LineColor", m_BloomEffect.linesColor.value);m_compositeMaterial.SetFloat("_LineAngle", m_BloomEffect.linesAngle.value);Blitter.BlitCameraTexture(cmd, m_CameraColorTarget, m_CameraColorTarget, m_compositeMaterial, 0);}context.ExecuteCommandBuffer(cmd);cmd.Clear();CommandBufferPool.Release(cmd);}private void SetupBloom(CommandBuffer cmd, RTHandle source){// 初始大小减半 降采样int downres = 1;int tw = m_Descriptor.width >> downres;int th = m_Descriptor.height >> downres;//Determine the iteration count based on the size of the pyramidint maxSize = Mathf.Max(tw, th);int iterations = Mathf.FloorToInt(Mathf.Log(maxSize,2f) - 1);int mipCount = Mathf.Clamp(iterations,1, m_BloomEffect.maxIterations.value);// Pre-filtering parametersfloat clamp = m_BloomEffect.clamp.value;float threshold = Mathf.GammaToLinearSpace(m_BloomEffect.threshold.value);float thresholdKnee = threshold * 0.5f;// Hardcoded soft knee// Material setupfloat scatter = Mathf.Lerp(0.05f,0.95f,m_BloomEffect.scatter.value);var bloomMaterial = m_bloomMaterial;bloomMaterial.SetVector("_Params",new Vector4(scatter,clamp,threshold,thresholdKnee));//Prefiltervar desc = GetCompatibleDescriptor(tw,th,hdrFormat);for (int i = 0; i < mipCount; i++){RenderingUtils.ReAllocateIfNeeded(ref m_BloomMipUp[i],desc,FilterMode.Bilinear,TextureWrapMode.Clamp,name: m_BloomMipUp[i].name);RenderingUtils.ReAllocateIfNeeded(ref m_BloomMipDown[i], desc, FilterMode.Bilinear, TextureWrapMode.Clamp,name: m_BloomMipDown[i].name);desc.width = Mathf.Max(1, desc.width >> 1);desc.height = Mathf.Max(i, desc.height >> i);}Blitter.BlitCameraTexture(cmd, source, m_BloomMipDown[0], RenderBufferLoadAction.DontCare, RenderBufferStoreAction.Store, bloomMaterial, 0);//Downsamplevar lastdown = m_BloomMipDown[0];for (int i = 0; i < mipCount - 1; i++){//第一个Pass是 2x 降采样 + 9tap高斯模糊//第二个Pass是 使用5tap过滤的9tap高斯模糊 + 双线性过滤 Blitter.BlitCameraTexture(cmd, lastdown, m_BloomMipUp[i], RenderBufferLoadAction.DontCare, RenderBufferStoreAction.Store, bloomMaterial, 1);Blitter.BlitCameraTexture(cmd, m_BloomMipUp[i], m_BloomMipDown[i], RenderBufferLoadAction.DontCare, RenderBufferStoreAction.Store, bloomMaterial, 2);lastdown = m_BloomMipDown[i];}// Upsamplefor (int i = mipCount - 2; i >= 0; i--){var lowMip = (i == mipCount - 2)? m_BloomMipDown[i + 1] : m_BloomMipUp[i + 1];var highMip = m_BloomMipDown[i];var dst = m_BloomMipUp[i];cmd.SetGlobalTexture("_SourceTexLowMip", lowMip);Blitter.BlitCameraTexture(cmd, highMip, dst, RenderBufferLoadAction.DontCare, RenderBufferStoreAction.Store, bloomMaterial, 3);}m_compositeMaterial.SetTexture("_Bloom_Texture", m_BloomMipUp[0]);m_compositeMaterial.SetFloat("_BloomIntensity", m_BloomEffect.intensity.value);cmd.SetGlobalFloat("_BloomIntensity", m_BloomEffect.intensity.value);}private RenderTextureDescriptor GetCompatibleDescriptor(){return GetCompatibleDescriptor(m_Descriptor.width, m_Descriptor.height, m_Descriptor.graphicsFormat);}private RenderTextureDescriptor GetCompatibleDescriptor(int tw, int th, GraphicsFormat graphicsFormat, DepthBits depthBufferBits = DepthBits.None){return GetCompatibleDescriptor(m_Descriptor, tw, th, graphicsFormat, depthBufferBits);}internal static RenderTextureDescriptor GetCompatibleDescriptor(RenderTextureDescriptor desc, int tw, int th, GraphicsFormat format, DepthBits depthBufferBits = DepthBits.None){desc.depthBufferBits = (int)depthBufferBits;desc.width = tw;desc.height = th;desc.graphicsFormat = format;desc.msaaSamples = 1;return desc;}}

在Renderer Data上吧Bloom Shader 和Composite Shader 拖拽进去
在这里插入图片描述
成功运行就能看到结果了:

在这里插入图片描述

风格化AO

要点: 添加Screen Space Ambient Occlusion 然后通过_ScreenSpaceOcclusionTexture 获取AO贴图,再把AO贴图作为Mask,在Mask内画斜线。
在这里插入图片描述

private static readonly int ScreenSpaceOcclusionTexture = Shader.PropertyToID("_ScreenSpaceOcclusionTexture");

可以在Composite Shader一起处理
一种效果如下:
在这里插入图片描述

总结

在实际游戏中,这些效果处理要更加复杂一些,这里给大家开个头,发挥想象把效果做得更出彩吧~

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

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

相关文章

高阶数据结构-----三种平衡树的实现以及原理(未完成)

TreeMap和TreeSet的底层实现原理就是红黑树 一)AVL树: 1)必须是一棵搜索树:前提是二叉树&#xff0c;任取一个节点&#xff0c;它的左孩子的Key小于父亲节点的Key小于右孩子节点的Key&#xff0c;中序遍历是有序的&#xff0c;按照Key的大小进行排列&#xff0c;高度平衡的二叉…

2024字节跳动校招面试真题汇总及其解答(一)

1. 【算法题】重排链表 给定一个单链表 L 的头节点 head ,单链表 L 表示为: L0 → L1 → … → Ln - 1 → Ln请将其重新排列后变为: L0 → Ln → L1 → Ln - 1 → L2 → Ln - 2 → … 不能只是单纯的改变节点内部的值,而是需要实际的进行节点交换。 示例 1: 输入:hea…

SSH是如何配置的

目录 什么是SSH SSH可以做什么其他用途&#xff1f; ssh有几种连接方法吗 我应该用哪种方法连接SSH1或SSH2&#xff1f; 每天都在用SSH你知道SSH的原理吗 开启ssh后telnet会关闭吗 SSH的优缺点 SSH和Telnet之间优缺点的对比 SSH的配置实验 ensp Cisco H3C 1、什么是…

QT—基于http协议的网络文件下载

1.常用到的类 QNetworkAccessManager类用于协调网络操作&#xff0c;负责发送网络请求&#xff0c;创建网络响应 QNetworkReply类表示网络请求的响应。在QNetworkAccessManager发送一个网络请求后创建一个网络响应。它提供了以下信号&#xff1a; finished()&#xff1a;完成…

【八大经典排序算法】:直接插入排序、希尔排序实现 ---> 性能大比拼!!!

【八大经典排序算法】&#xff1a;直接插入排序、希尔排序实现 ---> 性能大比拼&#xff01;&#xff01;&#xff01; 一、 直接插入排序1.1 插入排序原理1.2 代码实现1.3 直接插入排序特点总结 二、希尔排序 ( 缩小增量排序 )2.1 希尔排序原理2.2 代码实现2.3 希尔排序特点…

数据可视化、BI和数字孪生软件:用途和特点对比

在现代企业和科技领域&#xff0c;数据起着至关重要的作用。为了更好地管理和理解数据&#xff0c;不同类型的软件工具应运而生&#xff0c;其中包括数据可视化软件、BI&#xff08;Business Intelligence&#xff09;软件和数字孪生软件。虽然它们都涉及数据&#xff0c;但在功…

文献阅读:Chain-of-Thought Prompting Elicits Reasoning in Large Language Models

文献阅读&#xff1a;Chain-of-Thought Prompting Elicits Reasoning in Large Language Models 1. 文章简介2. 具体方法3. 实验结果 1. 数学推理 1. 实验设计2. 实验结果3. 消解实验4. 鲁棒性考察 2. 常识推理 1. 实验设计2. 实验结果 3. 符号推理 1. 实验设计2. 实验结果 4.…

华为数通方向HCIP-DataCom H12-821题库(单选题:241-260)

第241题 ​​LS Request​​报文不包括以下哪一字段? A、通告路由器(Advertising Router) B、链路状态 ID (Link Srate ID) C、数据库描述序列号(Database Dascription Sequence lumber) D、链路状态类型 Link state type) 答案:C 解析: LS Request 报文中包括以下字段…

协议定制 + Json序列化反序列化

文章目录 协议定制 Json序列化反序列化1. 再谈 "协议"1.1 结构化数据1.2 序列化和反序列化 2. 网络版计算器2.1 服务端2.2 协议定制(1) 网络发送和读取的正确理解(2) 协议定制的问题 2.3 客户端2.4 代码 3. Json实现序列化反序列化3.1 简单介绍3.2 使用 协议定制 J…

【送书活动】揭秘分布式文件系统大规模元数据管理机制——以Alluxio文件系统为例

前言 「作者主页」&#xff1a;雪碧有白泡泡 「个人网站」&#xff1a;雪碧的个人网站 「推荐专栏」&#xff1a; ★java一站式服务 ★ ★ React从入门到精通★ ★前端炫酷代码分享 ★ ★ 从0到英雄&#xff0c;vue成神之路★ ★ uniapp-从构建到提升★ ★ 从0到英雄&#xff…

python调用GPT实现:智能用例生成工具

工具作用&#xff1a; 根据输入的功能点&#xff0c;生成通用测试点 实现步骤 工具实现主要分2个步骤&#xff1a; 1.https请求调用Gpt,将返回响应结果保存为.md文件 2.用python实现 将 .md文件转换成.xmind文件 3.写个简单的前端页面&#xff0c;调用上述步骤接口 详细代…

操作系统强化认识之Shell编程学习与总结

目录 1.Shell的概述 2.Shell脚本入门 3.变量 3.1.系统预定义变量 3.2.自定义变量 3.3.特殊变量 4.运算符 5.条件判断 6.流程控制 6.1.if判断 6.2.case语句 6.3.for循环 6.4.while循环 7.read读取控制台输入 8.函数 8.1.系统函数 8.2.自定义函数 9.正则表示式入…

【C++入门到精通】C++入门 ——搜索二叉树(二叉树进阶)

阅读导航 前言一、搜索二叉树简介1. 概念2. 基本操作⭕搜索操作&#x1f36a;搜索操作基本代码&#xff08;非递归&#xff09; ⭕插入操作&#x1f36a;插入操作基本代码&#xff08;非递归&#xff09; ⭕删除操作&#x1f36a;删除操作基本代码&#xff08;非递归&#xff0…

MySQL无法查看系统默认字符集以及校验规则

show variables like character_set_database; show variables like collation_database;这个错误信息表示MySQL在尝试访问performance_schema.session_variables表时&#xff0c;发现该表不存在。这个问题可能是由于MySQL的版本升级导致的。解决这个问题的一种方法是运行mysql…

论文浅尝 | 训练语言模型遵循人类反馈的指令

笔记整理&#xff1a;吴亦珂&#xff0c;东南大学硕士&#xff0c;研究方向为大语言模型、知识图谱 链接&#xff1a;https://arxiv.org/abs/2203.02155 1. 动机 大型语言模型&#xff08;large language model, LLM&#xff09;可以根据提示完成各种自然语言处理任务。然而&am…

Java JUC 并发编程(笔记)

文章目录 再谈多线程并发与并行顺序执行并发执行并行执行 再谈锁机制重量级锁轻量级锁偏向锁锁消除和锁粗化 JMM内存模型Java内存模型重排序volatile关键字happens-before原则 多线程编程核心锁框架Lock和Condition接口可重入锁公平锁与非公平锁 读写锁锁降级和锁升级 队列同步…

[构建 Vue 组件库] 小尾巴 UI 组件库 —— 横向商品卡片(仿淘宝)

文章归档于&#xff1a;https://www.yuque.com/u27599042/row3c6 组件库地址 npm&#xff1a;https://www.npmjs.com/package/xwb-ui?activeTabreadmegitee&#xff1a;https://gitee.com/tongchaowei/xwb-ui 下载 npm i xwb-ui配置 按需导入 import {组件名 } from xwb-…

【Unity】 2D 游戏 库存模块实现

库存模块主要参考了 youtube 上的视频 BMo 的 Flexible INVENTORY SYSTEM in Unity with Events and Scriptable Objects 和 Simple Inventory UI in Unity With Grid Layouts 这两个视频是一个系列 还是一个视频也是 BMo的 How To INTERACT with Game Objects using UNITY E…

Nginx详解 第五部分:Ngnix反向代理(负载均衡 动静分离 缓存 透传 )

Part 5 一、正向代理与反向代理1.1 正向代理简介1.2 反向代理简介 二、配置反向代理2.1 反向代理配置参数2.1.1 proxy_pass2.1.2 其余参数 2.2 配置实例:反向代理单台web服务器2.3 代理转发 三、反向代理实现动静分离四、缓存功能五、反向代理客户端的IP透传5.1 原理概述5.2 一…

谁在为网络安全制造标尺?

“我们想帮助企业往后退一步&#xff0c;去全局的看一下自己的安全能力建设水平如何&#xff0c;以及在当下的阶段最应该做的安全建设是什么&#xff1f; ” 度量&#xff0c;对应的是更清晰的认知。而对企业安全而言&#xff0c;这种认知&#xff0c;也更在成为一把新的标尺…