赞
踩
urp管线下实现扫光效果
基本思路,还是根据深度还原世界坐标(以下简称world_pos),根据坐标的xyz判断是否在一些范围内,然后进行基于xyz两个坐标轴进行扫光
这里进行一个扩展,让扫光可以沿着任一方向进行,
就是传入一个旋转变换矩阵,对world_pos进行变换,然后判断aabb盒,这样就可以实现非xyz轴方向的扫光效果
运行效果如下:
可以沿任意方向扫光
代码如下:
- Shader "lsc/screen_scan_shader"
- {
- Properties
- {
- _MainTex("Texture", 2D) = "white" {}
- _scan_brush("Texture", 2D) = "white" {}
- }
- SubShader
- {
- // No culling or depth
- Cull Off ZWrite Off ZTest Always
-
- Pass
- {
- HLSLPROGRAM
- #pragma vertex vert
- #pragma fragment frag
-
- #include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Core.hlsl"
-
- //sampler2D _CameraDepthTexture;
- float4x4 _mtx_view_inv;
- float4x4 _mtx_proj_inv;
- //float4x4 _mtx_clip_to_world;
- TEXTURE2D_X_FLOAT(_CameraDepthTexture);
- SAMPLER(sampler_CameraDepthTexture);
-
-
- //扫光参数
- float4 _scan_color;
- float4 _scan_box_min;
- float4 _scan_box_max;
- float4x4 _scan_box_world_mtx;
-
- TEXTURE2D_X_FLOAT(_scan_brush);
- SAMPLER(sampler_LinearClamp);
-
- struct appdata
- {
- float4 vertex : POSITION;
- float2 uv : TEXCOORD0;
- };
-
- struct v2f
- {
- float2 uv : TEXCOORD0;
- float4 vertex : SV_POSITION;
- float4 screen_space : TEXCOORD1;
- };
-
- float4 cal_world_pos_by_dep(float ndc_dep, float2 screen_space, out float4 view_pos)
- {
- // 取出非线性深度与视深度
- float linearDepthZ = LinearEyeDepth(ndc_dep, _ZBufferParams);
- // 屏幕转ndc
- float4 ndc_pos;
- ndc_pos.xy = screen_space * 2.0 - 1.0;
- ndc_pos.zw = float2(ndc_dep, 1);
- // 添加齐次因子
- ndc_pos = ndc_pos * linearDepthZ;
- // 转成观察与世界坐标
- view_pos = mul(_mtx_proj_inv, ndc_pos);
- float4 world_pos = mul(_mtx_view_inv, float4(view_pos.xyz, 1));
-
- return world_pos;
- }
-
- int is_in_box(float3 pos)
- {
- //todo : need option
- if (pos.x <= _scan_box_max.x &&
- pos.y <= _scan_box_max.y &&
- pos.z <= _scan_box_max.z &&
- pos.x >= _scan_box_min.x &&
- pos.y >= _scan_box_min.y &&
- pos.z >= _scan_box_min.z
- )
- return 1;
-
- return 0;
- }
-
- v2f vert (appdata v)
- {
- v2f o;
-
- o.vertex = TransformObjectToHClip(v.vertex);
- o.uv = v.uv;
-
- // 计算屏幕空间坐标(含齐次因子)
- o.screen_space = ComputeScreenPos(o.vertex);
-
- return o;
- }
-
-
-
- sampler2D _MainTex;
-
- float4 frag (v2f i) : SV_Target
- {
- float4 col = tex2D(_MainTex, i.uv);
-
- // 插值后的屏幕坐标去除齐次因子
- float2 screen_space = i.screen_space.xy / i.screen_space.w;
- // 取出非线性深度
- float org_depth = SAMPLE_TEXTURE2D_X(_CameraDepthTexture, sampler_CameraDepthTexture, screen_space).x;
- // 计算世界坐标
- float4 view_pos;
- float4 world_pos = cal_world_pos_by_dep(org_depth, screen_space, view_pos);
-
- //转换到包围盒的旋转平移空间
- float4 box_space_pos = mul(_scan_box_world_mtx, float4(world_pos.xyz, 1));
- int in_box = is_in_box(box_space_pos.xyz);
-
- float2 brush_uv = float2(
- abs(box_space_pos.x - _scan_box_min.x) / (_scan_box_max.x - _scan_box_min.x),
- abs(box_space_pos.z - _scan_box_min.z) / (_scan_box_max.z - _scan_box_min.z)
- );
-
- // 从纹理中采样渐变效果,或者也可以用xz坐标计算生成简单的渐变效果
- float4 scan_brush = SAMPLE_TEXTURE2D_X(_scan_brush, sampler_LinearClamp, brush_uv).x;
- float scan_scale = scan_brush.r * brush_uv.x * brush_uv.y;
-
- col.xyz = _scan_color.xyz * in_box * scan_scale + col.xyz;
-
-
- //float tmp = world_pos.y;
- //col.xyz = float3(tmp, tmp, tmp);
-
-
- return col;
- }
-
- ENDHLSL
- }
- }
- }
render feature pass c#代码
- using UnityEngine;
- using UnityEngine.Rendering;
- using UnityEngine.Rendering.Universal;
-
- public class ScreenScanRenderPassFeature : ScriptableRendererFeature
- {
- class CustomRenderPass : ScriptableRenderPass
- {
- public Material screen_scan_material = null;
- public RenderTargetIdentifier render_target_color;
- public RenderTargetHandle temp_render_target;
-
- // This method is called before executing the render pass.
- // It can be used to configure render targets and their clear state. Also to create temporary render target textures.
- // When empty this render pass will render to the active camera render target.
- // You should never call CommandBuffer.SetRenderTarget. Instead call <c>ConfigureTarget</c> and <c>ConfigureClear</c>.
- // The render pipeline will ensure target setup and clearing happens in a performant manner.
- public override void OnCameraSetup(CommandBuffer cmd, ref RenderingData renderingData)
- {
- }
-
- // Here you can implement the rendering logic.
- // Use <c>ScriptableRenderContext</c> to issue drawing commands or execute command buffers
- // https://docs.unity3d.com/ScriptReference/Rendering.ScriptableRenderContext.html
- // You don't have to call ScriptableRenderContext.submit, the render pipeline will call it at specific points in the pipeline.
- public override void Execute(ScriptableRenderContext context, ref RenderingData renderingData)
- {
- //Debug.Log("Execute fog pass");
-
- if (!screen_scan_material)
- return;
-
- {
- Camera cam = renderingData.cameraData.camera;
- var mtx_view_inv = cam.worldToCameraMatrix.inverse;
- var mtx_proj_inv = cam.projectionMatrix.inverse;
-
- screen_scan_material.SetMatrix("_mtx_view_inv", mtx_view_inv);
- screen_scan_material.SetMatrix("_mtx_proj_inv", mtx_proj_inv);
- }
-
- // scan box
- {
- Vector4 box_min = new Vector4(-15, -1000, -50, 0);
- Vector4 box_max = new Vector4(15, 1000, 50, 0);
- screen_scan_material.SetVector("_scan_box_min", box_min);
- screen_scan_material.SetVector("_scan_box_max", box_max);
- screen_scan_material.SetVector("_scan_color", new Vector4(179.0f/255.0f, 224.0f / 255.0f, 230.0f / 255.0f, 1.0f));
-
- Matrix4x4 box_mtx = Matrix4x4.identity;
- //box_mtx = Matrix4x4.Rotate(Quaternion.Euler(0, 45 + 30 * Time.time, 0)) * Matrix4x4.Translate(new Vector3(-400, 0, -380));
- box_mtx = Matrix4x4.Rotate(Quaternion.Euler(0, 45 - 30 * Time.time, 0)) * Matrix4x4.Translate(new Vector3(-400, 0, -380));
-
- screen_scan_material.SetMatrix("_scan_box_world_mtx", box_mtx);
- }
-
- const string CommandBufferTag = "screen scan Pass";
- var cmd = CommandBufferPool.Get(CommandBufferTag);
-
- RenderTextureDescriptor opaqueDesc = renderingData.cameraData.cameraTargetDescriptor;
- opaqueDesc.depthBufferBits = 0;
- cmd.GetTemporaryRT(temp_render_target.id, opaqueDesc);
-
- // 通过材质,将计算结果存入临时缓冲区
- cmd.Blit(render_target_color, temp_render_target.Identifier(), screen_scan_material);
- // 再从临时缓冲区存入主纹理
- cmd.Blit(temp_render_target.Identifier(), render_target_color);
-
- // 执行命令缓冲区
- context.ExecuteCommandBuffer(cmd);
- // 释放命令缓存
- CommandBufferPool.Release(cmd);
- // 释放临时RT
- cmd.ReleaseTemporaryRT(temp_render_target.id);
- }
-
- // Cleanup any allocated resources that were created during the execution of this render pass.
- public override void OnCameraCleanup(CommandBuffer cmd)
- {
- }
- }
-
- CustomRenderPass m_ScriptablePass;
- public Material screen_scan_material = null;
-
- /// <inheritdoc/>
- public override void Create()
- {
- m_ScriptablePass = new CustomRenderPass();
-
- // Configures where the render pass should be injected.
- m_ScriptablePass.renderPassEvent = RenderPassEvent.AfterRenderingOpaques;
- }
-
- // Here you can inject one or multiple render passes in the renderer.
- // This method is called when setting up the renderer once per-camera.
- public override void AddRenderPasses(ScriptableRenderer renderer, ref RenderingData renderingData)
- {
- m_ScriptablePass.render_target_color = renderer.cameraColorTarget;
- m_ScriptablePass.screen_scan_material = screen_scan_material;
-
- renderer.EnqueuePass(m_ScriptablePass);
- }
- }
-
-
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。