ChuanXin 发表于 2022-9-22 18:23

UrpShader3D篇之电流效果

一、简介

关于3d篇的内容更多的在于介绍基础知识,所以相对简单一些,等3d篇介绍完了,笔者会以特别篇的方式做些给力的效果,敬请期待。本文呢笔者将介绍电流的实现。效果如图1所示。



图1 电流效果

二、原理剖析

首先电流是随机扰动的,所以噪声纹理采样是比不可少的,同时电流是随时间变化的,所以还要加入一个时间数据;但是仅采样一张噪声,得到的效果是朝某个方向偏移,不像电流随机方向的效果,所以要采样两次,分别从不同方向以不同速度采样,在将2个噪声数据叠加,这个时候,电流就会产生不固定的方向了;
接下来,噪声纹理得到的效果是不规则的白块,而电流则是细线的效果,这里有2种方法,一种是像消融效果一样,取两个相邻的step值相减得到边缘,另一种则是通过Procedual/Shape里的形状节点来获取,笔者参考的是网上大佬的思路使用的后者,具体差异呢大家可以自己比对一下,笔者感觉差不太多!
最后叠加到主纹理上,一个电流效果就完成了,哈哈,细节可以看shadergraph及shader代码~
三、绘制shadergraph

按照惯例上连连看!



图2 电流shadergraph

四、翻译为urpshader

按照惯例上shader!
Shader "3d/electricity"
{
    Properties
    {
      _FirstUvOffsetSpeed("Speed", Vector) = (0, 0.3,0,0)
      _SecondUvOffsetSpeed("Speed (1)", Vector) = (0, -0.3,0,0)
      _testFloat("testFloat", Float) = 0.6
      _Color("Color", Color) = (1, 0.7926317, 0, 0)
      _MainTex("MainTex", 2D) = "white" {}
    }
    SubShader
    {
      Tags
      {
            "RenderPipeline"="UniversalPipeline"
            "RenderType"="Opaque"
            "UniversalMaterialType" = "Unlit"
            "Queue"="Geometry"
      }
      Pass
      {
            Name "ELECTRICITY"
            Tags
            {
                "LightMode" = "UniversalForward"
            }

            Cull Back
            Blend One Zero
            ZTest LEqual
            ZWrite On

            HLSLPROGRAM

            #pragma target 3.0
            #pragma exclude_renderers d3d11_9x
            #pragma vertex vert
            #pragma fragment frag

            #include "Packages/com.unity.render-pipelines.core/ShaderLibrary/Color.hlsl"
            #include "Packages/com.unity.render-pipelines.core/ShaderLibrary/Texture.hlsl"
            #include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Core.hlsl"
            #include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/DBuffer.hlsl"
      
            struct Attributes
            {
               float3 positionOS : POSITION;
               float3 normal:NORMAL;
               half4 uv0 : TEXCOORD0;
               half4 color:COLOR;
            };

            struct Varyings
            {
               float4 positionCS : SV_POSITION;
               half4 uv : TEXCOORD0;
            };
      
            CBUFFER_START(UnityPerMaterial)
            float2 _SecondUvOffsetSpeed;
            float2 _FirstUvOffsetSpeed;
            float _testFloat;
            float4 _Color;
            float4 _MainTex_TexelSize;
            CBUFFER_END
            
            // Object and Global properties
            SAMPLER(SamplerState_Linear_Repeat);
            TEXTURE2D(_MainTex);
            SAMPLER(sampler_MainTex);

            inline float Unity_SimpleNoise_RandomValue_float (float2 uv)
            {
                float angle = dot(uv, float2(12.9898, 78.233));
                #if defined(SHADER_API_MOBILE) && (defined(SHADER_API_GLES) || defined(SHADER_API_GLES3) || defined(SHADER_API_VULKAN))
                  // 'sin()' has bad precision on Mali GPUs for inputs > 10000
                  angle = fmod(angle, TWO_PI); // Avoid large inputs to sin()
                #endif
                return frac(sin(angle)*43758.5453);
            }
            
            inline float Unity_SimpleNnoise_Interpolate_float (float a, float b, float t)
            {
                return (1.0-t)*a + (t*b);
            }
            
            
            inline float Unity_SimpleNoise_ValueNoise_float (float2 uv)
            {
                float2 i = floor(uv);
                float2 f = frac(uv);
                f = f * f * (3.0 - 2.0 * f);
            
                uv = abs(frac(uv) - 0.5);
                float2 c0 = i + float2(0.0, 0.0);
                float2 c1 = i + float2(1.0, 0.0);
                float2 c2 = i + float2(0.0, 1.0);
                float2 c3 = i + float2(1.0, 1.0);
                float r0 = Unity_SimpleNoise_RandomValue_float(c0);
                float r1 = Unity_SimpleNoise_RandomValue_float(c1);
                float r2 = Unity_SimpleNoise_RandomValue_float(c2);
                float r3 = Unity_SimpleNoise_RandomValue_float(c3);
            
                float bottomOfGrid = Unity_SimpleNnoise_Interpolate_float(r0, r1, f.x);
                float topOfGrid = Unity_SimpleNnoise_Interpolate_float(r2, r3, f.x);
                float t = Unity_SimpleNnoise_Interpolate_float(bottomOfGrid, topOfGrid, f.y);
                return t;
            }
            
            float GetSimpleNoiseValue(float2 UV, float Scale)
            {
                float t = 0.0;
            
                float freq = pow(2.0, float(0));
                float amp = pow(0.5, float(3-0));
                t += Unity_SimpleNoise_ValueNoise_float(float2(UV.x*Scale/freq, UV.y*Scale/freq))*amp;
            
                freq = pow(2.0, float(1));
                amp = pow(0.5, float(3-1));
                t += Unity_SimpleNoise_ValueNoise_float(float2(UV.x*Scale/freq, UV.y*Scale/freq))*amp;
            
                freq = pow(2.0, float(2));
                amp = pow(0.5, float(3-2));
                t += Unity_SimpleNoise_ValueNoise_float(float2(UV.x*Scale/freq, UV.y*Scale/freq))*amp;
            
                return t;
            }

            float GetRemapValue(float In, float2 InMinMax, float2 OutMinMax)
            {
                return OutMinMax.x + (In - InMinMax.x) * (OutMinMax.y - OutMinMax.x) / (InMinMax.y - InMinMax.x);
            }
            
            float GetRectangleNicestValue(float2 UV, float Width, float Height)
            {
                UV = UV * 2.0 - 1.0;
                float2 w = float2(Width, Height);   // rectangle width/height
            #if defined(SHADER_STAGE_RAY_TRACING)
                float2 o = saturate(0.5f + 1e7 * (w - abs(UV)));
                o = min(o, 1e7 * w * 2.0f);
            #else
                float2 f = min(fwidth(UV), 0.5f);
                float2 k = 1.0f / f;
                float2 o = saturate(0.5f + k * (w - abs(UV)));
                o = min(o, k * w * 2.0f);
            #endif
                return o.x * o.y;
            }
                                    
            Varyings vert(Attributes input)
            {
                const float3 positionWS = TransformObjectToWorld(input.positionOS);         
                Varyings outPut;
                outPut.positionCS = TransformWorldToHClip(positionWS);
                outPut.uv = input.uv0;
                return outPut;
            }

            half4 frag(Varyings packedInput) : SV_TARGET
            {
                const half2 uv = packedInput.uv.xy;
                const float time = _TimeParameters.x;
                UnityTexture2D mainTex2D = UnityBuildTexture2DStructNoScale(_MainTex);
                const float4 mainColor = SAMPLE_TEXTURE2D(mainTex2D.tex, mainTex2D.samplerstate, mainTex2D.GetTransformedUV(uv));
                const float2 firstSpeedMulTime = _FirstUvOffsetSpeed * (time.xx);
                const half2 firstOffsetUv = uv * half2(1, 1) + firstSpeedMulTime;
                const float noiseUv = GetSimpleNoiseValue(firstOffsetUv, 20);
                const half2 secondSpeedMulTime = _SecondUvOffsetSpeed * (time.xx);
                const half2 secondOffsetUv = uv * half2(1, 1) + secondSpeedMulTime;
                const float noiseUv2 = GetSimpleNoiseValue(secondOffsetUv, 20);
                const float finalNoise = noiseUv + noiseUv2;
                const float remapValue = GetRemapValue(finalNoise, half2 (0, 1), half2 (-25, 5));
                const float rectangleValue = GetRectangleNicestValue((remapValue.xx), 1, 1);
                const half4 electricityColor = _Color * (rectangleValue.xxxx);
                half4 finalColor = mainColor + electricityColor;
                return half4(finalColor.xyz,1);
            }
            ENDHLSL
      }
    }
    FallBack "Hidden/Universal Render Pipeline/FallbackError"
}五、结语

一个好用的电流效果,请收好,3d篇效果还在持续进行中,欢迎大家收藏关注~
页: [1]
查看完整版本: UrpShader3D篇之电流效果