我在 WPF 中有一个
ShaderEffect
,有两个 SamplerProperty
。第一个是采样器寄存器 0 中的隐式输入,第二个(在采样器寄存器 1 中)我传递一个 ImageBrush
,并以简单的 PNG 作为其源。Rectangle
,其 Fill
设置为以不同 PNG 作为源的 ImageBrush
。ViewportWidth
和ViewportHeight
,它们分别绑定到矩形的ActualWidth
和ActualHeight
,中间有一个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
大小)时,我开始丢失像素数据。WPF 似乎会调整纹理大小以匹配应用效果的矩形的大小。
有什么办法可以防止这种情况发生吗?
这对我来说是一个问题,因为在实际程序中我使用纹理将大量任意数据传递给着色器。插值后的数据完全混乱。
注意:
RenderOptions.BitmapScalingMode="NearestNeighbor"
的存在不会改变此行为。它只是改变纹理在传递到着色器之前按比例缩小的方式。
另请注意:WPF 在将所有纹理发送到着色器之前将其转换为 (p)BGRA32。重新调整可能是该过程的一部分。