WPF網格型別畫素著色器

ggtc發表於2024-06-29

由於WPF只能寫畫素著色器,沒法寫頂點著色器,所以只能在這上面做文章了
剛好有個紋理座標TEXCOORD輸入可用,而且值的範圍是已知的0-1,左上角是原點,這就好辦了

例子

索引

二分網格

  • 使用ceil
  • 0-1移動定義域到-0.5 - 0.5,然後向上取整變成 0 / 1
float4 main(float2 uv : TEXCOORD) : COLOR
{
    float ab =  ceil( uv.y-0.5 );
    return float4(ab,ab,ab,1.0);
}

image

4分網格

  • 使用ceil
  • 0-1,先放大定義域0-4,然後向左移動定義域,-0.5 - 3.5,向上取整 0/1/2/3,最後壓縮0/0.25/0.5/0.75/1
float4 main(float2 uv : TEXCOORD) : COLOR
{
    float ab =  ceil( uv.y*4-0.5 );
    float scale=ab/4;
    return float4(scale,scale,scale,1.0);
}

image

二值化多分網格

  • 使用sin round
  • 利用週期函式把定義域0-1範圍的週期調整到指定數,然後值域壓扁-0.5 - 0.5,向上移動0-1,四捨五入二值化
//三角函式是天然的週期函式
float4 main(float2 uv : TEXCOORD) : COLOR
{
    float num=6;
    float2 ab =  0.5*sin(uv*3.1415*num )+0.5;
    float2 scale=round(ab);
    return float4(scale.y,scale.y,scale.y,1.0);
}

image

二值化方格

  • 使用sin round abs
  • 在上一篇基礎上,相乘生成縱橫條紋。但這形成十字條紋,為了產生交錯條紋,就不能相乘,只能相加
float4 main(float2 uv : TEXCOORD) : COLOR
{
    float num=7;
    float abx =  0.5*sin(uv.x*3.1415*num )+0.5;
    float aby =  0.5*sin(uv.y*3.1415*num )+0.5;
    float scale=abs((round(abx)/2)+(round(aby)/2)-0.5);
    //0.4是避免浮點數精度問題,否則直接用round(scale)
    float scale2=ceil(scale-0.4);
    return float4(scale2,scale2,scale2,1.0);
}

image

動態方格

  • 使用sin round abs
/// <summary> time </summary>
/// <minValue>0</minValue>
/// <maxValue>100</maxValue>
/// <defaultValue>0</defaultValue>
float time : register(C0);
float4 main(float2 uv : TEXCOORD) : COLOR
{
    float num=7;
    float abx =  0.5*sin(uv.x*3.1415*num+time )+0.5;
    float aby =  0.5*sin(uv.y*3.1415*num )+0.5;
    float scale=abs((round(abx)/2)+(round(aby)/2)-0.5);
    float scale2=ceil(scale-0.4);
    return float4(scale2,scale2,scale2,1.0);
}

image

線框網格

  • 使用sin abs max step
  • 將週期函式取絕對值,變成一個個山峰,然後下沉,利用一個閾值,過濾出山尖
float4 main(float2 uv : TEXCOORD) : COLOR
{
    float gridLines = 11;

    float gridLineX = step(0.99, abs(sin(uv.x * 3.1415 * gridLines))); 
    float gridLineY = step(0.99, abs(sin(uv.y * 3.1415 * gridLines))); 

    float4 color = float4(max(gridLineX,gridLineY) , max(gridLineX,gridLineY) , max(gridLineX,gridLineY) , 1.0);

    return color;
}

image

線框網格上滾動的小球

  • 使用sin abs max step
  • 在前一篇基礎上,再傳入滑鼠位置,並再滑鼠周圍畫一個白色圓形,覆蓋線框顏色設定。使用語義VPOS獲取畫素位置判斷和滑鼠距離
float2 mousePosition : register(C0);
float4 main(float2 uv : TEXCOORD,float2 positon : VPOS) : COLOR
{
    float gridLines = 11;

    float gridLineX = step(0.99, abs(sin(uv.x * 3.1415 * gridLines))); 
    float gridLineY = step(0.99, abs(sin(uv.y * 3.1415 * gridLines)));
    float maxline=max(gridLineX,gridLineY);
    
    float innerCircle = 1.0 - step(50,length(positon-mousePosition));
    float maxResult=max(maxline,innerCircle);

    float4 color = float4(maxResult , maxResult , maxResult , 1.0);

    return color;
}

image

滑鼠操控小球

public class MouseCaptureEffect : ShaderEffect
{
    public static readonly DependencyProperty InputProperty = ShaderEffect.RegisterPixelShaderSamplerProperty("Input", typeof(MouseCaptureEffect), 0);
    public static readonly DependencyProperty MousePositionProperty = DependencyProperty.Register("MousePosition", typeof(Point), typeof(MouseCaptureEffect), new UIPropertyMetadata(new Point(0D, 0D), PixelShaderConstantCallback(0)));
    public MouseCaptureEffect()
    {
        PixelShader pixelShader = new PixelShader();
        pixelShader.UriSource = new Uri("pack://application:,,,/你的程式集名稱;component/路徑/TextEffect3.ps", UriKind.Absolute);
        this.PixelShader = pixelShader;

        this.UpdateShaderValue(InputProperty);
        this.UpdateShaderValue(MousePositionProperty);
    }
    public Brush Input
    {
        get
        {
            return ((Brush)(this.GetValue(InputProperty)));
        }
        set
        {
            this.SetValue(InputProperty, value);
        }
    }
    /// <summary> mouse </summary>
    public Point MousePosition
    {
        get
        {
            return ((Point)(this.GetValue(MousePositionProperty)));
        }
        set
        {
            this.SetValue(MousePositionProperty, value);
            Debug.WriteLine("aaa");
        }
    }
}
<Button Content="Btn">
    <Button.Effect>
        <local:MouseCaptureEffect x:Name="me" MousePosition="{Binding MousePositionw,Mode=TwoWay}" >
        </local:MouseCaptureEffect>
    </Button.Effect>
</Button>
this.MouseMove += (sender, e) =>
{
    //這行程式碼不管用
    //MousePositionw = e.GetPosition(this);
    // 更新滑鼠位置
    me.MousePosition= MousePositionw;
};

要注意的時,透過繫結的方式更新沒成功,只好手動賦值,不知道哪裡出問題了
image

相關文章