在Shader编程里,step函数是一个常用的内置函数,主要用于进行比较操作并产生阶跃输出。下面从基本语法、功能原理、使用场景等方面进行介绍。

Shader "ShaderLearning/Shader05"
{
    Properties
    {
        _MainTex ("Texture", 2D) = "white" {}
        _OnOff("OnOff", Range(0, 1)) = 0
    }
    SubShader
    {
        // No culling or depth
        Cull Off ZWrite Off ZTest Always

        Pass
        {
            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag

            #include "UnityCG.cginc"

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

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

            v2f vert(appdata v)
            {
                v2f o;
                o.vertex = UnityObjectToClipPos(v.vertex);
                o.uv = v.uv;
                return o;
            }

            sampler2D _MainTex;
            float _OnOff;

            fixed4 frag(v2f i) : SV_Target
            {
                float r = step(0.5, _OnOff) * step(0.5, i.uv.x);
                r += (1 - step(0.5, _OnOff)) * step(0.5, i.uv.y);
                return fixed4(r, 0, 0, 1);
            }
            ENDCG
        }
    }
}

基本语法

在GLSL(OpenGL Shading Language)、HLSL(High-Level Shading Language)等常见Shader语言中,step函数的语法是相同的:

float step(float edge, float x);
vec2 step(vec2 edge, vec2 x);
vec3 step(vec3 edge, vec3 x);
vec4 step(vec4 edge, vec4 x);
  • edge:比较的边界值。
  • x:待比较的值。
  • 返回值:如果x小于edge,返回0;如果x大于或等于edge,返回1。对于向量形式,会对向量的每个分量分别进行比较操作。

功能原理

step函数本质上是一个阶跃函数。它在x达到edge这个边界值时,输出从0跃变为1。以下是一个简单的代码示例来说明其工作原理:

// 假设这是在片段着色器中
void main() {
    float edge = 0.5;
    float x = 0.3;
    float result = step(edge, x);
    // 因为 0.3 < 0.5,所以 result 为 0
}

使用场景

  • 图形绘制:在绘制图形时,可借助step函数实现硬边界效果。例如,绘制一个颜色突变的矩形,只需比较像素坐标与矩形边界,当坐标超出边界时,颜色发生突变。
void main() {
    vec2 uv = gl_FragCoord.xy / iResolution.xy;
    float left = 0.2;
    float right = 0.8;
    float bottom = 0.2;
    float top = 0.8;
    float mask = step(left, uv.x) * step(uv.x, right) * step(bottom, uv.y) * step(uv.y, top);
    vec3 color = mix(vec3(0.0), vec3(1.0), mask);
    gl_FragColor = vec4(color, 1.0);
}
  • 阴影效果:在实现简单阴影效果时,可使用step函数。通过比较光线与物体的距离和某个阈值,来决定像素是否处于阴影中。
float shadow = step(light_distance, threshold);

注意事项

  • step函数的输出只有0和1两种状态,产生的是硬边界效果。若需要软边界效果,可使用smoothstep函数。
  • 在使用向量形式的step函数时,要确保向量的维度一致,避免出现意外结果。