如何在Unity URP的HLSL无光照Shader中实现动漫速度线?
动漫速度线Shader实现优化建议(URP + HLSL)
问题概述
在Unity Universal Render Pipeline(URP)中使用HLSL编写无光照Shader,目标是实现动漫风格的速度线效果,但当前调试的代码效果不符合预期。考虑采用径向函数或噪声函数实现,但缺乏具体落地方法。
当前片段代码(效果不符合预期)
half4 frag(Varyings IN) : SV_Target { float blendFactor = smoothstep(0.02, _LineWidth, abs(IN.uv.y - IN.uv.x)); return pow(IN.uv.x * blendFactor, 10) * _LineColor; }
完整Shader代码
Shader "Magnality/Speedlines" { Properties { _LineColor("Line Color", Color) = (1, 1, 1, 1) _Speed("Speed", Float) = 1.0 _Density("Density", Float) = 0.5 _LineWidth("Line Width", Float) = 0.003 [HideInInspector] _MainTex ("Texture", 2D) = "white" {} } SubShader { Tags { "RenderType"="Overlay" "RenderPipeline" = "UniversalPipeline" } LOD 100 Pass { HLSLPROGRAM #pragma vertex vert #pragma fragment frag #include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Core.hlsl" struct Attributes { float4 positionOS : POSITION; float2 texcoord : TEXCOORD0; }; struct Varyings { float4 positionHCS : SV_POSITION; float4 positionOS : TEXCOORD1; float2 uv : TEXCOORD0; float4 screenPos : TEXCOORD2; }; Varyings vert(Attributes IN) { Varyings OUT; OUT.positionHCS = TransformObjectToHClip(IN.positionOS.xyz); OUT.positionOS = IN.positionOS; OUT.uv = IN.texcoord; OUT.screenPos = ComputeScreenPos(OUT.positionHCS); return OUT; } CBUFFER_START(UnityPerMaterial) half4 _LineColor; float _Speed; float _Density; float _LineWidth; CBUFFER_END half4 frag(Varyings IN) : SV_Target { float blendFactor = smoothstep(0.02, _LineWidth, abs(IN.uv.y - IN.uv.x)); return pow(IN.uv.x * blendFactor, 10) * _LineColor; } ENDHLSL } } }
落地实现方案
1. 放射状速度线(径向函数实现)
适合表现从中心向外爆发的速度感,基于屏幕坐标计算径向角度生成线条,并通过时间参数实现滚动效果:
替换原frag函数为以下代码:
half4 frag(Varyings IN) : SV_Target { // 将屏幕坐标归一化到0~1范围 float2 screenUV = IN.screenPos.xy / IN.screenPos.w; // 速度线中心位置(可改为属性控制,适配不同爆发点) float2 center = float2(0.5, 0.5); float2 dir = screenUV - center; // 计算像素到中心的角度,用于生成放射状线条 float angle = atan2(dir.y, dir.x); // 结合密度参数控制线条数量,时间参数实现滚动动画 float linePattern = sin(angle * _Density + _Time.y * _Speed); // 用smoothstep实现线条边缘的平滑过渡,避免生硬锯齿 float line = smoothstep(_LineWidth, _LineWidth + 0.01, abs(linePattern)); line = 1 - line; // 反转得到亮线条效果 return line * _LineColor; }
2. 随机风格速度线(噪声函数实现)
适合表现自然随机的运动模糊感,通过简单伪噪声生成不规则线条:
首先在HLSL代码中添加伪噪声函数(放在CBUFFER_END之后):
// 简单伪随机函数 float random(float2 st) { return frac(sin(dot(st, float2(12.9898, 78.233))) * 43758.5453); } // 2D噪声函数 float noise(float2 st) { float2 i = floor(st); float2 f = frac(st); float a = random(i); float b = random(i + float2(1.0, 0.0)); float c = random(i + float2(0.0, 1.0)); float d = random(i + float2(1.0, 1.0)); float2 u = f * f * (3.0 - 2.0 * f); return lerp(a, b, u.x) + (c - a)* u.y * (1.0 - u.x) + (d - b) * u.x * u.y; }
然后替换frag函数:
half4 frag(Varyings IN) : SV_Target { float2 screenUV = IN.screenPos.xy / IN.screenPos.w; // 控制速度线的运动方向(可改为属性控制) float2 moveDir = float2(1.0, 0.1); // 随时间滚动UV,实现线条流动效果 float2 movingUV = screenUV + _Time.y * _Speed * moveDir; // 用噪声生成随机线条分布,密度参数控制线条数量 float noiseVal = noise(movingUV * _Density); // 提取噪声中接近0.5的区域作为线条 float line = smoothstep(_LineWidth, _LineWidth + 0.02, abs(noiseVal - 0.5)); line = 1 - line; return line * _LineColor; }
3. 优化原对角线速度线
如果需要保留对角线方向的速度线,可修改原代码解决线条不均匀问题,添加滚动动画:
half4 frag(Varyings IN) : SV_Target { // 对角线方向UV,添加时间参数实现滚动 float diagonalUV = IN.uv.x - IN.uv.y + _Time.y * _Speed; // 用正弦函数生成周期性线条 float linePattern = sin(diagonalUV * _Density); // 平滑线条边缘 float blendFactor = smoothstep(_LineWidth, _LineWidth + 0.01, abs(linePattern)); float line = 1 - blendFactor; return line * _LineColor; }
内容的提问来源于stack exchange,提问作者Magnality
相关产品推荐
相关产品推荐

