You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.04 20:07:33