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

news2024/11/18 14:00:14

【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);
        }
    }


}

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

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

相关文章

linux新建账号并配置权限

一、新建用户testuser useradd testuser二、设置新用户的密码为1234ABcd# passwd testuser之后输入两遍1234ABcd#。 三、提升用户testuser权限 这个个人理解是提升到root权限&#xff0c;需要修改一个配置文件。&#xff08;明天老师可能会讲文件读写权限&#xff0c;那就需…

数据分析和互联网医院小程序:提高医疗决策的准确性和效率

互联网医院小程序已经在医疗领域取得了显著的进展&#xff0c;为患者和医疗从业者提供了更便捷和高效的医疗服务。随着数据分析技术的快速发展&#xff0c;互联网医院小程序能够利用大数据来提高医疗决策的准确性和效率。本文将探讨数据分析在互联网医院小程序中的应用&#xf…

UVa1354,ACM/ICPC Tokyo 2005,Mobile Computing(天平难题)

1、题目 2、题意 给出房间的宽度 r r r 和 s s s 个挂坠的重量 w i w_i wi​。设计一个尽量宽&#xff08;但宽度不能超过房间宽度 r r r&#xff09;的天平&#xff0c;挂着所有挂坠。 天平由一些长度为1的木棍组成。木棍的每一端要么挂一个挂坠&#xff0c;要么挂另外一…

Spring体系结构

Spring体系结构 核心容器 核心容器由 spring-core&#xff0c;spring-beans&#xff0c;spring-context&#xff0c;spring-context-support和spring-expression&#xff08;SpEL&#xff0c;Spring 表达式语言&#xff0c;Spring Expression Language&#xff09;等模块组成&…

CMake aux_source_directory 学习

如下&#xff0c;prj是空文件夹&#xff1b; add.h; #include <iostream>using namespace std;int add1(int a, int b); num.h; int num1100; int num2301; add.cpp&#xff1b; #include "add.h"int add1(int i, int j) {return i j; } main.cpp&#x…

GPT做SQL查询引擎的自然语言

目录 面向企业查询的生成式人工智能 步骤1&#xff1a;将示例数据转换为单字符字符串 步骤2&#xff1a;为大型语言模型&#xff08;LM&#xff09;创建提示符 步骤3&#xff1a;将数据发送到OpenAI的API 步骤4&#xff1a;执行GPT返回的SQL代码的结果 步骤5(可选)&#…

SQL-正则表达式和约束

文章目录 主要内容一.正则表达式1.操作1代码如下&#xff08;示例&#xff09;: 2.操作2代码如下&#xff08;示例&#xff09;: 3.操作3代码如下&#xff08;示例&#xff09;: 4.操作4代码如下&#xff08;示例&#xff09;: 二.约束1.主键约束 2.自增长约束3.非空约束4.唯一…

专业135总400+合工大合肥工业大学833信号分析与处理信息通信上岸经验分享

专业135总400合工大合肥工业大学833信号分析与处理信息通信上岸经验分享 基础课经验很多&#xff0c;大同小异&#xff0c;我分享一下自己的833专业课复习经验。 一&#xff1a;用到的书本 1.《信号与系统》&#xff08;第三版&#xff09;郑君里&#xff0c;高等教育出版社…

计算机视觉-光源的目的和作用

光源的目的 机器视觉系统的核心是图像采集和图像处理&#xff0c;而光源则是影响图像水平的重要因素&#xff0c;通过适当的光源照明&#xff0c;使图像中的目标信息与背景信息得到更好的分离&#xff0c;可大大降低图像识别难度&#xff0c;提高系统的精度和可靠性。 对于机器…

【剑指offer|图解|双指针】移除元素 + 合并两个有序数组

&#x1f308;个人主页&#xff1a;聆风吟 &#x1f525;系列专栏&#xff1a;数据结构、算法模板、汇编语言 &#x1f516;少年有梦不应止于心动&#xff0c;更要付诸行动。 文章目录 &#x1f4cb;前言一. ⛳️移除元素二. ⛳️合并两个有序数组&#x1f4dd;全文总结 &#…

实用篇-Ribbon负载均衡

一、负载均衡原理 回想一下上面的 服务发现&#xff0c;order-service微服务向user-service微服务发送请求&#xff0c;但是user-service有两个&#xff0c;也就是开启了两个user-service实例&#xff0c;且端口不同&#xff0c;一个是8081&#xff0c;另一个是8082&#xff0…

【漏洞复现】酒店宽带运营系统RCE

漏洞描述 安美数字 酒店宽带运营系统 server_ping.php 远程命令执行漏洞 免责声明 技术文章仅供参考&#xff0c;任何个人和组织使用网络应当遵守宪法法律&#xff0c;遵守公共秩序&#xff0c;尊重社会公德&#xff0c;不得利用网络从事危害国家安全、荣誉和利益&#xff…

应用案例|基于三维机器视觉的曲轴自动化上下料应用方案

Part.1 项目背景 此案例服务对象为国内某知名大型汽车零部件制造工厂&#xff0c;该工厂有针对曲轴工件的自动化上下料需求。由于之前来料码放不规范&#xff0c;工件无序散乱摆放&#xff0c;上料节拍要求高&#xff0c;该工厂上下料效率极低。 Part.2 传统曲轴上下料存在的缺…

npm更新包时This operation requires a one-time password.

[访问我的npm包](mhfwork/yt-ui - npm) 更新npm包时出现 This operation requires a one-time password.是因为需要认证 解决办法 1. 点击红线处的链接 2. 进入npm官网获取指定秘钥 3. 再次填入 one-time password 即可

大数据架构设计理论与实践

大数据架构设计理论与实践 大数据处理系统概述 传统数据处理系统存在的问题 大数据处理系统面临的挑战 大数据处理系统的属性/特征 典型的大数据架构 Lambda架构 Lambda定义 优缺点 应用场景 Lambda的体系结构( Batch Layer (批处理层)、Speed Layer (加速层)、Serving Lay…

笔记44:Batch_Normlization 过程详解

笔记本地地址&#xff1a;D:\work_file\DeepLearning_Learning\03_个人笔记\2.图像处理任务\BN a a a a a a a a a a a a a a a a a

玩转视图变量,轻松实现动态可视化数据分析

前言 在当今数据驱动的世界中&#xff0c;数据分析已经成为了企业和组织中不可或缺的一部分。传统的静态数据分析方法往往无法满足快速变化的业务需求和实时决策的要求。为了更好地应对这些挑战&#xff0c;观测云的动态可视化数据分析应运而生。 在动态可视化数据分析中&…

【算法】滑动窗口题单——4.不定长滑动窗口(求子数组个数)

文章目录 前言2799. 统计完全子数组的数目解法1——枚举右端点&#xff0c;移动左端点解法2——枚举左端点&#xff0c;扩展右端点 713. 乘积小于 K 的子数组1358. 包含所有三种字符的子字符串数目2302. 统计得分小于 K 的子数组数目2537. 统计好子数组的数目2762. 不间断子数组…

【深度学习】Transformer、GPT、BERT、Seq2Seq什么区别?

请看vcr&#xff1a;https://transformers.run/back/transformer/

♥ uniapp 环境搭建

♥ uniapp 环境搭建 开发uniapp需要用到的工具有两个&#xff1a; 1、用到的平台和地址&#xff1a; 需要了解的几个平台以及地址&#xff1a; &#xff08;1&#xff09;微信公众平台 https://mp.weixin.qq.com/ &#xff08;2&#xff09;微信开发文档 https://develo…