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

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

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

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

实现效果

一、实现方法

1.要求和原理

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

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

2.实现步骤

1)创建UniversalRenderPipelineAsset

​ 在编写RenderFeature前需要创建UniversalRenderPipelineAsset

​ Create→Randering→URPAsset(with Universal Render)

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

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

   //使用的UniversalRenderPipelineAssetpublic UniversalRenderPipelineAsset UniversalRenderPipelineAsset;void Start(){//分别在Graphics和 Quality里设置成使用的UniversalRenderPipelineAssetGraphicsSettings.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);//执行CommandBuffercontext.ExecuteCommandBuffer(cmd);//回收CommandBufferCommandBufferPool.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 100Pass{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_Zreal depth = SampleSceneDepth(UV);
#elsereal 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的变化,其余为0float 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 100Pass{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的变化,其余为0float 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 updatevoid Start(){material = new Material(scanShader);}// Update is called once per framevoid 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.mzph.cn/news/122804.shtml

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

相关文章

【考研数学】数学“背诵”手册 | 需要记忆且容易遗忘的知识点

文章目录 引言一、高数常见泰勒展开 n n n 阶导数公式多元微分函数连续、可微、连续可偏导之间的关系多元函数极值无条件极值条件极值 三角函数的积分性质华里士公式&#xff08; “点火”公式 &#xff09;特殊性质 原函数与被积函数的奇偶性结论球坐标变换公式 二、线代施密特…

CondaError: Downloaded bytes did not match Content-Length

问题 使用anaconda下载包文件时&#xff0c;出现了CondaError: Downloaded bytes did not match Content-Length的错误 CondaError: Downloaded bytes did not match Content-Lengthurl: https://conda.anaconda.org/pytorch/win-64/pytorch-2.1.0-py3.11_cuda11.8_cudnn8_0.…

npm : 无法加载文件 C:\Program Files\nodejs\npm.ps1,因为在此系统上禁止运行脚本。

1、在vscode终端执行 get-ExecutionPolicy &#xff0c;显示Restricted&#xff0c;说明状态是禁止的。 2、更改状态: set-ExecutionPolicy RemoteSigned 出现需要管理员权限提示&#xff0c;可选择执行 Set-ExecutionPolicy -Scope CurrentUser 出现的ExecutionPolicy参数后输…

H5游戏源码分享-色块选择游戏

H5游戏源码分享-色块选择游戏 玩到后面色块越来越小&#xff0c;越来越难找出 <!DOCTYPE html><html><head><meta http-equiv"Content-Type" content"text/html; charsetUTF-8"><meta charset"UTF-8"><meta na…

bitlocker 加密锁定的固态硬盘,更换到别的电脑上,怎么把原密钥写进新电脑TPM芯片内,开启无需手动填密钥

环境: Win11 专业版 联想E14笔记本 512G ssd 问题描述: 一台笔记本因充电故障,需要拿去维修,不想重装系统,将bitlocker 加密锁定的固态硬盘拆下更换到别的笔记本电脑上,现在开机要手动填密钥,怎么把原密钥写进新电脑TPM芯片内,开启无需手动填密钥和之前那台电脑一…

C的自定义类型

目录 1. 结构体 1.1. 结构体类型的声明 1.1.1. 特殊声明 2. 结构的自引用 3. 结构体变量的定义和初始化 4. 结构体内存对齐 4.1. 结构体内存对齐 4.2. 修改默认对齐数 5. 结构体传参 6. 结构体实现位段&#xff08;位段的填充&可移植性&#xff09; 6.1. 什么是位…

Glide原理

本文基于Carson整理 1.简介 相比其他几种图片加载框架&#xff0c;Glide性能最好。这得益于其高效的图片缓存策略 其还有多样化的媒体格式加载&#xff1a;如GIF、Video&#xff0c;对于商城首页需展示丰富样式、信息的页面需求来说&#xff0c;也是必不可少的。 2.加载原理…

nodejs+vue+elementui+express酒店管理系统

登录&#xff1a;运行系统后&#xff0c;进行登录&#xff0c;可使用本系统。 客房预定&#xff1a;此界面先通过条件查询客房信息&#xff0c;然后进行客房预定。对预定的客房还可以取消和支付操作。 信息查询&#xff1a;可查询所有的公告信息&#xff0c;点击公告名称&#…

[量化投资-学习笔记003]Python+TDengine从零开始搭建量化分析平台-Grafana画K线图

在前面两个笔记&#xff1a; PythonTDengine从零开始搭建量化分析平台-数据存储 PythonTDengine从零开始搭建量化分析平台-MA均线的多种实现方式 中有提到使用 Grafana 画图&#xff0c;不过画的都是均线。除了均线&#xff0c;Grafana 非常人性的提供了 K线图模块 搭配 TDeng…

基于群居蜘蛛算法的无人机航迹规划

基于群居蜘蛛算法的无人机航迹规划 文章目录 基于群居蜘蛛算法的无人机航迹规划1.群居蜘蛛搜索算法2.无人机飞行环境建模3.无人机航迹规划建模4.实验结果4.1地图创建4.2 航迹规划 5.参考文献6.Matlab代码 摘要&#xff1a;本文主要介绍利用群居蜘蛛算法来优化无人机航迹规划。 …

Photoshop(PS)安装教程(2023最新最详细图文教程)

目录 一.简介 二.安装步骤 软件&#xff1a;PS版本&#xff1a;2023语言&#xff1a;简体中文大小&#xff1a;3.20G系统要求&#xff1a;Win10&#xff08;1903&#xff09;及以上版本&#xff0c;64位操作系统硬件要求&#xff1a;CPU2.0GHz 内存8G(或更高&#xff0c;不支持…

5G 3GPP全球频谱介绍

所谓 “频谱”&#xff0c;是指特定类型的无线通信所在的射频范围。不同的无线技术使用不同的频谱&#xff0c;因此互不干扰。由于一项技术的频谱是有限的&#xff0c;因此频谱空间存在大量竞争&#xff0c;并且人们也在不断开发和增强全新的、高效率的频谱使用方式。 介绍5G …

Vue echarts 折线图 背景颜色渐变 (两种实现方式)

需求 实现方式 两种方法 方法一&#xff1a;color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [{}&#xff0c;{}&#xff0c;{}]) 方法二&#xff1a;避开new echarts&#xff0c;color: {x: 0, y: 0, x2: 0, y2: 1,colorStops: [{}&#xff0c;{}&#xff0c;{}]} …

Linux(Centos7)操作记录

1、nginx -t #Nginx配置文件检查 上述截图代表检查没问题 上述截图检查配置文件配置错误&#xff0c;并提示错误文件位置 2、systemctl restart nginx #重启Nginx 重启Nginx失败 3、systemctl status nginx.service #查看Nginx服务状态 80端口被占导致服务启动失败 4、n…

k8s 金丝雀发布与声明式管理

Deployment控制器支持自定义控制更新过程中的滚动节奏&#xff0c;如“暂停(pause)”或“继续(resume)”更新操作。比如等待第一批新的Pod资源创建完成后立即暂停更新过程&#xff0c;此时&#xff0c;仅存在一部分新版本的应用&#xff0c;主体部分还是旧的版本。然后&#xf…

基于水循环算法的无人机航迹规划-附代码

基于水循环算法的无人机航迹规划 文章目录 基于水循环算法的无人机航迹规划1.水循环搜索算法2.无人机飞行环境建模3.无人机航迹规划建模4.实验结果4.1地图创建4.2 航迹规划 5.参考文献6.Matlab代码 摘要&#xff1a;本文主要介绍利用水循环算法来优化无人机航迹规划。 1.水循环…

【赠书活动】从瀑布模式到水母模式:ChatGPT如何赋能软件研发全流程

&#x1f449;博__主&#x1f448;&#xff1a;米码收割机 &#x1f449;技__能&#x1f448;&#xff1a;C/Python语言 &#x1f449;公众号&#x1f448;&#xff1a;测试开发自动化【获取源码商业合作】 &#x1f449;荣__誉&#x1f448;&#xff1a;阿里云博客专家博主、5…

YOLOv5算法 | 万字长文带你深度解析yolov5s.yaml配置文件

前言&#xff1a;Hello大家好&#xff0c;我是小哥谈。配置文件yolov5s.yaml在YOLOv5模型训练过程中发挥着至关重要的作用&#xff0c;属于初学者必知必会的文件&#xff01;在YOLOv5-6.0版本源码中&#xff0c;配置了5种不同大小的网络模型&#xff0c;分别是YOLOv5n、YOLOv5s…

使用GoQuery实现头条新闻采集

概述 在本文中&#xff0c;我们将介绍如何使用Go语言和GoQuery库实现一个简单的爬虫程序&#xff0c;用于抓取头条新闻的网页内容。我们还将使用爬虫代理服务&#xff0c;提高爬虫程序的性能和安全性。我们将使用多线程技术&#xff0c;提高采集效率。最后&#xff0c;我们将展…

Linux中shell脚本中的运算

目录 一、运算符号 二、运算指令 三、练习 一、运算符号 加法-减法*乘法/除法%除法后的余数**乘方自加一--自减一 <小于<小于等于>大于>大于等于等于ji&#xff0c;jji*jj*i/jj/i%jj%i 二、运算指令 (()) ##((a12)) let ##let a12 expr ##expr 1 2 …