2012-07-25 27 views
5

लागू करने के बाद धुंधली तस्वीर मैं WPF में पिक्सेल शेडर के अजीब व्यवहार में आया हूं।शेडर प्रभाव

यह समस्या 100% पुनरुत्पादित है, इसलिए मैंने छोटे डेमो प्रोग्राम को लिखा। आप स्रोत कोड here डाउनलोड कर सकते हैं।

सब बुराई की जड़ छोटे वर्ग शीर्षक 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 लाइनों renders: कम लाइन स्थायी निर्देशांक है, लेकिन ऊपरी रेखा EndX निर्भरता संपत्ति पर निर्भर करता है।

तो यह ढांचा तत्व पिक्सेल शेडर प्रभाव के लिए लक्षित है। सादगी के लिए मैं ग्रेस्केल शेडर प्रभाव का उपयोग here पाया। तो मैंने GrayscaleEffect को MyFrameworkElement पर लागू किया। आप परिणाम देख सकते हैं, यह अच्छा लग रहा है।

जब तक मैं EndX संपत्ति तेजी से वृद्धि हुई है।

छोटे रेखा धुंधली है और बड़ी लाइन ठीक है!

लेकिन अगर मैं ग्रेस्केल प्रभाव को हटा देता हूं, तो सभी लाइनें देखेंगे जैसे उन्हें चाहिए।

किसी को भी इस धुंधला के कारण क्या व्याख्या कर सकते हैं? या इससे भी बेहतर मैं इस समस्या को कैसे हल कर सकता हूं?

+0

विशाल मूल्यों के लिए बिटमैपफेक्ट की सीमा की तरह लगता है। – LPL

+0

@ एलपीएल यदि आप एंडएक्स प्रॉपर्टी में दूसरी (निचली) लाइन बांधते हैं और फिर एंडएक्स 80000 सेट करते हैं, तो सब ठीक हो जाएगा। मेरा मतलब है, हमारे पास अभी भी भारी मूल्य हैं, दोनों पंक्तियां बहुत लंबी हैं, लेकिन प्रभाव ठीक से काम करता है। या मुझे तुम्हारा विचार नहीं मिला, क्या मैंने किया? –

उत्तर

1

कस्टम पिक्सेल शेडर के साथ इसे इंटरमीडिएट बिटमैप बनाना है और फिर उस बनावट को पिक्सेल शेडर द्वारा नमूना मिल जाता है।

आप एक विशाल प्रतिपादन बना रहे हैं, इसलिए आप रेंडर पथ में कुछ सीमा मार रहे हैं।

एक त्वरित सुधार क्लिप करने के लिए इस प्रकार है कि तुम क्या गाया चाहते हैं:

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(); 

अद्यतन:

एक सिद्धांत यह है कि यह बिटमैप पैमाने पर करने के लिए एक फिल्टर का उपयोग कर रहा है जब यह अधिकतम बनावट आकार (से अधिक है जो आपके ग्राफिक्स कार्ड आर्किटेक्चर के आधार पर भिन्न हो सकता है) ... इसलिए यह पिक्सेल शेडर के माध्यम से एक अलग आकार में जाता है .... फिर इसे मूल आकार में वापस ले जाया जाता है।

इस प्रकार स्केलिंग फ़िल्टर आपके बिटमैप की सामग्री के आधार पर कलाकृतियों का कारण बन रहा है (यानी क्षैतिज रेखाएं और ऊर्ध्वाधर रेखाएं एक पैमाने पर जीवित रहती हैं और विकर्ण रेखाओं से बेहतर होती हैं)।

.NET 4 ने उस डिफ़ॉल्ट फ़िल्टर को बदल दिया जो इसे कम गुणवत्ता वाले फ़िल्टरिंग के लिए उपयोग करता है ... बिलीनेर, फंता के बजाय ... शायद यह आपके द्वारा प्राप्त गुणवत्ता को भी प्रभावित करता है।

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

UPDATE2:

की पुष्टि है कि मैं क्या सोच रहा था ऊपर इस प्रकार का।

यदि आप विंडोज प्रदर्शन टूलकिट/सूट (विंडोज एसडीके का हिस्सा) का उपयोग करते हैं, तो आप स्लाइडर वैल्यू को बढ़ाते समय वीडियो मेमोरी को नारंगी ग्राफ में घुमाएंगे क्योंकि एक बड़ा इंटरमीडिएट बिटमैप बनावट बनाई जा रही है। यह तब तक बढ़ता रहता है जब तक यह एक सीमा को हिट नहीं करता है, फिर यह flatlines ... और जब पिक्सेलेशन स्पष्ट हो जाता है।

enter image description here

Update3:

आप सेट करते हैं "सॉफ्टवेयर रेंडरर" (टीयर 0) के लिए मोड प्रस्तुत करना तो आप देख सकते हैं कि यह कैसे प्रतिपादन इतनी बड़ी दृश्य के साथ copes - कलाकृतियों पर प्रदर्शित होने शुरू एक अलग बिंदु .... संभवतः क्योंकि बनावट आकार सीमा आपके GPUs के लिए बड़ी/अलग है। लेकिन कलाकृतियां अभी भी दिखाई देती हैं क्योंकि यह आंतरिक रूप से बिलिनेर फ़िल्टर का उपयोग कर रही है।

रेंडरऑप्शन का उपयोग करने की कोशिश कर रहा है। SetBitmapScalingMode को फ़िल्टर में फ़िल्टर करने के लिए किसी भी तरह से प्रतिपादन गुणवत्ता को बदलने की प्रतीत नहीं होती है (मुझे लगता है क्योंकि यह कस्टम पिक्सेल शेडर पथ के माध्यम से सम्मानित नहीं होता है)।

Application_Startup में इस रखो सॉफ्टवेयर रेंडरर परिणाम देखने के लिए:

RenderOptions.ProcessRenderMode = RenderMode.SoftwareOnly; 
1

ध्यान दें कि छवि सामान्य रूप से लंबवत दिशा में धुंधली होती है, लेकिन क्षैतिज में जाली होती है।

चूंकि शेडर्स रास्टर छवियों पर लागू होते हैं, वेक्टर नहीं, रेखाएं बनावट में रास्टरकृत होती हैं। हार्डवेयर आमतौर पर 8198 * 8192 तक बनावट का समर्थन करता है। मेरे मामले में "धुंधला", जैसा कि आप इसे कॉल करते हैं, 16384 के स्लाइडर मान पर दिखाई देता है। इसलिए, मेरा वर्चुअलबॉक्स आभासी ग्राफिक्स कार्ड 16384 * 16384 तक का समर्थन करता है। आपकी सीमा भिन्न हो सकती है। तो बस इस मान को उससे कम रखें।

लेकिन यह अजीब बात है कि डब्ल्यूपीएफ पूरी छवि को रास्टराइज करता है, क्योंकि इसका केवल छोटा हिस्सा दिखाई देता है। तो एक और संभावित कारण भी है, जो शेडर के अंदर ही है, लेकिन इसे बाइनरी में संकलित किया गया है, इसलिए मैं इसे जांच नहीं सकता।

अद्यतन: with shader applied

ऐसा लगता है कि खड़ी नहीं बल्कि क्षैतिज फ़िल्टर किया जाता है: मेरे मामले में यह इस तरह से लग रहा है।

+0

मैंने अब भी ध्यान दिया है कि आपकी छवि मेरे से अलग दिखती है। कम संकल्प के रूप में आपका दिखता है bilinearly फ़िल्टर। इसका मतलब है कि आपके पास सामान्य जीपीयू है। और यह वर्ग बनावट का उपयोग करता है। मेरे मामले में छवि को फैलाया गया था (धुंधला नहीं है क्योंकि मेरे पास कोई निस्पंदन नहीं है) केवल क्षैतिज रूप से। –

+0

मैंने पहले से ही एलवीएल को समान टिप्पणी पोस्ट कर दी है। यदि दोनों लाइनें विशाल हैं - प्रभाव ठीक से लागू होता है। क्या आप इसे समझा सकते हैं? क्या आप अपनी छवियों को कहीं भी अपलोड कर सकते हैं? –

1

ठीक है, मैं इस मिल गया है! मैंने लाइब्रेरी को आपके ग्रेस्केल प्रभाव से हटा दिया और यह भी जांचने के लिए डब्ल्यूसीएफ प्रेजेंटेशन कोर लाइब्रेरी को डीकंपिल्ड किया कि ब्लरफेक्ट एक ही स्थिति में सही काम करता है। और मैंने पाया कि BlurEffect लागू करता सार विधि Effect.GetRenderBounds जो में अनुपस्थित है GrayscaleEffect। मैंने यह भी देखा कि ग्रेस्केल प्रभाव प्रेजेंटेशनकोर वी 3.0.0 के खिलाफ बनाया गया है जहां प्रभाव GetRenderBound नहीं है।

तो यह WPF के तीसरे और चौथे संस्करणों के बीच एक असंगतता है। वहाँ इसे ठीक करने के तीन तरीके हैं:

  1. आप GrayscaleEffect के स्रोत कोड है - जरूरत विधियां जोड़ें और क्रम की 4.0.0 संस्करण के खिलाफ यह संकलन।
  2. आप रनटाइम को अपने एप्लिकेशन को संस्करण 3 * पर स्विच कर सकते हैं। *।
  3. आप के स्रोतों नहीं है, तो GrayscaleEffect लेकिन क्रम के 3 संस्करण का उपयोग नहीं कर सकते हैं, GrayscaleEffect कि प्रभाव (v4) विरासत और अनुपस्थित तरीकों को लागू करता है के लिए आवरण लिखें।

मैंने दूसरे तरीके की कोशिश की और समस्या गायब हो गई।

+0

_GetRenderBounds_ _ShaderEffect_ में कार्यान्वित किया गया है, जो _GrayscaleEffect_ की मूल श्रेणी है, और इसका कार्यान्वयन _BlurEffect_ के कार्यान्वयन के समान ही है। .NET 4.0 के खिलाफ GrayscaleEffect संकलित करने में मदद नहीं करता है। .NET 3.5 के विरुद्ध संकलन अनुप्रयोग मदद करता है, लेकिन इस तरह से मेरे असली एप्लिकेशन में अस्वीकार्य है। ऐसा लगता है कि यह ढांचे के अंदर समस्या है। –

0

पुराना सवाल, लेकिन कस्टम शेडरफेक्ट को लागू करने के बाद छवि के धुंधले होने में किसी समस्या के लिए उपयोगी हो सकता है।

भी ओपी का उल्लेख प्रस्तुत सामग्री के पैमाने पर जारी किया जा सकता है, मुझे WPFShadersLibrary से वीडियो, टेक्स्ट और सामान्य विंडो के भीतर किसी भी अन्य सामग्री के ShaderEffects को लागू करने के बाद धुंधला होने की समस्या है।

मैंने देखा कि यह छवि एक छोटे से बिट से बदलती है, जिसके परिणामस्वरूप "पिक्सेल विभाजन" होता है, इसलिए मैंने चुने गए शेडरफेक्ट: एक्स ऑफसेट और वाई ऑफसेट के लिए दो नए गुण बनाए, और उन्हें एचएलएसएल (नीचे कोड देखें) में लागू किया, फिर XAML में स्लाइडर से आबद्ध:

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

तो मैं कुछ मनमाने ढंग से ऑफसेट के साथ प्रयोग किया और चित्र पुनः-संरेखित करने में सक्षम था। अभी भी कुछ न्यूनतम धुंधला (या विस्तार से नुकसान) है लेकिन परिणाम काफी बेहतर था।

वर्तमान में इस समाधान के साथ समस्या, मुझे नहीं पता कि संकल्प या विंडो आकार के आधार पर ऑफ़सेट की भविष्यवाणी कैसे करें।

संबंधित मुद्दे