当前位置: 首页> 文旅> 旅游 > 广州番禺最新疫情_服务公司logo_二十个优化_百度关键词排名爬虫

广州番禺最新疫情_服务公司logo_二十个优化_百度关键词排名爬虫

时间:2025/7/14 8:48:32来源:https://blog.csdn.net/m0_68267247/article/details/143731575 浏览次数:0次
广州番禺最新疫情_服务公司logo_二十个优化_百度关键词排名爬虫

目录

 

前言:

一、前期了解

ScriptableRendererFeature

ScriptableRenderPass

VolumeComponent

二、创建系统

准备:

实操:

1.CustomPostProcessRenderFeature

2.CustomPostProcessVolume

3.CustomPostProcessRenderPass

三、完整代码 

CustomPostProcessRenderFeature

CustomPostProcessVolume

CustomPostProcessRenderPass

四、案例

五、一些问题 


 

前言:

在游戏制作过程中,后处理效果的增加能够给我们的画面带来许多眼前一亮的效果,画面的美化。而在URP中不同于BuildIn管线,URP需要自定义RenderFeature来实现一个个后处理,但是能不能像URP内置的后处理一样只有一个RenderPass呢?如下图:

6e85840624e74391b4940c65dc9c8170.png

答案当然是肯定的!

这是我学习参考的文章:Unity URP14.0 自定义后处理系统 - 知乎

上面的文章是基础,当然里面的介绍对于没有接触过RenderFeature这些有点不友好(当初我学习的时候也是一脸没看懂,笑~【有一个网页的文章找不到了,那篇其实比较完全,但是没关系,下面我会介绍我使用系统所遇到的所有问题和解决办法】)。

小破站的视频是我依据上面的文章所写的工具脚本(是早期版本啦,下面的文章是更全面,考虑情况更多的系统,如果是学习的话可以看看小破站链接里的代码,如果是学习系统如何创建的,请跳过这些)。

 

一、前期了解

RenderFeature代码的创立可以用Unity自带的创建方法,如下图:

1c8a2a5ec5f34689864751f7026cd7eb.gif

f65bca5c98c44b3eaafb84071043157d.png

打开之后我们可以看到CustomRenderPassFeature继承ScriptableRendererFeature,其中又定义了一个继承ScriptableRenderPassCustomRenderPass类。

 

ScriptableRendererFeature

330f0f9a4b0d43919a8430e3c0d580c6.png

ScriptableRendererFeature能够将我们定义的ScriptableRenderPass插入到CameraRender序列里,让Camera进行渲染。

 

ScriptableRenderPass

f736521fd1ac4999aad9cef3607f385e.png

ScriptableRenderPass定义了我们该如何渲染此通道(也就是我们核心处理后处理逻辑的地方)。

相关的我就不多说了,里面的函数方法周期我也不再介绍,大家可以去看官方文档。

 

VolumeComponent

2ca8b57543774b46ba92b38ab5e60e5b.png

相信使用URP内置的后处理效果时,都会使用Volume组件

6f5833e46f434b31a7b821853fbce5ad.png

这是为了方便我们进行效果调节的组件,当然Volume也可以有其它的效果,我们接下来的系统也会借助这个组件功能来调节我们的后效,具体的Volume可以参考官方文档,我就不再介绍了。

 

二、创建系统

准备:

首先我们先思考一下我们的系统需要实现什么功能。

1.在RenderSetting添加自定义的后效RenderFeature,此Feature只能添加一次

2.RenderFeature插入我们的自定义后效RenderPass,这个RenderPass会遍历我们所有的自定义的后效,根据后效的启用与否,来决定是否在render序列里进行添加。

3.自定义Volume组件,可以在Volume下调节效果。

4.优化:每个效果尽力只调用一次渲染命令。

 

实操:

首先创建3个脚本,分别是CustomPostProcessRenderFeatureCustomPostProcessRenderPassCustomPostProcessVolume

66dbbd5e34bb4fe89bc6a4751580c70e.png

根据命名就知道它们各自的分工是什么。

 

1.CustomPostProcessRenderFeature

using UnityEngine;
using UnityEngine.Rendering.Universal;[DisallowMultipleRendererFeature]
public class CustomPostProcessRenderFeature : ScriptableRendererFeature
{CustomPostProcessRenderPass m_renderPass;[SerializeField] private RenderPassEvent m_passRenderEvent = RenderPassEvent.BeforeRenderingPostProcessing;public override void Create(){m_renderPass = new CustomPostProcessRenderPass();m_renderPass.renderPassEvent = m_passRenderEvent;}public override void AddRenderPasses(ScriptableRenderer renderer, ref RenderingData renderingData){if (renderingData.cameraData.cameraType == CameraType.Game && renderingData.cameraData.postProcessEnabled){renderer.EnqueuePass(m_renderPass);}}
}

89e7d2807ae9425b93529222c8f61e14.png

可以看到CustomPostProcessRenderFeature继承ScriptableRendererFeature

在类的上方有一个特性[DisallowMultipleRendererFeature],旨在CustomPostProcessRenderFeature只能添加一次。

 

Create方法里我们初始化RenderPass,并且设置了RenderPass插入的渲染事件7404dcdee9bd4a0e83556e4a66647a5a.png

而在AddRenderPasses方法里我们将RenderPass进行正式的添加到Camera的render序列里。

8c3d8f710a434ef687dfcb5c49b87363.png

 

2.CustomPostProcessVolume

using System;
using UnityEngine;
using UnityEngine.Rendering;
using UnityEngine.Rendering.Universal;
public abstract class CustomPostProcessVolume : VolumeComponent, IPostProcessComponent
{private Material material;public abstract string shaderPath { get; }public Material m_material{get{if (Shader.Find(shaderPath) == null){
#if UNITY_EDITORDebug.LogError($"Shader at path '{shaderPath}' doesn't exist or there are some errors in the Shader ! ");
#endifreturn null;}else{if (material == null)material = CoreUtils.CreateEngineMaterial(shaderPath);return material;}}}public virtual int orderInPass => 0;public abstract bool IsActive();public virtual bool IsTileCompatible() => false;public abstract void SetMaterialProperty(RenderingData renderingData, RenderTexture src, RenderTexture des, int passNum = 0);protected virtual void Dispose(bool disposing) { }public void Dispose(){CoreUtils.Destroy(material);Dispose(true);GC.SuppressFinalize(this);}protected override void OnDestroy(){Dispose();base.OnDestroy();}}

这里面的代码比较多,我们一个一个来解释。

366c643dee2e420e9d5a32250eed84b4.png

首先类变成了抽象类,目的是为了下面的抽象方法,因为继承我们自定义的Volume基类都必须实现一些方法。然后这个基类继承了VolumeComponentIPostProcessComponent,这两个都是必要的,可以看看官方的Bloom:

23cbc9f3906f4a97808c4ab3ba660611.png

 

5ac24b1c09e44dc186a6bfbbc479c83b.png

接着定义一个material变量,这个变量用来存储我们的后效材质球。

下面是一个抽象的string类型shaderPath,这个是shader的路径,我们会根据路径来找到Shader。

m_material属性就定义了material变量的创建与获取。

 

26ab91258ae542e4ba40dc732fd0055d.png

orderInPass定义了此效果在渲染上的先后顺序,比如A效果为0,B效果为0,则它们的顺序可能不会固定,但是A效果为0,B效果为1,则A效果会比B效果先渲染,就会出现B效果是在A效果上层叠加的。

 

IsActiveIsTileCompatibleIPostProcessComponent的抽象方法的实现,但是我将它们修改了一下,将IsActive变为抽象方法是因为继承的子类必须实现此方法,后续会根据IsActive的真否来进行批次优化。IsTileCompatible基本没啥用,默认false就可以,子类也不一定必须实现所以改为virtual。

SetMaterialProperty是核心抽象方法,我们material材质的属性变量改变就会调用它,所有子类都必须实现它。

其中有4个参数,这些参数的作用如下:

RenderingData renderingData

这个参数是将Camera的renderingData数据传递进来,我们可以操作很多,比如获取摄像机的位置,大小,摄像机的参数等等。

 

RenderTexture src

这个参数是渲染后效的基础图,有时候你会需要它。

RenderTexture des:

这个参数是渲染后效的目标图,有时候你会需要它。

int passNum

这个参数默认为0,当你一个效果用到多Pass或者是一个shader有多个Pass时,你需要多个Pass操作的时候它会很有用。

 

9fa6a6fd203e491a8d245caf47cd3e7e.png

两个Dispose意义不一样,第一个带参数的Dispose是在子类可以实现的,用于其它临时资源的释放(如在子类声明临时RenderTexture),第二个则是基类里的方法,此方法是释放掉我们创建的材质球资源内存。

 

887966904ec44303b394b551c8efb938.png

Destroy方法里调用释放资源

01f6f9d3a9574cbab4e5da0c9c97e8b5.png

 

3.CustomPostProcessRenderPass

using System.Linq;
using System.Collections.Generic;
using UnityEngine.Rendering;
using UnityEngine.Rendering.Universal;public class CustomPostProcessRenderPass : ScriptableRenderPass
{RTHandle mTemp0;RTHandle mTemp1;List<CustomPostProcessVolume> active_components = new List<CustomPostProcessVolume>();List<CustomPostProcessVolume> components;public override void OnCameraSetup(CommandBuffer cmd, ref RenderingData renderingData){// 从VolumeManager获取所有自定义的RC_VolumeComponent,并根据他们的orderInPass排序存储列表var stack = VolumeManager.instance.stack;components = VolumeManager.instance.baseComponentTypeArray.Where(t => t.IsSubclassOf(typeof(CustomPostProcessVolume)) && stack.GetComponent(t) != null).Select(t => stack.GetComponent(t) as CustomPostProcessVolume).OrderBy(t => t.orderInPass).ToList();if (components == null)return;if (components.Count == 0)return;active_components.Clear();foreach (var item in components){if (item.IsActive() && item.m_material != null)active_components.Add(item);}if (active_components.Count == 0)return;var descriptor = renderingData.cameraData.cameraTargetDescriptor;descriptor.msaaSamples = 1;descriptor.depthBufferBits = 0;RenderingUtils.ReAllocateIfNeeded(ref mTemp0, descriptor, name: "mTempRT0");if (active_components.Count == 1){if (active_components[0].m_material.shader.passCount > 1)RenderingUtils.ReAllocateIfNeeded(ref mTemp1, descriptor, name: "mTempRT1");}else if (active_components.Count > 1)RenderingUtils.ReAllocateIfNeeded(ref mTemp1, descriptor, name: "mTempRT1");}public override void Execute(ScriptableRenderContext context, ref RenderingData renderingData){if (active_components != null && active_components.Count > 0){var cmd = CommandBufferPool.Get("CustomPostProcessRenderPass");context.ExecuteCommandBuffer(cmd);cmd.Clear();for (int i = 0; i < active_components.Count; i++){if (active_components[i].m_material == null)continue;if (i == 0){var passCount = active_components[0].m_material.shader.passCount;if (passCount == 1){using (new ProfilingScope(cmd, new ProfilingSampler(active_components[0].ToString()))){active_components[0].SetMaterialProperty(renderingData, renderingData.cameraData.renderer.cameraColorTargetHandle, mTemp0, 0);cmd.Blit(renderingData.cameraData.renderer.cameraColorTargetHandle, mTemp0, active_components[0].m_material, 0);}}else{for (int passNum = 0; passNum < passCount; passNum++){using (new ProfilingScope(cmd, new ProfilingSampler(active_components[0].ToString()))){if (passNum == 0){active_components[0].SetMaterialProperty(renderingData, renderingData.cameraData.renderer.cameraColorTargetHandle, mTemp0, passNum);cmd.Blit(renderingData.cameraData.renderer.cameraColorTargetHandle, mTemp0, active_components[0].m_material, passNum);}else{active_components[0].SetMaterialProperty(renderingData, mTemp0, mTemp1, passNum);cmd.Blit(mTemp0, mTemp1, active_components[0].m_material, passNum);CoreUtils.Swap(ref mTemp0, ref mTemp1);}}}}}else{var passCount = active_components[i].m_material.shader.passCount;for (int passNum = 0; passNum < passCount; passNum++){using (new ProfilingScope(cmd, new ProfilingSampler(active_components[i].ToString()))){active_components[i].SetMaterialProperty(renderingData, mTemp0, mTemp1, passNum);cmd.Blit(mTemp0, mTemp1, active_components[i].m_material, passNum);CoreUtils.Swap(ref mTemp0, ref mTemp1);}}}}cmd.Blit(mTemp0, renderingData.cameraData.renderer.cameraColorTargetHandle);context.ExecuteCommandBuffer(cmd);cmd.Clear();CommandBufferPool.Release(cmd);}}public void Dispose(){mTemp0?.Release();mTemp1?.Release();if (components != null){foreach (var item in components){item.Dispose();}components.Clear();}active_components?.Clear();}
}

OK,现在我们一个一个来看。

22d6f1059b6f483097b6254f6c7b784d.png

首先类继承ScriptableRenderPass不用多说。

然后跳过变量我们先来看方法:

8c9efbf4f7fe4fc1a6a1497fcefdc65a.png

OnCameraSetup方法里我们进行初始化

462bb236ad074111a91b16a8d689f4a0.png

我们是根据Volume组件来确定自定义后效的,这就是自定义Volume基类的一个作用,我们通过Linq来查找到继承了CustomPostProcessVolume基类的Volume所有组件,存放在变量components里。

当然如果components为null或者是长度为0,那说明没有自定义后效,那么下面的操作也不用进行了。

 

然后我们先回到变量上:

96cf84b51eb14fca822a5d8b5dcbb264.png

可以看到components存放的是所有的自定义Volume,而active_components自然存放的就是激活的components。

35428229c46b4eeeafc01eeb1396d8a8.png

而这几句就是初始化active_components,判断依据就是volumecomponent是否是激活并且材质球不为null,那么就添加进去。

b4439028f97e4aed94dd10fe44274c57.png

如果最后没有激活的volumecomponent,那么就没必要进行下一步操作了。

 

83b1ff09d66b4ed0942fe0f56213ed13.png

然后是声明临时RT,其变量如下:

009a6799de56433a9e5e5cc78c6297d0.png

为什么声明两个呢?如果你的shader只进行一次pass渲染,那么一个就够了,但是如果是多个,我们可以在两个RT上进行乒乓渲染,这样就可以减少RT的创建。

8ec48f44f1a94b80990c5e1b7799d831.png

这一部分就是声明默认的第一张RT,它的名字是mTempRT0;

469c311791264a729e9f427dd37bfc02.png

然后我们会进行判断,如果激活的volumecomponent只有一个,并且这个后效所使用的shader里面的pass有多个,那么我们就需要再声明一张RT,如果是激活的volumecomponent有多个,那必然是需要两张RT来进行交换渲染的,所以需要声明它。

所谓的乒乓渲染就是:

后效之前图——>mTemp0

mTemp0——>mTemp1

mTemp1——>(交换结果)mTemp0

mTemp0——>mTemp1

mTemp1——>(交换结果)mTemp0

........

最后一步:mTemp0——>后效目标图

 

8dca988585f146ef83d431261576d3e5.png

Execute函数里我们进行渲染逻辑处理 

c915d6114835421d9a98b83076860852.png

0eeddbf8b43c4a3499a4a407e9b1fc77.png

首先我们是根据激活的volumecomponent来添加渲染的,所以要在active_components不为null并且长度不为0的条件下处理逻辑。

 

4f18b5643236483cb582b450a75dbcae.png

这个声明是为了在FrameDebugger里看到我们的自定义后效Pass。

 

2be3020d438e4378925e885362346428.png

然后我们开始遍历激活的volumecomponents。

 

cebcb14836394c5ca84866327b9ff57e.png

再一次进行判断,如果激活的volumecomponent没有材质球则不再继续下面操作

 

2ffe85e5a67b4781a6c604e1a84f4c55.png

在这里我们对active_components第一个元素逻辑单独处理,为什么要单独拿出来呢?因为第一个元素肯定会用到renderingData.cameraData.renderer.cameraColorTargetHandle(也就是后处理之前渲染完的的图),我们需要将它进行渲染到mTempRT0,后面若是有多个pass或者是多个自定义后处理,我们只要进行mTemp0和mTemp1乒乓渲染就可以了。

 

84318332ea134feb84c4fde1d55377c3.png

可以看到我们先获得第一个volumecomponent所使用材质球的shader的pass数量,如果是一个那么只需要直接Blit渲染即可,如果是多个pass,那么我们需要调用循环来处理多个pass的逻辑,第一个pass照常是直接Blit,从第二个pass开始,就是需要将mTemp0渲染到mTemp1,并交换它们的结果,这样就保持了mTemp0始终是最后的渲染效果。

 

b5c5e8dae7b24ac9ba9d2fdadabc4268.png

从第二个active_component开始,都是按照相同的逻辑进行处理

 

经过上面的渲染,我们确保了后效的处理的图片结果保存在mTemp0里。

 

aaec5a9dba924101b99a6bff5b28ab4f.png

最后我们将mTemp0渲染到最终的屏幕图上。

 

3c1233c4bf5e4f11ada3fa9effb54d43.png

在我们自定义的Dispose函数中,我们进行资源的释放。

然后需要在CustomPostProcessRenderFeature调用它。

91b4b7df567f4589acdbb7fc43142f66.png

 

fdb3815481a245da8124338215118166.png

 

三、完整代码 

CustomPostProcessRenderFeature

using UnityEngine;
using UnityEngine.Rendering.Universal;[DisallowMultipleRendererFeature]
public class CustomPostProcessRenderFeature : ScriptableRendererFeature
{CustomPostProcessRenderPass m_renderPass;[SerializeField] private RenderPassEvent m_passRenderEvent = RenderPassEvent.BeforeRenderingPostProcessing;public override void Create(){m_renderPass = new CustomPostProcessRenderPass();m_renderPass.renderPassEvent = m_passRenderEvent;}public override void AddRenderPasses(ScriptableRenderer renderer, ref RenderingData renderingData){if (renderingData.cameraData.cameraType == CameraType.Game && renderingData.cameraData.postProcessEnabled){renderer.EnqueuePass(m_renderPass);}}protected override void Dispose(bool disposing){if (m_renderPass != null){m_renderPass.Dispose();}}
}

CustomPostProcessVolume

using System;
using UnityEngine;
using UnityEngine.Rendering;
using UnityEngine.Rendering.Universal;
public abstract class CustomPostProcessVolume : VolumeComponent, IPostProcessComponent
{private Material material;public abstract string shaderPath { get; }public Material m_material{get{if (Shader.Find(shaderPath) == null){
#if UNITY_EDITORDebug.LogError($"Shader at path '{shaderPath}' doesn't exist or there are some errors in the Shader ! ");
#endifreturn null;}else{if (material == null)material = CoreUtils.CreateEngineMaterial(shaderPath);return material;}}}public virtual int orderInPass => 0;public abstract bool IsActive();public virtual bool IsTileCompatible() => false;public abstract void SetMaterialProperty(RenderingData renderingData, RenderTexture src, RenderTexture des, int passNum = 0);protected virtual void Dispose(bool disposing) { }public void Dispose(){CoreUtils.Destroy(material);Dispose(true);GC.SuppressFinalize(this);}protected override void OnDestroy(){Dispose();base.OnDestroy();}}

CustomPostProcessRenderPass

using System.Linq;
using System.Collections.Generic;
using UnityEngine.Rendering;
using UnityEngine.Rendering.Universal;public class CustomPostProcessRenderPass : ScriptableRenderPass
{RTHandle mTemp0;RTHandle mTemp1;List<CustomPostProcessVolume> active_components = new List<CustomPostProcessVolume>();List<CustomPostProcessVolume> components;public override void OnCameraSetup(CommandBuffer cmd, ref RenderingData renderingData){// 从VolumeManager获取所有自定义的RC_VolumeComponent,并根据他们的orderInPass排序存储列表var stack = VolumeManager.instance.stack;components = VolumeManager.instance.baseComponentTypeArray.Where(t => t.IsSubclassOf(typeof(CustomPostProcessVolume)) && stack.GetComponent(t) != null).Select(t => stack.GetComponent(t) as CustomPostProcessVolume).OrderBy(t => t.orderInPass).ToList();if (components == null)return;if (components.Count == 0)return;active_components.Clear();foreach (var item in components){if (item.IsActive() && item.m_material != null)active_components.Add(item);}if (active_components.Count == 0)return;var descriptor = renderingData.cameraData.cameraTargetDescriptor;descriptor.msaaSamples = 1;descriptor.depthBufferBits = 0;RenderingUtils.ReAllocateIfNeeded(ref mTemp0, descriptor, name: "mTempRT0");if (active_components.Count == 1){if (active_components[0].m_material.shader.passCount > 1)RenderingUtils.ReAllocateIfNeeded(ref mTemp1, descriptor, name: "mTempRT1");}else if (active_components.Count > 1)RenderingUtils.ReAllocateIfNeeded(ref mTemp1, descriptor, name: "mTempRT1");}public override void Execute(ScriptableRenderContext context, ref RenderingData renderingData){if (active_components != null && active_components.Count > 0){var cmd = CommandBufferPool.Get("CustomPostProcessRenderPass");context.ExecuteCommandBuffer(cmd);cmd.Clear();for (int i = 0; i < active_components.Count; i++){if (active_components[i].m_material == null)continue;if (i == 0){var passCount = active_components[0].m_material.shader.passCount;if (passCount == 1){using (new ProfilingScope(cmd, new ProfilingSampler(active_components[0].ToString()))){active_components[0].SetMaterialProperty(renderingData, renderingData.cameraData.renderer.cameraColorTargetHandle, mTemp0, 0);cmd.Blit(renderingData.cameraData.renderer.cameraColorTargetHandle, mTemp0, active_components[0].m_material, 0);}}else{for (int passNum = 0; passNum < passCount; passNum++){using (new ProfilingScope(cmd, new ProfilingSampler(active_components[0].ToString()))){if (passNum == 0){active_components[0].SetMaterialProperty(renderingData, renderingData.cameraData.renderer.cameraColorTargetHandle, mTemp0, passNum);cmd.Blit(renderingData.cameraData.renderer.cameraColorTargetHandle, mTemp0, active_components[0].m_material, passNum);}else{active_components[0].SetMaterialProperty(renderingData, mTemp0, mTemp1, passNum);cmd.Blit(mTemp0, mTemp1, active_components[0].m_material, passNum);CoreUtils.Swap(ref mTemp0, ref mTemp1);}}}}}else{var passCount = active_components[i].m_material.shader.passCount;for (int passNum = 0; passNum < passCount; passNum++){using (new ProfilingScope(cmd, new ProfilingSampler(active_components[i].ToString()))){active_components[i].SetMaterialProperty(renderingData, mTemp0, mTemp1, passNum);cmd.Blit(mTemp0, mTemp1, active_components[i].m_material, passNum);CoreUtils.Swap(ref mTemp0, ref mTemp1);}}}}cmd.Blit(mTemp0, renderingData.cameraData.renderer.cameraColorTargetHandle);context.ExecuteCommandBuffer(cmd);cmd.Clear();CommandBufferPool.Release(cmd);}}public void Dispose(){mTemp0?.Release();mTemp1?.Release();if (components != null){foreach (var item in components){item.Dispose();}components.Clear();}active_components?.Clear();}
}

四、案例

用这个案例正好做一个场景扫描的效果吧(当然是全屏扫描了哈~)

注意:我们采样的是CommandBuff.Blit渲染,此方法会将相机渲染图传递给Shader的_MainTex属性,所有要对相机的渲染图进行后效渲染,必须包含参数_MainTex。

0a669584b0414f8e900f12a3f4c875b5.png

我这里采用的是深度图还原世界坐标,然后使用SphereMask进行alpha区域的计算

Unity深度图重建

Sphere Mask 节点 | Shader Graph | 10.5.0

Shader代码:

Shader "Hidden/BR/PostProcess/BR_ScanScene"
{Properties{_MainTex ("MainTex", 2D) = "white" { }}SubShader{Tags { "RenderType" = "Overlay" "Queue" = "Geometry" "RenderPipeline" = "UniversalPipeline" }LOD 100Pass{HLSLPROGRAM#pragma vertex vert#pragma fragment frag#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Core.hlsl"#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/DeclareDepthTexture.hlsl"TEXTURE2D(_MainTex);SAMPLER(sampler_MainTex);uniform float3 _Center;uniform float _Radius;uniform float _Hardness;uniform float _Range;uniform half4 _BaseColor;struct Attributes{float4 positionOS : POSITION;float2 texcoord : TEXCOORD0;};struct Varyings{float4 positionHS : SV_POSITION;float4 positionSS : TEXCOORD0;float2 uv : TEXCOORD1;};float Unity_SphereMask_float(float3 Position, float3 Center, float Radius, float Hardness){return 1 - saturate((distance(Position, Center) - Radius) / (1 - Hardness));}Varyings vert(Attributes v){Varyings o;o.positionHS = TransformObjectToHClip(v.positionOS.xyz);o.positionSS = ComputeScreenPos(o.positionHS);o.uv = v.texcoord;return o;}half4 frag(Varyings i) : SV_Target{half3 base_map = SAMPLE_TEXTURE2D(_MainTex, sampler_MainTex, i.uv).rgb;float2 screenPos = i.positionSS.xy / i.positionSS.w;#if UNITY_REVERSED_Zreal depth = SampleSceneDepth(screenPos);#elsereal depth = lerp(UNITY_NEAR_CLIP_VALUE, 1, SampleSceneDepth(screenPos));#endiffloat3 worldPos = ComputeWorldSpacePosition(screenPos, depth, UNITY_MATRIX_I_VP);float sphere_gray1 = Unity_SphereMask_float(worldPos, _Center, _Radius, _Hardness);float sphere_gray2 = Unity_SphereMask_float(worldPos, _Center, lerp(0.0, max(_Radius - _Range, 0.0), saturate(ceil(_Range))), _Hardness);float alpha = sphere_gray1 - sphere_gray2;half3 final_Color = lerp(base_map, _BaseColor.rgb, alpha);return half4(final_Color, 1.0);}ENDHLSL}}FallBack "Hidden/Universal Render Pipeline/FallbackError"
}

Volume脚本

using UnityEngine;
using UnityEngine.Rendering;
using UnityEngine.Rendering.Universal;[System.Serializable, VolumeComponentMenuForRenderPipeline("BR/BR_ScanScene", typeof(UniversalRenderPipeline))]public class BR_ScanScene : CustomPostProcessVolume
{public override string shaderPath => "Hidden/BR/PostProcess/BR_ScanScene";public Vector3Parameter center = new Vector3Parameter(Vector3.zero);public FloatParameter radius = new FloatParameter(0f);public FloatParameter range = new FloatParameter(0f);public ClampedFloatParameter hardness = new ClampedFloatParameter(0f, 0f, 0.99f);public ColorParameter baseColor = new ColorParameter(Color.white, true, true, true);public override bool IsActive() => radius.value > 0 && radius.overrideState && hardness.value < 1f;public override void SetMaterialProperty(RenderingData renderingData, RenderTexture src, RenderTexture des, int passNum = 0){m_material.SetVector("_Center", center.value);m_material.SetFloat("_Radius", radius.value);m_material.SetFloat("_Hardness", hardness.value);m_material.SetFloat("_Range", range.value);m_material.SetColor("_BaseColor", baseColor.value);}
}

208705a3b1da4afaa4c03bb370bd64e2.png

上面的标签主要是为了在Volume组件上能够添加。

b8a61d5b6c3644d9b1d5c5bcda947980.png

347f3e32c0be494d8c8f7f672aeb8879.png

下面就是声明在Volume上显示的变量,然后实现isActive函数和SetMaterialProperty函数。

 

效果:

83324823d2e24b328b6e6cb296a5684a.gif

 

五、一些问题 

当使用里系统,在编辑器运行是没有问题的,而打包之后发现一点效果的没有。

这是因为Shader.Find没有引用到Shader,Shader没有被包含,我们需要做的是在ProjectSetting中加上我们的Shader。

83b44f857e1f496fbd5cec2c50862e14.png

如果嫌这种配置太麻烦或是不想修改Unity默认的设置,就可以创建一个自定义的Scriptable脚本引用这些Shader。当然系统对应创建材质球的部分就需要被更改了,看各自需要。

 

 

关键字:广州番禺最新疫情_服务公司logo_二十个优化_百度关键词排名爬虫

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com

责任编辑: