XAML 防止WPF ShaderEffect SamplerProperty将纹理调整为控制大小

xmd2e60i  于 11个月前  发布在  其他
关注(0)|答案(1)|浏览(175)

我在WPF中有一个ShaderEffect,其中有两个SamplerProperty。一个是采样器寄存器0中的隐式输入,另一个(在采样器寄存器1中)我传递了一个ImageBrush,其中有一个简单的PNG作为它的源。
此效果会套用至Rectangle,而其Fill设定为ImageBrush,且来源为不同的PNG。
我还将两个常量ViewportWidthViewportHeight传递给着色器,这两个常量分别绑定到矩形的ActualWidthActualHeight,中间有一个IValueConverter,它舍入到整数像素(因为出于某种原因,矩形总是比整数像素高0.04个像素)。
以下是XAML:

<TextBlock Grid.Row="0">
        Texture: 1009 x 753, Control: <Run Text="{Binding Path=ActualWidth, ElementName=TheRectangle, Mode=OneWay, Converter={StaticResource ResourceKey=Rounder}}"
        /> x <Run Text="{Binding Path=ActualHeight, ElementName=TheRectangle, Mode=OneWay, Converter={StaticResource ResourceKey=Rounder}}"/>
    </TextBlock>all textures passed to MyEffect1. -->
    <Rectangle x:Name="TheRectangle" Grid.Row="1" Margin="20" RenderOptions.BitmapScalingMode="NearestNeighbor" >
        <Rectangle.Fill>
            <ImageBrush ImageSource="D:\NoEffect.png"/>
        </Rectangle.Fill>
        <Rectangle.Effect>
            <l:MyEffect1
                x:Name="MyEffect"
                ViewportWidth="{Binding Path=ActualWidth, ElementName=TheRectangle, Mode=OneWay, Converter={StaticResource ResourceKey=Rounder}}"
                ViewportHeight="{Binding Path=ActualHeight, ElementName=TheRectangle, Mode=OneWay, Converter={StaticResource ResourceKey=Rounder}}"
            >
                <l:MyEffect1.TestTexture>
                    <ImageBrush x:Name="Texture" ImageSource="D:\MinecraftSkeletonTexture.png"/>
                </l:MyEffect1.TestTexture>
            </l:MyEffect1>
        </Rectangle.Effect>
    </Rectangle>

字符串
下面是HLSL着色器代码:

sampler2D ImplicitTexture : register(S0);
sampler2D TestTexture : register(S1);

float ViewportWidth : register(C0);
float ViewportHeight : register(C1);

float4 main(float2 UV : TEXCOORD) : SV_Target
{
    // These two tests work as expected.
    // return tex2D(ImplicitTexture, UV);
    // return tex2D(TestTexture, UV);

    // Convert UV-space to pixels
    float2 ScreenPixel = UV * float2(ViewportWidth, ViewportHeight);
    // Hard-coded size (in pixels) of TestTexture, for easy testing
    float2 TestTextureSourceSize = float2(1009, 753);
    // Where (in pixels) we want to sample the TestTexture
    // We could also e.g. zoom in by a factor of 5 by dividing ScreenPixel by 5, or shift to the left by 100 pixels by adding float2(100, 0)
    float2 SamplePositionInPixels = ScreenPixel;
    // Convert pixels to UV-space
    float2 TestTextureRelativeUv = SamplePositionInPixels / TestTextureSourceSize;
    // Sample the texture at that position
    return tex2D(TestTexture, TestTextureRelativeUv);
}


这在原则上是可行的,但问题是我实际上无法从着色器访问整个TestTexture。当我减小窗口大小(因此也减小了Rectangle大小)时,我开始丢失像素数据。
下面是一个现象的视频:https://imgur.com/a/4hbebMS
结果不应扭曲,也不应像那样变成块状。
WPF似乎会调整纹理的大小,以符合套用此效果的矩形大小。
有什么办法可以防止这种情况发生吗?
这对我来说是个问题,因为在实际的程序中,我使用纹理将大量的任意数据传递给着色器,这些数据被插值完全打乱了。
注意事项:RenderOptions.BitmapScalingMode="NearestNeighbor"的存在并不会改变这个行为。它只是改变了纹理在传递到着色器之前缩小的方式。另请注意:WPF会在将所有纹理传送到着色器之前,先将它们转换为(p)BGRA32。重新调整比例可能是该过程的一部分。

mpgws1up

mpgws1up1#

请看blogs.ugidotnet.org/leonardo,0.04像素的问题可以是PNG文件,因为无法在元数据中存储96 DPI。尝试使用PNGGauntlet删除元数据,以便WPF默认为96 DPI,并且您不会调整纹理大小。为了解决第二个问题(固定TestTexture大小),您应该避免将Brush重命名(不要将其放在重命名的元素中)。

相关问题