5

WPF のピクセル シェーダーの奇妙な動作に遭遇しました。

この問題は 100% 再現可能であるため、簡単なデモ プログラムを作成しました。ソースコードはこちらからダウンロードできます。

すべての悪の根源は、MyFrameworkElement という名前の小さなクラスです。

internal sealed class MyFrameworkElement : FrameworkElement
{
    public double EndX
    {
        get
        {
            return (double)this.GetValue(MyFrameworkElement.EndXProperty);
        }
        set
        {
            this.SetValue(MyFrameworkElement.EndXProperty, value);
        }
    }

    public static readonly DependencyProperty EndXProperty =
        DependencyProperty.Register("EndX",
            typeof(double),
            typeof(MyFrameworkElement),
            new FrameworkPropertyMetadata(0d, FrameworkPropertyMetadataOptions.AffectsRender));

    protected override void OnRender(DrawingContext dc)
    {
        dc.DrawLine(new Pen(Brushes.Red, 2), new Point(0, 0), new Point(this.EndX, 100));
        dc.DrawLine(new Pen(Brushes.Green, 3), new Point(10, 300), new Point(200, 10));
    }
}

ご覧のとおり、このフレームワーク要素は 2 つの線をレンダリングします。下の線は永続的な座標を持ちますが、上の線は EndX 依存関係プロパティに依存します。

したがって、このフレームワーク要素は、ピクセル シェーダー効果のターゲットです。簡単にするために、ここにあるグレースケール シェーダー効果を使用します。そこで、MyFrameworkElement に GrayscaleEffect を適用しました。結果を見ることができます。

EndXプロパティを大幅に増やすまで。

細いラインはぼやけて、太いラインはスッキリ!

しかし、グレースケール効果を削除すると、すべての線が本来のように見えます。

このぼやけの理由を説明できる人はいますか? または、どうすればこの問題を解決できますか?

4

4 に答える 4

2

カスタム ピクセル シェーダーでは、中間ビットマップを作成する必要があり、そのテクスチャがピクセル シェーダーによってサンプリングされます。

大規模なレンダリングを作成しているため、レンダリング パスでいくつかの制限に達しています。

簡単な修正は、次のようにレンダリングしたいものをクリップすることです:

Geometry clip = new RectangleGeometry(new Rect(0,0,this.ActualWidth, this.ActualHeight));

dc.PushClip(clip);

dc.DrawLine(new Pen(Brushes.Red, 2), new Point(0, 0), new Point(this.EndX, 100));
dc.DrawLine(new Pen(Brushes.Green, 3), new Point(200, 10), new Point(10, 300));

dc.Pop();

アップデート:

1 つの理論は、ビットマップが最大テクスチャ サイズ (グラフィックス カードのアーキテクチャによって異なる場合があります) を超えたときに、フィルターを使用してビットマップをスケーリングしているというものです...そのため、異なるサイズでピクセル シェーダーを通過します....元のサイズに縮小されます。

したがって、スケーリング フィルターは、ビットマップのコンテンツに応じてアーティファクトを引き起こします (つまり、水平線と垂直線は、対角線よりも縮小および拡大しても存続します)。

.NET 4 は、フィルタリングに使用する既定のフィルターを低品質のものに変更しました...Fant ではなくバイリニアです...おそらく、これは得られる品質にも影響します。

http://10rem.net/blog/2010/05/16/more-on-image-resizing-in-net-4-vs-net-35sp1-bilinear-vs-fant

更新 2:

この種のことは、私が上で考えていたことを確認します。

Windows パフォーマンス ツールキット/スイート (Windows SDK の一部) を使用している場合、スライダーの値を大きくすると、オレンジ色のグラフでビデオ メモリが大量に消費されるのがわかります。これは、より大きな中間ビットマップ テクスチャが作成されるためです。限界に達するまで増加し続け、その後横ばいになります...そして、ピクセレーションが明らかになるときです。

ここに画像の説明を入力

更新3:

レンダリング モードを「ソフトウェア レンダラー」(Tier 0) に設定すると、このような大きなビジュアルのレンダリングにどのように対処するかを確認できます。アーティファクトは別のポイントで表示され始めます....おそらくテクスチャ サイズの制限が大きいためです。 /お使いの GPU とは異なります。ただし、バイリニア フィルターを内部で使用しているため、アーティファクトは引き続き表示されます。

RenderOptions.SetBitmapScalingMode を使用してフィルターを Fant に上げようとしても、レンダリングの品質はまったく変わらないようです (カスタム ピクセル シェーダー パスを通過するときに受け入れられないためだと思います)。

これを Application_Startup に入れて、ソフトウェア レンダラーの結果を確認します。

RenderOptions.ProcessRenderMode = RenderMode.SoftwareOnly;
于 2012-07-25T14:25:29.523 に答える
2

画像は通常、縦方向はぼやけていますが、横方向はジャグになっていることに注意してください。

シェーダーはベクターではなくラスター イメージに適用されるため、線はテクスチャーにラスター化されます。ハードウェアは通常、8198*8192 までのテクスチャをサポートします。私の場合、いわゆる「ぼかし」はスライダー値 16384 で表示されます。したがって、私の virtualBox 仮想グラフィックス カードは最大 16384*16384 をサポートします。制限は異なる場合があります。したがって、この値をそれよりも低くしてください。

しかし、WPF が画像全体をラスタライズするのは奇妙です。画像のごく一部しか見えないからです。したがって、シェーダー自体の内部にある別の理由も考えられますが、バイナリにコンパイルされているため、確認できません。

更新: 私の場合、次のようになります。 シェーダーを適用した状態

水平ではなく垂直にフィルタリングされているように見えます。

于 2012-07-25T14:17:38.310 に答える
1

古い質問ですが、Custom ShaderEffect を適用した後に画像のぼやけに問題がある人には役立つかもしれません。

OPが言及した問題も、レンダリングされたコンテンツのスケールに関連している可能性があります.WPFShadersLibraryのShaderEffectsを通常のウィンドウ内のビデオ、テキスト、およびその他のコンテンツに適用した後、ぼかしに関して同様の問題がありました.

その画像が少しだけ下にシフトし、「ピクセル分割」が発生することに気付いたので、選択した ShaderEffect の 2 つの新しいプロパティ XOffset と YOffset を作成し、それらを HLSL に適用し (以下のコードを参照)、Sliders にバインドしましたXAML :

float2 newPos;
newPos.x = uv.x + offsetX;
newPos.y = uv.y + offsetY;

次に、任意のオフセットをいくつか試して、画像を再調整することができました。最小限のぼやけ (または細部の損失) はまだありますが、結果は著しく良くなりました。

現在、このソリューションの問題は、解像度またはウィンドウ サイズに応じてオフセットを予測する方法がわからないことです。

于 2015-01-27T14:36:46.037 に答える
1

わかりました、これを手に入れました!グレースケール効果を使用してライブラリを逆コンパイルし、WCF PresentationCore ライブラリも逆コンパイルして、BlurEffectが同じ状況で完璧に機能する理由を確認しました。そして、BlurEffectGrayscaleEffectにない抽象メソッド Effect.GetRenderBounds を実装ていることがわかりました。また、 GrayscaleEffectは、Effect にGetRenderBoundがない PresentationCore v 3.0.0 に対してビルドされていることにも気付きました。

したがって、これは WPF の 3 番目と 4 番目のバージョン間の非互換性です。それを修正するには、次の 3 つの方法があります。

  1. GrayscaleEffectのソース コードがある場合は、必要なメソッドを追加し、4.0.0 バージョンのランタイムに対してコンパイルします。
  2. アプリケーションが使用するランタイムをバージョン 3.* に切り替えることができます。
  3. GrayscaleEffectのソースがなく、第 3 バージョンのランタイムを使用できない場合は、Effect (v4)を継承し、存在しないメソッドを実装するGrayscaleEffectのラッパーを記述します。

2番目の方法を試したところ、問題はなくなりました。

于 2012-07-26T07:07:20.850 に答える