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.hqwc.cn/news/110267.html

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

相关文章

MQ的初步了解

目录 什么是MQ&#xff1f; 为什么要用MQ&#xff08;MQ的优点&#xff09;&#xff1f; MQ的缺点 常用的MQ产品 MQ使用中的常见问题 什么是MQ&#xff1f; 【1】MQ&#xff1a;MessageQueue&#xff0c;消息队列。 队列&#xff0c;是一种FIFO 先进先出的数据结构。消息由…

基于SpringBoot的驾校管理系统

基于SpringBootVue的驾校管理系统、前后端分离 开发语言&#xff1a;Java数据库&#xff1a;MySQL技术&#xff1a;SpringBoot、Vue、Mybaits Plus、ELementUI工具&#xff1a;IDEA/Ecilpse、Navicat、Maven 【主要功能】 角色&#xff1a;管理员、用户、教练 管理员&#x…

Python 可迭代对象、迭代器、生成器

可迭代对象 定义 在Python的任意对象中&#xff0c;只要它定义了可以返回一个迭代器的 __iter__ 魔法方法&#xff0c;或者定义了可以支持下标索引的 __getitem__ 方法&#xff0c;那么它就是一个可迭代对象&#xff0c;通俗的说就是可以通过 for 循环遍历了。Python 原生的列…

【图论】有向图的强连通分量

算法提高课笔记 文章目录 理论基础SCC板子 例题受欢迎的牛题意思路代码 学校网络题意思路代码 最大半连通子图题意思路代码 银河题意思路代码 理论基础 什么是连通分量&#xff1f; 对于一个有向图&#xff0c;分量中任意两点u&#xff0c;v&#xff0c;必然可以从u走到v&am…

结构体成绩排序

任务描述 本关任务&#xff1a;有n个学生的信息(包括学号&#xff0c;姓名&#xff0c;成绩)&#xff0c;要求按照成绩的高低顺序输出学生的信息。 相关知识 参考结构体第1关相关知识 编程要求 在右侧编辑器Begin-End处补充代码&#xff0c;要求按照成绩的高低顺序输出学生…

【深度学习】 Python 和 NumPy 系列教程(廿七):Matplotlib详解:3、多子图和布局:散点矩阵图(Scatter Matrix Plot)

目录 一、前言 二、实验环境 三、Matplotlib详解 1、2d绘图类型 2、3d绘图类型 3、多子图和布局 1. subplot()函数 2. subplots()函数 3. 散点矩阵图&#xff08;Scatter Matrix Plot&#xff09; 一、前言 Python是一种高级编程语言&#xff0c;由Guido van Rossum于…

视屏点播项目

项目背景 大家应该在电脑上刷过视频吧,这个项目就是模拟一下我们刷视频的整个流程,我们要做的是一个类似B站的网页,这里面包含视频的上传修改和观看以及删除,注意我这个是一个简易版本的,在后面我会做一个升级,增加其他的功能. 基本原理 下面我们说一下我们项目的基本原理.我…

如何根据性能需求进行场景设计?

场景设计一 探索 测试环境 客户端: win10 这里可以用linux,但没用,因为想直观查看结果。 被测环境:linux X86 4核CPU16G内存 被测接口:登录接口,没有做数据驱动。 在测试执行前,先使用influxSQL把influxdb的数据清理一下,以防影响结果查看。 有这么一个需求,要求系…

Android 12 源码分析 —— 应用层 五(SystemUI的StatusBar类的启动过程和三个窗口的创建)

Android 12 源码分析 —— 应用层 五&#xff08;SystemUI的StatusBar类的启动过程和三个窗口的创建&#xff09; 在前面的文章中&#xff0c;我们介绍了SystemUI App的基本布局和基本概念。接下来&#xff0c;我们进入SystemUI应用的各个UI是如何被加入屏幕的。那么我们就先从…

SOLIDWORKS Composer反转关键帧实现产品安装过程

SOLIDWORKS Composer 是一款被用来制作交互式产品说明书的工具&#xff0c;可以帮助我们对产品设定精确的机构动画&#xff0c;并能根据材质生成一定细节的渲染图像。 今天我们主要向大家讲解的是&#xff0c;利用SOLIDWORKS Composer关键帧反转实现产品动态的安装。 一般情况下…

微信小程序通过 wxministore 实现类似于vuex的全局装填数据管理

首先 我们打开终端 引入依赖 npm install wxministore --save然后 如果你是新版开发者工具 就 npm i构建一下 如果你是 老版本的 微信开发者工具 就打开右上角详情 选择本地管理 勾选 使用 npm 模块 然后 在根目录下创建一个 store.js 当然建在哪是你自己决定的 反正 后面能…

密集人头检测数据集汇总和格式转换

1、VSCrowd 2022年9月新出的数据集,数据集链接:https://github.com/HopLee6/VSCrowd-Dataset 网盘地址:链接:https://pan.baidu.com/s/17VARxt59y7GnUHIskEGzKw?pwd=m9qo 提取码:m9qo 数据格式: FrameID HeadID x1 y1 x2 y2 p1 p2 HeadID x1 y1 x2 y2 p1 p2 … Fram…