تقديم الخطوط باستخدام أقنعة التغطية ، الجزء 1

الصورة

عندما بدأنا في تطوير ملف تعريف الأداء الخاص بنا ، عرفنا أننا سنفعل ما يقرب من جميع واجهات المستخدم التي نقدمها بمفردنا. قريباً كان علينا أن نقرر الطريقة التي نختار أن نجعل منها الخطوط. كان لدينا المتطلبات التالية:

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

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

في هذه السلسلة من المقالات ، سأصف بالتفصيل التقنية التي نستخدمها ، مع تقسيم الوصف إلى ثلاثة أجزاء:

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

يمكنك أيضًا رؤية النتائج النهائية في الملف التعريفي ، ولكن فيما يلي مثال على الشاشة مع تقديم الخط Segoe UI باستخدام عارض الخطوط الخاص بنا:


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


الفكرة: تخزين الطلاء بدلاً من الظل


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

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

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

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

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


باختصار على تقنيات تقديم الخط الأساسية


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

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

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


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


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

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

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

ومن المثير للاهتمام ، في حل هذه المشكلة ، ذهب أبل ومايكروسوفت بطرق مختلفة. تلتزم Microsoft بالوضوح المطلق ، وتسعى Apple إلى عرض الخطوط بشكل أكثر دقة. على الإنترنت ، يمكنك العثور على أشخاص يشكون من الخطوط الضبابية على أجهزة Apple ، لكن العديد من الأشخاص يعجبهم ما يرونه على Apple. هذا جزئيا مسألة ذوق. إليكم منشور Joel on Software ، وهنا نشر Peter Bilak حول هذا الموضوع ، لكن إذا بحثت على الإنترنت ، يمكنك العثور على مزيد من المعلومات.

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

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


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

تقديم الصورة الرمزية باستخدام شبكة موحدة


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


الحصول على texels


سنقوم بتحويل نافذة البيكسل بتات التغطية المخزنة في texels. نحتاج إلى الإجابة على السؤال التالي: كم عدد العينات التي ستدخل إلى نافذة البكسل الخاصة بنا؟ يتضح من الصورة التالية:


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

  • احسب الموضع النسبي لنافذة البكسل مقارنةً بـ 4 texels.
  • الحصول على texels لدينا نافذة بكسل يتقاطع مع.

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


الفرق بين الركن الأيسر السفلي من البيكسل والزاوية السفلية اليسرى من شبكة texel هو الموضع النسبي لإطار البيكسل في الإحداثيات العادية. في هذه الصورة ، سيكون موضع نافذة البكسل هو [0.69 ، 0.37]. في الكود:

vec2 bottomLeftPixelPos = uv * size -0.5;
vec2 bottomLeftTexelPos = floor(bottomLeftPixelPos);
vec2 weigth = bottomLeftPixelPos - bottomLeftTexelPos;


باستخدام تعليمة textureGather ، يمكننا الحصول على أربعة texels في وقت واحد. يتوفر فقط في OpenGL 4.0 وأعلى ، لذلك يمكنك تشغيل أربعة texelFetch بدلاً من ذلك. إذا مررنا فقط بإحداثيات textureGather UV ، فعندئذٍ مع وجود تطابق تام لإطار البكسل مع texel ، ستظهر مشكلة:


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

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


توضح هذه الصورة أنه باستخدام مركز شبكة texel ، فإن نقاط أخذ العينات الأربعة التي تم التقاطها بواسطة textureGather ستكون دائمًا في وسط texels. في الكود:

vec2 centerTexelPos = (bottomLeftTexelPos + vec2(1.0, 1.0)) / size;
uvec4 result = textureGather(fontSampler, centerTexelPos, 0);


بكسل نافذة القناع الأفقي


لقد حصلنا على أربعة texels وهم يشكلون معًا شبكة من 8 بتات تغطية. لحساب البتات في إطار البكسل ، نحتاج أولاً إلى إعادة تعيين البتات خارج إطار البيكسل. للقيام بذلك ، سنقوم بإنشاء قناع نافذة بكسل وننفذ bitwise وبين قناع البكسل وأقنعة تغطية texel. يتم تنفيذ إخفاء الأفقي والرأسي بشكل منفصل.

يجب أن يتحرك قناع البكسل الأفقي مع الوزن الأفقي ، كما هو موضح في هذه الرسوم المتحركة:


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


لكي يتحرك القناع فقط في وسط الخلية ، ولكن ليس عند حوافه ، يكفي التقريب البسيط:

unsigned int pixelMask = 0x0F0 >> int(round(weight.x * 4.0));

الآن لدينا قناع بكسل لسلسلة 8 بت كاملة تمتد اثنين من texels. إذا اخترنا نوع التخزين الصحيح في قناع التغطية ذي 16 بت لدينا ، فهناك طرق للجمع بين texel اليسار واليمين وإجراء تقنيع البكسل الأفقي لخط كامل 8 بت في المرة الواحدة. ومع ذلك ، يصبح هذا مشكلة مع التقنيع العمودي عندما ننتقل إلى الشبكات الدوارة. لذلك ، بدلاً من ذلك ، نجمع مع اثنين من texels اليسار الآخر وعلى حدة texels اليمين لإنشاء أقنعة تغطية 32 بت. نحن نخفي النتائج اليمنى واليسرى بشكل منفصل.

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

unsigned int leftRowMask = pixelMask >> 4;
unsigned int rightRowMask = pixelMask & 0xF;
unsigned int leftMask = (leftRowMask << 12) | (leftRowMask << 8) | (leftRowMask << 4) | leftRowMask;
unsigned int rightMask = (rightRowMask << 12) | (rightRowMask << 8) | (rightRowMask << 4) | rightRowMask;


للقناع ، نجمع بين اثنين من texels الأيسر واثنين texels يمين ، ثم نقوم بإخفاء الخطوط الأفقية:

unsigned int left = ((topLeft & leftMask) << 16) | (bottomLeft & leftMask);
unsigned int right = ((topRight & rightMask) << 16) | (bottomRight & rightMask);


الآن قد تبدو النتيجة كما يلي:


يمكننا بالفعل حساب بتات هذه النتيجة باستخدام تعليمة bitCount. يجب ألا نقسم على 16 ، ولكن على 32 ، لأنه بعد القناع العمودي لا يزال لدينا 32 بت محتمل ، وليس 16. هنا هو العرض الكامل للرسومات في هذه المرحلة:


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

اخفاء عمودي


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

سنقوم بإنشاء قناع واحد يغطي كامل ارتفاع اثنين من texels. نتيجة لذلك ، نريد حفظ أربعة خطوط كاملة من texels وقناع جميع الباقي ، أي أن القناع سيكون 4 × 4 بت ، أي ما يعادل 0xFFFF. استنادًا إلى موضع نافذة البكسل ، نقوم بتغيير الخطوط السفلية ومسح الخطوط العلوية.

int shiftDown = int(round(weightY * 4.0)) * 4;
left = (left >> shiftDown) & 0xFFFF;
right = (right >> shiftDown) & 0xFFFF;


نتيجةً لذلك ، قمنا أيضًا بإخفاء البتات الرأسية خارج نافذة البكسل:


الآن يكفي أن نحسب البتات الباقية في texels ، والتي يمكن إجراؤها باستخدام عملية bitCount ، ثم قسّم النتيجة على 16 واحصل على الظل المطلوب!

float shade = (bitCount(left) + bitCount(right)) / 16.0;

الآن يبدو تقديم الرسالة بالكامل كما يلي:


أن تستمر ...


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


وسنرى أن كل هذا تقريبًا يمكن تخفيضه إلى عدة طاولات.

بفضل Sebastian Aaltonen ( SebAaltonen ) لمساعدته في حل مشكلة textureGather ، وبالطبع إلى Michael van der Leu ( MvdleeuwGG ) على أفكاره ومحادثاته المثيرة في الأمسيات.

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


All Articles