【Unity】RenderFeature应用(简单场景扫描效果)

【Unity】RenderFeature应用(简单场景扫描效果)

RenderFeature 是一个用于渲染图形的概念,通常在图形引擎或游戏引擎中使用。它是一个模块化的组件,负责处理特定的渲染功能,例如阴影、光照、粒子效果等。

点击地面生成一个不断扩展的圆光效果,用于实现一些画面的特效

实现效果

一、实现方法

1.要求和原理

案例是基于unity urp渲染管线制作,使用了RenderFeature后处理效果。

基本原理一句话,通过相机深度图重建像素的世界空间位置,空间坐标和点击点的坐标进行距离运算画出圆。

2.实现步骤

1)创建UniversalRenderPipelineAsset

​ 在编写RenderFeature前需要创建UniversalRenderPipelineAsset

​ Create→Randering→URPAsset(with Universal Render)

​ 创建后会同时生成UniversalRenderPipelineAsset和UniversalRenderData

​ 动态设置当前UniversalRenderPipelineAsset的方法(也可以手动设置)

   //使用的UniversalRenderPipelineAsset
    public UniversalRenderPipelineAsset UniversalRenderPipelineAsset;
    void Start()
    {
        //分别在Graphics和 Quality里设置成使用的UniversalRenderPipelineAsset
        GraphicsSettings.renderPipelineAsset = UniversalRenderPipelineAsset;
        QualitySettings.renderPipeline = UniversalRenderPipelineAsset;
    }

2)编写RenderFeature

​ 创建RenderFeature,具体介绍可以参见【Unity】RenderFeature笔记

​ Create→Randering→RenderFeature

​ 下面是通用的shader后处理方法,不同的是参数内容和方法

using UnityEngine;
using UnityEngine.Rendering;
using UnityEngine.Rendering.Universal;

public class ScanRenderPassFeature : ScriptableRendererFeature
{
    class CustomRenderPass : ScriptableRenderPass
    {
        public Material _Material;
        public Vector4 _Pos;//点击点
        public Color _Color;//线颜色
        public float _Interval;//线间距
        public float _Strength;//强度范围

        public override void Execute(ScriptableRenderContext context, ref RenderingData renderingData)
        {
           // Matrix4x4 frustumCorners = GetFrustumCornersRay();
            CommandBuffer cmd = CommandBufferPool.Get("ScanRender");
            _Material.SetVector("_CentorPoint", _Pos);
            _Material.SetColor("_Color", _Color);
            _Material.SetFloat("_Interval", _Interval);
            _Material.SetFloat("_Strength", _Strength);
            cmd.Blit(colorAttachment, RenderTargetHandle.CameraTarget.Identifier(), _Material);
            //执行CommandBuffer
            context.ExecuteCommandBuffer(cmd);
            //回收CommandBuffer
            CommandBufferPool.Release(cmd);
        }
    }

    CustomRenderPass m_ScriptablePass;
    public Shader ScanShader;
    public Vector4 Pos;
    public Color Color;
    public float Interval;//间距
    public float Strength;//强度
    /// <inheritdoc/>
    public override void Create()
    {
        m_ScriptablePass = new CustomRenderPass();
        m_ScriptablePass._Material = new Material(ScanShader);
        m_ScriptablePass._Pos = Pos;
        m_ScriptablePass._Color = Color;
        m_ScriptablePass._Interval = Interval;
        m_ScriptablePass._Strength = Strength;
        // Configures where the render pass should be injected.
        m_ScriptablePass.renderPassEvent = RenderPassEvent.AfterRendering;
    }
    public void SetParam()
    {
        m_ScriptablePass._Pos = Pos;
        m_ScriptablePass._Strength = Strength;
    }
    public override void AddRenderPasses(ScriptableRenderer renderer, ref RenderingData renderingData)
    {
        renderer.EnqueuePass(m_ScriptablePass);
    }
}

3)编写shader

​ shader要实现的是两个功能,一是深度图重建像素的世界空间位置,再是根据空间位置画出扩展圆

​ 重建像素的世界空间位置可以参照官方的案例

​ 从深度纹理重建像素的世界空间位置 |URP |7.7.1 (unity3d.com)

​ 核心方法:

​ ComputeWorldSpacePosition:是一个用于计算物体在世界空间中位置的函数。它通常用于计算游戏中的物体 在世界坐标系中的位置。

​ SampleSceneDepth:用于获取深度图像。它主要用于实现一些基本的深度相关功能,比如观察场景中物体深 度信息、计算物体之间的距离等。

​ 下面结合官方的方法进行修改

Shader "Unlit/ScanShaderURP"
{
    Properties
    {
        _CentorPoint("CentrePoint",Vector) = (0, 0, 0, 0)
        _Color("color",Color) = (1,1,1,1)   //颜色
    }
    SubShader
    {
        Tags { "RenderType"="Opaque" }
        LOD 100

        Pass
        {
            HLSLPROGRAM
            #pragma vertex vert
            #pragma fragment frag
            #include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/DeclareDepthTexture.hlsl"
          
           struct Attributes
            {
            float4 positionOS   : POSITION;
        };

        struct Varyings
        {
            float4 positionHCS  : SV_POSITION;
        };

            float4x4 _FrustumCornersRay;
            float  _Interval;//间距
            float _Strength;//强度
            sampler2D _CameraColorTexture;
            float4 _CentorPoint;
            float4 _Color;
            Varyings vert(Attributes IN)
            {
                Varyings OUT;
                OUT.positionHCS = TransformObjectToHClip(IN.positionOS.xyz);
                return OUT;
            }
            half4 frag(Varyings IN) : SV_Target
            {
                 //uv变换
                float2x2 muls = float2x2(-1, 0, 0, 1);
                float2 centerUV = float2(1, 0);
                float2 UV =1-( mul(( IN.positionHCS.xy / _ScaledScreenParams.xy), muls)+centerUV);
                //获取深度图
#if UNITY_REVERSED_Z
                real depth = SampleSceneDepth(UV);
#else
                real depth = lerp(UNITY_NEAR_CLIP_VALUE, 1, SampleSceneDepth(UV));
#endif
                //获取世界坐标位置
                float3 worldPos = ComputeWorldSpacePosition(UV, depth, UNITY_MATRIX_I_VP);
                half4 col2 = tex2D(_CameraColorTexture, UV);
                float lerpValue = 0;
                //对截面外的空间进行屏蔽
                if (depth < _ProjectionParams.z - 1) {
                    float Mul = distance(_CentorPoint.xyz, worldPos.xyz);
                    //change控制圈的距离
                    float change = _Strength;
                //Mul的值是一定大于0的
                //第一个smoothstep小于change的值裁剪为0,大于_Interval + change的为1
                //第二个smoothstep大于_Interval + change的为1,小于的为0
                //两smoothstep相减得到0 + change和 _Interval + change距离间0到1的变化,其余为0
                    float lerp1 = smoothstep(0 + change, _Interval + change, Mul);
                    float lerp2 = smoothstep(_Interval + change, _Interval + change, Mul);
                    float dis = lerp1 - lerp2;
                    lerpValue = dis;
                }
                half4 myCol = lerp(col2, _Color, lerpValue);
                return myCol;
            }
                ENDHLSL
        }
    }
}

4)控制方法


using System.Linq;
using UnityEngine;
using UnityEngine.Rendering.Universal;

public class ScanControl : MonoBehaviour
{
    public UniversalRendererData renderData;
    ScanRenderPassFeature custom;
    private void Start()
    {
      custom = renderData.rendererFeatures.OfType<ScanRenderPassFeature>().FirstOrDefault();
    }
    private void Update()
    {
        if (Input.GetMouseButtonDown(1))
        {
            Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);
            RaycastHit hit;
            if (Physics.Raycast(ray, out hit))
            {
                Vector3 vector = hit.point;
                Vector4 vector4 = new Vector4(vector.x, vector.y, vector.z, 1);
                custom.Pos = vector4;
                custom.Strength = 0;
            }
        }
    }
    private void LateUpdate()
    {
        custom.Strength += Time.deltaTime*10;
        custom.SetParam();
    }
}

3.在built-in里的实现方法

shader

Shader "Unlit/ScanShaderBuiltIn"
{
    Properties
    {

        _MainTex("Base (RGB)", 2D) = "white" {} // 主纹理
        _CentorPoint("CentrePoint",Vector) = (0, 0, 0, 0)
        _Color("color",Color) = (1,1,1,1)   //颜色,一般用fixed4
        _InverseZ("InverseZ", Float) = -1 
    }
    SubShader
    {
        Tags { "RenderType"="Opaque" }
        LOD 100

        Pass
        {
            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag
            #include "UnityCG.cginc"

            struct appdata
            {
                float4 vertex : POSITION;
                float2 uv : TEXCOORD0;
            };

            struct v2f
            {
                float2 uv : TEXCOORD0;
                float4 pos : SV_POSITION;
                float3 viewVec :TEXCOORD1;
            };
            sampler2D _MainTex; // 主纹理
            float _Interval;//间距
            float _Strength;//强度
            float _InverseZ;
            sampler2D _CameraColorTexture;
            sampler2D _CameraDepthTexture;
            float4 _CentorPoint;
            fixed4 _Color;
            v2f vert (appdata v)
            {
                v2f o;
                o.uv = v.uv;
                o.pos = UnityObjectToClipPos(v.vertex); //MVP变换
                float4 screenPos = ComputeScreenPos(o.pos); // 计算“齐次空间”下的屏幕坐标
               // float4 ndcPos = (screenPos / screenPos.w) * 2 - 1; //屏幕坐标--->ndc坐标变换公式
               // float4 ndcPos = o.pos / o.pos.w; //手动进行透视除法
                float3 ndcPos = float3(o.uv.xy * 2.0 - 1.0, 1); //直接把uv映射到ndc坐标
                float far = _ProjectionParams.z; //获取投影信息的z值,代表远平面距离
                float3 clipVec = float3(ndcPos.x, ndcPos.y, ndcPos.z * _InverseZ) * far; //裁切空间下的视锥顶点坐标
                o.viewVec = mul(unity_CameraInvProjection, clipVec.xyzz).xyz; //观察空间下的视锥向量
                return o;
            }

            fixed4 frag (v2f i) : SV_Target
            {
                fixed4 col2 = tex2D(_MainTex, i.uv);
           //   fixed4 col2 = tex2D(_CameraColorTexture, i.uv);
                float depth = SAMPLE_DEPTH_TEXTURE(_CameraDepthTexture,i.uv);//采样深度图
                depth = Linear01Depth(depth); //转换为线性深度
                float3 viewPos = i.viewVec * depth; //获取实际的观察空间坐标(插值后)
                float3  worldPos = mul(unity_CameraToWorld, float4(viewPos,1)).xyz; //观察空间-->世界空间坐标
                float factor = 0;
                if (depth < _ProjectionParams.z - 1) {
                    float Mul = distance(_CentorPoint.xyz, worldPos.xyz);
                    float change = _Strength;
                    //Mul的值是一定大于0的
                   //第一个smoothstep小于change的值裁剪为0,大于_Interval + change的为1
                   //第二个smoothstep大于_Interval + change的为1,小于的为0
                   //两smoothstep相减得到0 + change和 _Interval + change距离间0到1的变化,其余为0
                    float lerp1 = smoothstep(0 + change, _Interval + change, Mul);
                    float lerp2 = smoothstep(_Interval + change, _Interval + change, Mul);
                    float dis = lerp1 - lerp2;
                    float lerpDis = smoothstep(0.99, 1, dis);
                    factor = dis;
                }
                fixed4 myCol = lerp(col2, _Color, factor);
                return myCol;
         
            }
            ENDCG
        }
    }
}

控制脚本

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

public class ScanManager : MonoBehaviour
{
    [SerializeField]
    private bool enableWave = false; // 是否开启扫描特效
    [SerializeField]
    private Shader scanShader;
    private Material material = null; // 材质
     Vector4 _Pos=Vector4.zero;
    public Color _Color;
     float _Interval=1;//间距
     float _Strength=0;//强度
    // Start is called before the first frame update
    void Start()
    {
        material = new Material(scanShader);
    }

    // Update is called once per frame
    void Update()
    {
        if (Input.GetMouseButtonDown(1))
        {
            Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);
            RaycastHit hit;
            if (Physics.Raycast(ray, out hit))
            {
                Vector3 vector = hit.point;
                Vector4 vector4 = new Vector4(vector.x, vector.y, vector.z, 1);
                Debug.Log(vector4);
                _Pos = vector4;
                _Strength = 0;
                enableWave = true;
            }
        }
    }

    private void OnRenderImage(RenderTexture src, RenderTexture dest)
    {
     
        if (enableWave)
        {
            _Strength += Time.deltaTime * 10;
            material.SetVector("_CentorPoint", _Pos);
            material.SetColor("_Color", _Color);
            material.SetFloat("_Interval", _Interval);
            material.SetFloat("_Strength", _Strength);
            Graphics.Blit(src, dest, material);
        }
        else
        {
            Graphics.Blit(src, dest);
        }
    }


}

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【网络】序列化反序列化

序列化反序列化 一、序列化反序列化1、概念2、序列化作用3、序列化框架的选择 二、Json1、介绍2、简单使用 一、序列化反序列化 1、概念 在前文《网络编程套接字》中&#xff0c;我们实现了服务器与客户端之间的字符串通信&#xff0c;这是非常简单的通信&#xff0c;在实际使…

p5.js 到底怎么设置背景图?

本文简介 点赞 关注 收藏 学会了 在 《p5.js 光速入门》 里我们学过加载图片元素&#xff0c;学过过背景色的用法&#xff0c;但当时没提到背景图要怎么使用。 本文就把背景图这部分内容补充完整&#xff0c;并且会提到在 p5.js 里使用背景图的一些注意点。 背景图的用法…

pgsql 分组查询,每组取10条

需求&#xff1a; 按照表的字段分组&#xff0c;然后每组取10条结果&#xff0c;返回即可 sql 如下&#xff1a; SELECT* FROM (SELECT chk_id,feature_id,task_id, ROW_NUMBER () OVER (PARTITION BY chk_id ORDER BY chk_id) AS row_num FROM ics_check_report WHERE task…

中微爱芯74逻辑兼容替代TI/ON/NXP工规品质型号全

这里写自定义目录标题 工业级型号全产品线概述![在这里插入图片描述](https://img-blog.csdnimg.cn/097ef810b2234f07b0c0c1e962a73761.png)批量应用行业头部客户兼容替代封装对照逻辑参数对比电平转换系列型号对照HC/HCT 系列型号对照AHC/AHCT 系列型号对照LV/LVC 系列型号对照…

我是如何快速从python小白达到20k?

前言 首先说一下我自己的情况&#xff0c;我之前是学JAVA的&#xff0c;JAVA亡了只好转行python 很多新手就在好奇自己明明都认认真真的学习了python&#xff0c;但就是感觉很杂很乱&#xff0c;按照我这个流程&#xff0c;至少可以省一大半时间&#xff0c;完整的知识体系很重…

数据可视化报表分享:区域管理驾驶舱

在零售数据分析中&#xff0c;区域管理驾驶舱报表是用来分析企业运营数据&#xff0c;以制定销售策略和提高利润。因此这张报表需要整合大量数据&#xff0c;数据整合、分析、指标计算的工作量极大&#xff0c;在讲究高效率、高度及时性的大数据时代&#xff0c;BI数据可视化分…

Vue 3.3.6 发布,得益于WeakMap,它更快了

性能改进和DOM节点的附加属性的类型检查使新的Vue值得更新。Vue团队确实做了很多工作。实际上&#xff0c;他们在同一天发布了两个子版本。Vue 3.3.5 和 3.3.6 都在2023年10月20日发布。 WeakMaps 其中一个得到改进的是在可能的情况下从 Maps 和 Sets 转移到WeakMaps 和WeakSet…

centos服务器搭建安装Gitlab教程使用教程

1、更新服务器&#xff1a; sudo yum update -y && sudo yum upgrade -y 2、下载Gitlab的RPM包 https://packages.gitlab.com/gitlab/gitlab-cece表示开源el表示centos 选64位el8对应CentOS8 本教程以centos8为例&#xff0c;在服务器中&#xff0c;下载centos8的…

计算机网络【CN】TCP报文段格式【20B】

序号&#xff1a;本报文段所发送的数据的第一个字节的序号确认号&#xff1a;期望收到对方下一个报文段的第一个数据字节的序号。 重要控制位&#xff1a; 紧急位URG&#xff1a;URG1时&#xff0c;标明此报文段中有紧急数据&#xff0c;是高优先级的数据&#xff0c;应尽快传送…

MediaPlayer

1、概念 MediaPlayer是Android原生的多媒体播放器&#xff0c;可以用它来实现本地或者在线音视频的播放。 2、MediaPlayer的状态 下面的图是官方给出的状态转换图&#xff0c;也可易理解为MediaPlayer的生命周期。 椭圆形&#xff1a;表示MediaPlayer的状态&#xff1b;弧形…

Python环境下LaTeX数学公式转图像方案调研与探讨

目录 引言方案一&#xff1a;基于LaTeX环境方案二&#xff1a;基于KaTeX(推荐) 方案三&#xff1a;基于Matplotlib写在最后 引言 近来&#xff0c;涉及到一些公式识别的项目&#xff0c;输入是公式的图像&#xff0c;输出是LaTeX格式的数学公式字符串。 这类项目一般都采用深…

基于Pytorch的驾驶员分心行为实时检测

本文使用深度学习和Pytorch(PyTorch 2.0.1\Torchvision 0.15.2)实时检测驾驶员的分心行为,并附录完整代码。 检测分心驾驶是现代汽车中最重要的功能之一。无论是自动驾驶汽车还是其它高端汽车,都配备了驾驶员监控系统,以持续跟踪驾驶员的行为。这对确保驾驶员保持目光在道路…

前端技术知识(含八股)总结 - 持续更新中

前端技术知识&#xff08;含八股&#xff09;总结 - 持续更新中 参考文献1.HTML和CSS1.1 语义化标签1.2 CSS 选择器及优先级 / position 定位 / box-sizing 属性 / transition / 继承属性&#xff08;如字体文字类的属性大部分有继承&#xff09;/ 行内元素和块级元素 / html的…

【git】git使用教程

1、版本管理工具 如果有一个软件能记录我们对文档的所有修改&#xff0c;所有版本&#xff0c;这类软件我们一般叫做版本控制工具。 特性“ 能够记录历史版本&#xff0c;回退历史版本团队开发&#xff0c;方便代码合并 2、版本管理工具介绍 svn、git svn是集中式版本控制…

音视频开发(一)ffmpeg 简单学习

前言 简单音视频处理。 学习自&#xff1a; 小破站FFmpeg最强教学丨入门FFmpeg看这一篇就够了丨从入门到放弃系列_哔哩哔哩_bilibili 01 下载、配置_哔哩哔哩_bilibili 基础知识 音视频处理基本都是&#xff1a;采样-处理得到帧队列-编码得到包队列-封装得到文件。 视频…

视频分辨率/帧率/码率选择参考

1. 视频码率与分辨率的参考表 1080&#xff0a;720的分辨率&#xff0c;用5000K左右&#xff1b; 720&#xff0a;576的分辨率&#xff0c;用3500K左右&#xff1b; 640&#xff0a;480的分辨率&#xff0c;用1500K左右。 2. 计算公式 基本算法&#xff1a;码率&#xff08;kb…

selenium 根据【关键词】获取知网文献信息

哈喽大家好&#xff0c;我是咸鱼 之前咸鱼写过几篇关于知网爬虫的文章&#xff0c;后台反响都很不错。虽然但是&#xff0c;咸鱼还是忍不住想诉苦一下 有些小伙伴文章甚至代码看都没看完&#xff0c;就问我 ”为什么只能爬这么多条文献信息&#xff1f;“&#xff08;看过代码…

SpringMVC 资源状态转移RESTful

文章目录 1、RESTful简介a>资源b>资源的表述c>状态转移 2、RESTful的实现HiddenHttpMethodFilterRESTful案例 1、RESTful简介 REST&#xff1a;Representational State Transfer&#xff0c;表现层资源状态转移。 a>资源 资源是一种看待服务器的方式&#xff0c…

【面试题08.06.汉诺塔问题】

目录 一、题目描述二、算法原理三、代码实现 一、题目描述 二、算法原理 三、代码实现 class Solution { public:void hanota(vector<int>& A, vector<int>& B, vector<int>& C) {int nA.size();_hanota(n,A,B,C);}void _hanota(int n,vector&l…