unity urp内置的SAMPLER SamplerState

处理云阴影,打算直接在post阶段做个贴花了事

根据世界坐标的xz做为纹理采样的坐标,加上旋转缩放,形成运行的云阴影

采样器要用clamp方式

于是这样声明了一个

            SAMPLER(sampler_CloudTex)

            {

                Filter = MIN_MAG_MIP_LINEAR;

                AddressU = Clamp;//no work

                AddressV = Clamp;//no work

            };

发现不启作用

去官网看了一下,发现有内置的采样器定义

“Point”, “Linear” or “Trilinear” (required) set up texture filtering mode.

“Clamp”, “Repeat”, “Mirror” or “MirrorOnce” (required) set up texture wrap mode.Wrap modes can be specified per-axis (UVW), e.g. “ClampU_RepeatV”.

“Compare” (optional) set up sampler for depth comparison; use with HLSL SamplerComparisonState type and SampleCmp / SampleCmpLevelZero functions.

意思是根据名字组合,如

sampler_<过滤><UV处理>  形成一个变量名,用这个变量作为参数形成采样

例如:sampler_LinearClamp 这个表示采样过滤是linear,超过(0,1)用clamp方式采样

SAMPLER(sampler_LinearClamp);在shader里这样声明变量

采样是这样使用:

float4 cloud = SAMPLE_TEXTURE2D_X(_CloudTex, sampler_LinearClamp, cloud_uv);

也可以这样

 _CloudTex.Sample(sampler_LinearClamp, cloud_uv);

对应代码截图

unity的有些内置处理真是暗黑。

运行结果如下:

附上代码,同时也演示了如何在urp添加自定义管线

shader代码:

Shader "lsc/test_post_fog"
{
    Properties
    {
        _MainTex ("Texture", 2D) = "white" {}
        _CloudTex("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"
            #include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Lighting.hlsl"

            sampler2D _MainTex;

            //sampler2D _CameraDepthTexture;
            float4x4 _mtx_view_inv;
            float4x4 _mtx_proj_inv;
            //float4x4 _mtx_clip_to_world;
            TEXTURE2D_X_FLOAT(_CameraDepthTexture);
            SAMPLER(sampler_CameraDepthTexture);

            //cloud
            TEXTURE2D_X_FLOAT(_CloudTex);
            SAMPLER(sampler_LinearClamp);//work
            float4x4 _mtx_cloud_uv_rotate;
            float4 _cloud_offset_scale;
            //SAMPLER(sampler_CloudTex)
            //{
            //    Filter = MIN_MAG_MIP_LINEAR;
            //    AddressU = Clamp;//no work
            //    AddressV = Clamp;//no work
            //};

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

            struct v2f
            {
                float2 uv : TEXCOORD0;
                float4 vertex : SV_POSITION;

                float4 screen_pos : TEXCOORD1;
                float2 ndc_pos : TEXCOORD2;
            };

            v2f vert (appdata v)
            {
                v2f o;
                //o.vertex = UnityObjectToClipPos(v.vertex);
                VertexPositionInputs vertexInput = GetVertexPositionInputs(v.vertex.xyz);
                o.vertex = vertexInput.positionCS;

                o.uv = v.uv;

                o.screen_pos = ComputeScreenPos(o.vertex);
                o.ndc_pos = (v.uv) * 2.0 - 1.0;

                return o;
            }


            float4 frag(v2f i) : SV_Target
            {
                float4 view_pos;
                float3 world_pos;

                float depth01 = SAMPLE_TEXTURE2D_X(_CameraDepthTexture, sampler_CameraDepthTexture, i.uv).r;

                //lsc 取出线性深度,即摄影机空间的z坐标
                float linearDepthZ = LinearEyeDepth(depth01, _ZBufferParams);

                //lsc 纹理映射转换到标准空间
                float4 screen_pos = float4(i.ndc_pos.x, i.ndc_pos.y, depth01, 1);
                //lsc 转成齐次坐标
                screen_pos = screen_pos * linearDepthZ;
                //lsc 还原摄影机空间坐标
                view_pos = mul(_mtx_proj_inv, screen_pos);
                //lsc 世界
                world_pos = mul(_mtx_view_inv, float4(view_pos.xyz, 1));

                //高度雾衰减
                float h_percent = saturate(((world_pos.y - 0.0f) / 20.0f));
                float fac_h = exp(-h_percent * h_percent);

                //距离雾衰减
                float dis = length(world_pos.xyz - _WorldSpaceCameraPos.xyz);
                float d_percent = 1 - ((dis - 50.0) / 100.0f);
                d_percent = saturate(d_percent);
                float fac_d = exp(-d_percent * d_percent);

                float4 final_col;
                final_col.w = 1.0;

                float4 col = tex2D(_MainTex, i.uv);

                //cloud  处理云阴影,纹理平移旋转
                float2 cloud_uv = (world_pos.xz - _cloud_offset_scale.xy) / _cloud_offset_scale.z;
                cloud_uv = cloud_uv * 2 - 1;
                cloud_uv = mul(_mtx_cloud_uv_rotate, float4(cloud_uv.x, 0, cloud_uv.y, 0)).xz;
                cloud_uv = cloud_uv * 0.5 + 0.5;
                float4 cloud = SAMPLE_TEXTURE2D_X(_CloudTex, sampler_LinearClamp, cloud_uv);// _CloudTex.Sample(sampler_LinearClamp, cloud_uv);
                float cloud_dis = length(world_pos.xz - (_cloud_offset_scale.xy + _cloud_offset_scale.z/2));
                cloud.r = cloud.r * pow(clamp(1 - cloud_dis / _cloud_offset_scale.z * 2, 0, 1), 1);
                col.xyz = lerp(col.xyz, float3(0, 0, 0), cloud.r);
                return col;

                //最终雾效
                final_col.rgb = lerp(col.rgb, float3(0.2, 0.5, 0.8), fac_d * fac_h * 1);

                return final_col;
            }
            ENDHLSL
        }
    }
}

对应的feature与pass cs代码

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

public class FogCustomRenderPassFeature : ScriptableRendererFeature
{
    class FogCustomRenderPass : ScriptableRenderPass
    {
        public RenderTargetIdentifier render_target_color;
        public RenderTargetHandle temp_render_target;
        public Material custom_full_screen_material = null;
        public Texture tex_cloud = null;

        // 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 (!custom_full_screen_material)
                return;

            {
                Camera cam = renderingData.cameraData.camera;
                var mtx_view_inv = cam.worldToCameraMatrix.inverse;
                var mtx_proj_inv = cam.projectionMatrix.inverse;

                custom_full_screen_material.SetMatrix("_mtx_view_inv", mtx_view_inv);
                custom_full_screen_material.SetMatrix("_mtx_proj_inv", mtx_proj_inv);
                custom_full_screen_material.SetTexture("_CloudTex", tex_cloud);

                Vector4 cloud_offset_scale = new Vector4(350, 350, 100, 1);
                custom_full_screen_material.SetVector("_cloud_offset_scale", cloud_offset_scale);
                Matrix4x4 cloud_rotate = Matrix4x4.identity;
                //cloud_rotate = Matrix4x4.Rotate(Quaternion.AxisAngle(new Vector3(0, 1, 0),9 * Time.time));
                cloud_rotate = Matrix4x4.Rotate(Quaternion.Euler(0, 30 * Time.time, 0));
                custom_full_screen_material.SetMatrix("_mtx_cloud_uv_rotate", cloud_rotate);

                //Debug.Log("screen height:" + cam.scaledPixelHeight + " screen width:" + cam.scaledPixelWidth);

                //Debug.Log("pass Execute view_inv:" + mtx_view_inv + " proj_inv:" + mtx_proj_inv);
            }


            const string CommandBufferTag = "FogCustomRenderPassFeature 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(), custom_full_screen_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)
        {
        }
    }

    FogCustomRenderPass m_ScriptablePass;

    public Material custom_full_screen_material = null;
    public Texture tex_cloud = null;

    /// <inheritdoc/>
    public override void Create()
    {
        //Debug.Log("Create fog pass");

        m_ScriptablePass = new FogCustomRenderPass();

        // Configures where the render pass should be injected.
        m_ScriptablePass.renderPassEvent = RenderPassEvent.AfterRenderingOpaques;
        //m_ScriptablePass.renderPassEvent = RenderPassEvent.AfterRenderingTransparents;
    }

    // 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.custom_full_screen_material = custom_full_screen_material;
        m_ScriptablePass.tex_cloud = tex_cloud;

        renderer.EnqueuePass(m_ScriptablePass);
    }
}


猜你喜欢

转载自blog.csdn.net/lsccsl/article/details/118086659