GLSL: مركز أو Centroid؟ أو عندما تهاجم تظليل

عند تعديل التظليل للعبة القادمة ، صادفت قطعة أثرية غير سارة تظهر فقط عند تشغيل الجهاز MSAA. في لقطة شاشة المشهد ، يمكنك رؤية عدد قليل من وحدات البكسل الساطعة. كانت قيم اللون في العديد منها كبيرة جدًا بعد تحولها إلى "أشباح" متعددة الألوان.

الصورة

أوجه انتباهكم إلى ترجمة مقالة تشرح بالتفصيل سبب هذه الظاهرة وطريقة التعامل معها.

الصورة

الشكل 1 - الصور الصحيحة (يسار) وغير صحيحة (يمين). انتبه إلى الشريط الأصفر في الحافة اليسرى للصورة "غير الصحيحة". على الرغم من أن متغير myMixer يختلف من 0 إلى 1 ، إلا أنه يتخطى هذا النطاق بطريقة ما في الصورة "غير الصحيحة".

فكر في شظية شظية بسيطة مع تحول بسيط غير خطي:

smooth in float myMixer; //      . //  sqrt    . void main( void ) { const vec3 blue = vec3( 0.0, 0.0, 1.0 ); const vec3 yellow = vec3( 1.0, 1.0, 0.0 ); float a = sqrt( myMixer ); //    myMixer < 0.0 vec3 color = mix( blue, yellow, a ); //   gl_FragColor = vec4( color, 1.0 ); } 

من أين أتى الشريط الأصفر على اليسار في الصورة غير الصحيحة؟ لفهم الخطأ الذي حدث بشكل أفضل ، دعونا ننظر أولاً إلى الحالة التي يعمل فيها كل شيء بشكل صحيح (تقريبًا) دائمًا.

الصورة

هذا هو تنقيط الكلاسيكية مع عينة واحدة. المربعات الرمادية هي بكسل ، والنقاط الصفراء هي مراكز البكسل الموجودة في إحداثيات نافذة نصف عدد صحيح (بشكل افتراضي ، تكون إحداثيات بكسل اليسار السفلي في gl_FragCoord (0.5 ، 0.5) - trans. ).

الصورة

في الصورة أعلاه ، يفصل الخط الثانوي نصف مساحة البدائية. أعلى وإلى يسار هذا الخط ، يكون المتغير myMixer موجبًا ، وأسفل ويمينًا سلبيًا.

يصنف التنقيط أحادي العينة الكلاسيكي البيكسلات وفقًا للعضوية البدائية ، ويخلق أجزاء فقط للبكسلات التي تقع مراكزها داخل البدائية. في هذا المثال ، سيتم إنتاج ستة أجزاء ، تظهر في أعلى اليسار. لا تندرج البيكسلات ذات اللون الصامت في البدائية. لن يتم إنشاء شظايا لهم.

الصورة

يشير اللون الأخضر إلى النقاط التي سيتم فيها احتساب تظليل القطعة. سيتم احتساب قيمة myMixer لمركز كل بكسل. لاحظ أن النقاط الخضراء أعلى وعلى يسار السطر ، لذلك ستكون قيم myMixer فيها إيجابية. جميع بيانات الإدخال المرتبطة بالقمم (متغيرات متغيرة أو متداخلة / خارجية) سيتم استيفائها أيضًا في هذه النقاط.

لا يستخدم تظليلنا البسيط المشتقات (صريحة أو ضمنية ، على سبيل المثال ، عند أخذ عينات من نسيج بمستويات mip) ، ولكن يتم تمييز المشتقات dFdx (أفقي) و dFdy (عمودي) بالسهام. داخل البدائية ، فهي محددة بشكل جيد ومنتظم.

لتلخيص: في اختيار واحد ، يتم إنشاء الأجزاء فقط إذا وقع مركز البيكسل "داخل" البدائية ، ويتم حساب بيانات الجزء لمركز البيكسل ، ويتم إجراء استيفاء بيانات قمة الرأس وحساب التظليل فقط داخل البدائية. كل شيء جيد و "صحيح". (دائمًا تقريبًا. في الوقت الحالي ، دعنا نتجاهل عدم دقة بعض المشتقات على البكسلات على طول الحدود البدائية).

لذلك ، كل شيء (تقريبا) ممتاز في التنقيط مع اختيار واحد. ولكن ما الذي يمكن أن يحدث عندما يتم تشغيل multisampling؟

الصورة

هذا هو تنقيط multisampling الكلاسيكية. المربعات الرمادية تشير إلى بكسل. النقاط الصفراء هي مراكز بكسل بإحداثيات نصف عدد صحيح. عند النقاط الزرقاء ، يحدث أخذ العينات. يوضح هذا المثال مخططًا بسيطًا لعينتين مستديرتين. يمكن تعميم جميع الحجج لعدد تعسفي من العينات.

الصورة

الخط لا يزال يفصل بين نصف مساحة البدائية. أعلى وإلى يسارها ، قيمة myMixer إيجابية. أقل وإلى اليمين - سلبية.

عند التنقيط بأخذ عينات متعددة ، يقوم مصنف البيكسل بإنشاء جزء في حالة وجود عينة بكسل واحدة على الأقل داخل البدائية.

في هذا المثال ، سيتم إنشاء 10 أجزاء ، كما هو موضح في النصف العلوي الأيسر. لاحظ الأجزاء الأربعة المضافة على طول الوجه ، والتي تقع فيها عينة واحدة داخل البدائية ، على الرغم من أن المركز خارج. بكسل خارج البدائية لا تزال باهتة.

الصورة

ماذا سيحدث عند الحساب في مركز البكسل؟

سيتم حساب التظليل في نقاط خضراء وحمراء لكل جزء من الأجزاء. يتم حساب البيانات المرتبطة myMixer في وسط كل بكسل. في النقاط الخضراء ، ستكون هذه القيم إيجابية ، لأنها أعلى وعلى يسار الحدود. النقاط الحمراء هي خارج البدائية ، لأن قيم myMixer فيها سلبية. عند النقاط الحمراء ، يتم استقراء البيانات المرتبطة بدلاً من الاستيفاء.

في التظليل الخاص بنا ، لا يتم تعريف قيم sqrt (myMixer) باستخدام myMixer سلبي. حتى عندما تكمن قيم myMixer المسجلة بواسطة تظليل قمة الرأس في الفاصل الزمني من صفر إلى واحد ، في تظليل الشظية قد يتجاوز myMixer هذا الفاصل بسبب الاستقراء. وبالتالي ، مع myMixer سلبي ، لم يتم تعريف نتيجة تظليل جزء.

الصورة

ما زلنا نفكر في حساب التظليل في مراكز البيكسلات ، وتظهر الأسهم في الشكل dFdx و dFdy. في الأجزاء الداخلية للمضلع ، يتم تعريفها جيدًا نظرًا لأن جميع العمليات الحسابية تتم في مراكز البكسل الموجودة في فواصل زمنية متساوية.

الصورة

ماذا سيحدث عند حساب نقاط أخرى غير مراكز البكسل؟

النقاط الخضراء هي النقاط التي سيتم فيها حساب التظليل. يتم حساب القيمة المرتبطة myMixer في النقطه الوسطى من كل بكسل.

النقطة الوسطى من البيكسل هي مركز ثقل تقاطع مربع البيكسل والداخلية للبدائية. بالنسبة للبكسل المغطى بالكامل ، فإن الوسط هو المركز. بالنسبة للبكسل المغطى جزئيًا ، يختلف الوسط النقطي عادة عن الوسط.

يسمح معيار OpenGL للتطبيق بتحديد نقطة تعسفية عند تقاطع البدائية والبكسل بدلاً من centroid المثالي. على سبيل المثال ، يمكن أن تكون نقطة أخذ العينات.

في هذا المثال ، إذا كان المركز يقع داخل البدائية ، يتم حساب بيانات قمة الرأس للمركز. خلاف ذلك ، يتم حسابها في أي من نقاط العينة التي تقع داخل البدائية. يحدث هذا لأربعة بكسل على طول الحدود. تقع جميع النقاط الخضراء فوق وعلى يسار الحدود ، لذلك يتم دائمًا تقريب القيم الموجودة فيها ولا يتم استنباطها مطلقًا.

لماذا لا تحسب دائما تظليل النقطه الوسطى؟ بشكل عام ، هو أكثر تكلفة من الحوسبة في المركز. ومع ذلك ، ليس هذا هو العامل الرئيسي.

كل شيء عن حساب المشتقات. انتبه إلى الأسهم بين النقاط الخضراء. المسافة بينهما ليست هي نفسها بالنسبة لأزواج مختلفة من النقاط. بالإضافة إلى ذلك ، y غير ثابت لـ dFdx ، و x غير ثابت لـ dFdy. المشتقات تكون أقل دقة عند حسابها في النقط الوسطى .

هذا حل وسط ، وبالتالي فإن OpenGL ، بدءًا من GLSL 1.20 ، يوفر لمطوّر التظليل إمكانية الاختيار بين المركز والنترويد باستخدام مؤهل centroid:

 centroid in float myMixer; //  centroid  smooth //      . //  sqrt    . void main( void ) { const vec3 blue = vec3( 0.0, 0.0, 1.0 ); const vec3 yellow = vec3( 1.0, 1.0, 0.0 ); float a = sqrt( myMixer ); //    myMixer < 0.0 vec3 color = mix( blue, yellow, a ); //   gl_FragColor = vec4( color, 1.0 ); } 

متى يجب عليك استخدام النقطه الوسطى؟

  1. عندما يمكن أن تؤدي القيمة المستقاة إلى نتائج غامضة. إيلاء اهتمام خاص للوظائف المدمجة ، والتي وصفها "النتيجة غير محددة إذا ..."
  2. عند استخدام قيمة استقراءية مع وظيفة غير خطية أو متقطعة جدًا. يتضمن ذلك دالة الخطوة أو حساب التوهج ، خاصةً عندما يكون الأس كبيرًا بدرجة كافية.

متى يجب ألا تستخدم centroid؟

  1. إذا كنت بحاجة إلى مشتقات محددة. يمكن أن تكون المشتقات إما صريحة (استدعاء dFdx) أو ضمنية ، على سبيل المثال ، عينات من مواد ذات مستويات mip أو مع ترشيح متباين الخواص. في مواصفات GLSL ، تعتبر المشتقات في النقط الوسطى غير صالحة للاستعمال بحيث يتم إعلانها غير محددة. في مثل هذه الحالات ، حاول أن تكتب:

     centroid in float myMixer; //  ! smooth in float myCenterMixer; //     . 

  2. إذا تم تقديم شبكة تكون فيها معظم حدود البدائية داخلية ومحددة جيدًا دائمًا. أبسط مثال على ذلك هو شريط مكون من 100 مثلث (TRIANGLE_STRIP) ، يكون فيه المثلثات الأولى والأخيرة فقط عرضة للاستقراء. سينتج عن تصفيات centroid الاستيفاء على هذين المثلثين على حساب فقدان الدقة والاستمرارية في المثلثات 98 المتبقية.
  3. إذا كنت تعلم أن القطع الأثرية قد تظهر من وظيفة غير محددة أو غير خطية أو غير متصلة ، ولكن في الممارسة العملية ، تصبح هذه القطع الأثرية غير مرئية تقريبًا. إذا كان تظليل لا يهاجم - لا إصلاحه!

Source: https://habr.com/ru/post/ar434046/


All Articles