مخزن الاستنسل

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

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

في أبسط الحالات، يُستخدم مخزن الاستنسل لتحديد منطقة العرض (الرسم بالاستنسل). أما في الاستخدامات الأكثر تطورًا، فيُستفاد من الارتباط الوثيق بين مخزن العمق (Z-buffer) ومخزن الاستنسل في مسار العرض . على سبيل المثال، يمكن زيادة/إنقاص قيم الاستنسل تلقائيًا لكل بكسل يفشل أو يجتاز اختبار العمق.

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

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

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

يمكن الوصول إلى مخزن الاستنسل ومعدلاته في رسومات الحاسوب باستخدام واجهات برمجة التطبيقات مثل OpenGL و Direct3D و Vulkan أو Metal .

بنيان

يتشارك مخزن الاستنسل عادةً نفس مساحة الذاكرة مع مخزن العمق (Z-buffer)، وتكون النسبة عادةً 24 بت لمخزن العمق + 8 بت لمخزن الاستنسل، أو في السابق 15 بت لمخزن العمق + 1 بت لمخزن الاستنسل. وهناك صيغة أخرى هي 4 + 24، حيث يُستخدم 28 بت من أصل 32 بت ويتم تجاهل 4 بت. يُعد كل من مخزن الاستنسل ومخزن العمق جزءًا من مخزن الإطار ، المرتبط بمخزن اللون. وكانت أول شريحة متاحة لسوق أوسع هي شريحة Permedia II من 3Dlabs ، والتي دعمت مخزن استنسل أحادي البت.

يمكن استخدام البتات المخصصة لمخزن الاستنسل لتمثيل القيم العددية في النطاق [0، 2 ^n - 1]، وكذلك كمصفوفة منطقية (حيث n هو عدد البتات المخصصة)، ويمكن استخدام كل منهما للتحكم في جزء معين من المشهد. كما يمكن الجمع بين هاتين الطريقتين لاستخدام الذاكرة المتاحة.

اختبار الاستنسل

يُعد اختبار الاستنسل أو تطبيق الاستنسل من بين العمليات التي تُجرى على البكسلات/الأجزاء (عمليات لكل بكسل)، ويأتي بعد اختبار ألفا وقبل اختبار العمق . يضمن اختبار الاستنسل عدم وصول البكسلات غير المرغوب فيها إلى اختبار العمق، مما يوفر وقت معالجة المشهد. وبالمثل، يمنع اختبار ألفا وصول البكسلات المقابلة إلى اختبار الاستنسل.

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

وبذلك، يكون رد الفعل المحتمل ناتجًا عن نتيجة مقارنة ثلاثة مستويات مختلفة من عمق الحالة ومخزن الاستنسل:

  • لم يتم اجتياز اختبار الاستنسل
  • اجتاز اختبار الاستنسل، لكنه لم يجتاز اختبار العمق.
  • تم اجتياز كلا الاختبارين (أو تم اجتياز اختبار الاستنسل، ولم يتم تمكين العمق)

في كل حالة من هذه الحالات، يمكن تطبيق عمليات مختلفة على البكسل المُفحوص. في دوال الاستنسل في OpenGL، تُحدد قيمة المرجع والقناع، على التوالي، الدالة glStencilFunc. في Direct3D، يتم ضبط كل مكون من هذه المكونات على حدة باستخدام دوال SetRenderState للأجهزة المتحكم بها حاليًا. تتوقع هذه الدالة مُعاملين، الأول هو الشرط المراد تعيينه، والآخر قيمته. بالترتيب المذكور أعلاه، تُسمى هذه الشروط D3DRS_STENCILFUNC وD3DRS_STENCILREF وD3DRS_STENCILMASK.

تُعدّل عمليات الاستنسل في OpenGL دالة glStencilOp التي تتوقع ثلاث قيم. في Direct3D، تُعيّن كل حالة دالة SetRenderState مُحددة. الحالات الثلاث التي يُمكن تعيينها للعمليات هي: D3DRS_STENCILFAIL و D3DRENDERSTATE_STENCILZFAIL و D3DRENDERSTATE_STENCILPASS.

قتال الزومبي

بسبب عدم دقة مخزن العمق (Z-buffer)، قد تظهر المضلعات المستوية قصيرة المدى أو المتداخلة كسطح مستوٍ واحد ذي مقاطع عرضية غير منتظمة متعددة. وتختلف هذه المقاطع تبعًا لموقع الكاميرا وعوامل أخرى، وتتغير بسرعة. يُعرف هذا بظاهرة "التداخل بين العمق والعمق" (Z-fighting). توجد حلول متعددة لهذه المشكلة:

- تقريب المستوى البعيد لتقييد عمق المشهد، وبالتالي زيادة دقة مخزن العمق (Z-buffer)، أو تقليل المسافة التي تكون عندها الكائنات مرئية في المشهد.

- زيادة عدد البتات المخصصة لمخزن Z، وهو أمر ممكن على حساب الذاكرة المخصصة لمخزن الاستنسل.

- تحريك المضلعات بعيدًا عن بعضها البعض، مما يحد من إمكانيات الفنان لإنشاء مشهد متقن.

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

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

حجم الظل

حجم الظل هو تقنية تُستخدم في رسومات الحاسوب ثلاثية الأبعاد لإضافة الظلال إلى المشهد المُصوَّر. وقد اقترحها فرانك كرو لأول مرة عام 1977 [ 2 ] باعتبارها هندسة تصف الشكل ثلاثي الأبعاد للمنطقة المحجوبة عن مصدر الضوء. يقسم حجم الظل العالم الافتراضي إلى قسمين: مناطق مظللة ومناطق غير مظللة.

يُعتبر تطبيق تقنية مستودع الاستنسل لإنشاء أحجام الظلال من بين أكثر تقنيات التظليل العملية للاستخدام في الوقت الحقيقي على أجهزة الرسومات ثلاثية الأبعاد الحديثة. وقد اشتهرت هذه التقنية بفضل لعبة الفيديو Doom 3 ، وأصبح أحد أشكالها المستخدمة في هذه اللعبة يُعرف باسم "Carmack's Reverse" .

تأملات

يتم رسم انعكاس المشهد عن طريق تحويل المشهد نفسه وانعكاسه بالنسبة إلى مستوى "المرآة"، الأمر الذي يتطلب تمريرات عرض متعددة واستخدام مخزن الاستنسل لتقييد المناطق التي تعمل فيها تمريرة العرض الحالية:

  1. ارسم المشهد باستثناء مناطق الانعكاس – لكل انعكاس، قم بقفل مخزن العمق (Z-buffer) ومخزن اللون (color buffer)
    1. اجعل الجزء المرئي من المرآة مرئيًا
    2. تم إعداد اختبار العمق بحيث يتم تمرير كل بكسل لإدخال القيمة القصوى وينجح دائمًا
  2. لكل مرآة:
    1. تم ضبط اختبار العمق بحيث ينجح فقط إذا كانت مسافة البكسل أقل من المسافة الحالية (السلوك الافتراضي).
    2. يتم تغيير تحويل المصفوفة ليعكس المشهد بالنسبة لمستوى المرآة
    3. قم بإلغاء قفل مخزن العمق (Z-buffer) ومخزن الألوان (color buffer).
    4. ارسم المشهد، ولكن فقط الجزء الواقع بين مستوى المرآة والكاميرا. بعبارة أخرى، مستوى المرآة هو أيضًا مستوى قص.
    5. يتم قفل مخزن الألوان مرة أخرى، ويتم ضبط اختبار العمق بحيث ينجح دائمًا، ثم يتم إعادة ضبط الاستنسل للمرآة التالية.

الظلال المستوية

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

مشكلة أخرى، قد تظهر أو لا تظهر حسب التقنية المستخدمة، هي تصميم عدد أكبر من المضلعات في جزء واحد من الظل، مما ينتج عنه أجزاء داكنة وأخرى فاتحة من نفس الظل. يمكن حل المشاكل الثلاث هندسيًا، ولكن نظرًا لإمكانية استخدام تسريع الأجهزة مباشرةً، فإن استخدام مخزن الاستنسل يُعدّ حلاً أكثر أناقة: 1. تفعيل الإضاءة. 2. رسم مشهد بدون أي مضلع يُراد إسقاط الظلال عليه. 3. رسم جميع المضلعات التي يُراد إسقاط الظلال عليها، ولكن بدون إضاءة. عند القيام بذلك، يتم تعيين قيمة محددة لكل بكسل في مخزن الاستنسل، وذلك للأرضية التي ينتمي إليها. يجب أن تكون المسافة بين هذه القيم اثنين على الأقل، لأنه لكل مستوى، تُستخدم قيمتان لحالتين: في الظل والإضاءة. 4. تعطيل أي إضاءة عامة (لضمان أن الخطوات التالية ستؤثر فقط على الإضاءة المحددة). لكل مستوى: لكل إضاءة: 1. تعديل مخزن الاستنسل، وتحديد البكسلات التي تحمل قيمة محددة للمستوى المحدد فقط. قم بزيادة قيمة جميع البكسلات التي تمثل الكائنات المسقطة بين تاريخ مستوى معين وقيمة سطوع معينة. 2. اسمح فقط للضوء المحدد برسم المستوى الذي لم تتغير فيه قيمة جزء من قيمته المحددة.

الظلال المكانية

يُعرَّف تطبيق الظلال المكانية باستخدام مخزن الاستنسل بأنه أي ظل لجسم هندسي يشمل حجمه جزءًا من المشهد الموجود فيه. إذا كان أي جزء من المشهد ينتمي إلى هذا الحجم، فلن يتم إضاءة أي جزء منه، وإلا فسيتم إضاءته. تتفاقم هذه المشكلة مع زيادة عدد مصادر الإضاءة، لكنها لا تعالج عدد المناطق التي تسقط عليها الظلال. توجد عدة حلول لهذه المشكلة، لكننا اتبعنا الخوارزمية التالية: 1. رسم مشهد بدون إضاءة. 2. قفل مخزن العمق (Z-buffer) ومخزن اللون، بحيث لا يمكن إجراء أي تغييرات عليهما. لكل مصدر إضاءة: 1. استخدام معلومات تفصيلية عن المشهد (مخزن العمق) لملء مخزن الاستنسل فقط في أجزاء المشهد التي لا يوجد بها ظل حجمي أو غير مرئية من المباني الموجودة. 2. إلغاء قفل مخزن اللون، وضبط وظيفة مخزن العمق للسماح بالتعديلات فقط عندما تكون قيمة العمق مساوية لقيمة موجودة. 3. رسم المشهد مضاءً فقط بهذا المصدر، ولكن فقط لجزء المشهد الذي يجتاز اختبار الاستنسل.

تشير كل فقرة من هذه الفقرات إلى إمكانية استخدام مخزن استنسل نظيف.

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

تطبيقات أخرى

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

يتضمن تطبيق آخر مجال التصور أثناء تقنية نمذجة المواد الصلبة Constructive Solid Geometry (CSG)، حيث يمكن لمخزن الاستنسل، جنبًا إلى جنب مع مخزن Z، حل مشاكل العمليات المنطقية لـ SOLiD بنجاح.

تُستخدم مخازن الاستنسل أيضًا في برامج العرض المؤجلة لتمييز أو رفض وحدات البكسل التي لا يمكن أن يؤثر عليها ضوء معين، مما يقصر عملية الإضاءة على حجم الضوء أو وحدات البكسل الأخرى ذات الصلة؛ وتنفذ بعض التطبيقات ذلك من خلال تمرير استنسل مبكر على هندسة حجم الضوء للتخلص من العديد من الأجزاء قبل الإضاءة. [ 3 ] [ 4 ]

OpenGL

glEnable ( GL_STENCIL_TEST ); // غير مُفعّل افتراضيًا. glStencilMask ( stencilMask ); // السماح بالكتابة إلى مخزن الاستنسل، افتراضيًا (0xFF) بدون قناع. glClearStencil ( clearStencilValue ); // مسح قيمة الاستنسل، افتراضيًا = 0. glStencilFunc ( func , ref , mask ); // افتراضيًا GL_ALWAYS، 0، 0xFF، اجتياز اختبار الاستنسل دائمًا. glStencilOp ( fail , zfail , zpass ); // افتراضيًا GL_KEEP، GL_KEEP، GL_KEEP، عدم تغيير مخزن الاستنسل. glClear ( GL_STENCIL_BUFFER_BIT ); // مسح مخزن الاستنسل، وملؤه بـ (clearStencilValue & stencilMask).

اختبار: (مرجع وقناع) دالة (قيمة الاستنسل وقناع)

وذلك تبعاً للشروط الثلاثة المحتملة لوظيفة الاستنسل/وظيفة العمق.

1. فشل وظيفة اختبار الاستنسل:

 إذا كانت قيمة func هي GL_NEVER، فسيفشل اختبار الاستنسل دائمًا. لم يتم تعديل أي من مخزني الألوان/العمق. تم تعديل مخزن الاستنسل وفقًا لفشل glStencilOp. إذا استخدمنا الأمر glStencilOp(GL_REPLACE, GL_KEEP, GL_KEEP)، فسيتم تنفيذ GL_REPLACE و stencilValue = (ref & stencilMask) // سيصبح ref

2. نجاح وظيفة اختبار الاستنسل / فشل وظيفة اختبار العمق:

 إذا كانت الدالة على سبيل المثال GL_ALWAYS، فسوف ينجح اختبار الاستنسل دائمًا، ولكن قد يفشل اختبار العمق. لم يتم تعديل أي من مخزن الألوان/مخزن العمق. تم تعديل مخزن الاستنسل وفقًا لـ glStencilOp zfail. إذا استخدمنا الأمر glStencilOp(GL_KEEP, GL_INCR, GL_KEEP)، فسيتم تنفيذ GL_INCR و قيمة الاستنسل = (قيمة الاستنسل + 1) // ستصبح 1

3. تمريرات وظيفة الاستنسل / تمريرات وظيفة العمق:

 إذا كانت قيمة الدالة GL_ALWAYS، فسينجح اختبار الاستنسل دائمًا. وينطبق الأمر نفسه إذا نجح اختبار العمق. تم تعديل كل من مخزن اللون/مخزن العمق. تم تعديل مخزن الاستنسل وفقًا لـ glStencilOp zpass. إذا قلنا، glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP) فلن تتغير قيم الاستنسل، بل سيتم تعديل اللون ومخازن Z فقط.

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

// تعطيل الألوان ومخازن العمق glColorMask ( GL_FALSE , GL_FALSE , GL_FALSE , GL_FALSE ); glDepthMask ( GL_FALSE );glStencilFunc ( GL_NEVER , 1 , 0xFF ); // عدم اجتياز اختبار الاستنسل glStencilOp ( GL_REPLACE , GL_KEEP , GL_KEEP ); // استبدال قيم مخزن الاستنسل إلى ref=1 glStencilMask ( 0xFF ); // تحرير مخزن الاستنسل للكتابة glClear ( GL_STENCIL_BUFFER_BIT ); // مسح مخزن الاستنسل أولاً بكتابة قيمة الاستنسل الافتراضية (0) إلى كامل مخزن الاستنسل. draw_stencil_shape (); // عند مواقع بكسل شكل الاستنسل في مخزن الاستنسل، يتم استبدال قيم مخزن الاستنسل إلى ref = 1

الآن استخدم مخزن الاستنسل المُهيأ واختبار الاستنسل للكتابة فقط في المواقع التي تكون فيها قيمة الاستنسل 1:

// تفعيل الألوان ومخازن العمق. glColorMask ( GL_TRUE , GL_TRUE , GL_TRUE , GL_TRUE ); glDepthMask ( GL_TRUE );// لا حاجة لتعديل مخزن الاستنسل في تمريرة الاستنسل والعمق. glStencilMask ( 0x00 ); // يمكن تحقيق ذلك أيضًا باستخدام glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);// اختبار الاستنسل: يتم اجتياز اختبار الاستنسل فقط عند قيمة stencilValue تساوي 1 (بافتراض نجاح اختبار العمق). // وكتابة المحتوى الفعلي إلى مخزن العمق ومخزن اللون فقط في مواقع شكل الاستنسل. glStencilFunc ( GL_EQUAL , 1 , 0xFF ); draw_actual_content ();

انظر أيضاً

مراجع

  1. "تقنيات مخزن الاستنسل (Direct3D 9) - تطبيقات Win32" .
  2. كرو، فرانكلين سي: "خوارزميات الظل لرسومات الحاسوب"، رسومات الحاسوب (وقائع SIGGRAPH '77) ، المجلد 11، العدد 2، 242-248.
  3. راستي كونس. "الفصل 19. التظليل المؤجل في تابولا راسا" . مطورو NVIDIA / جواهر وحدة معالجة الرسومات 3.
  4. إيان د. رومانيك. "VGP352 - الأسبوع 10: التظليل المؤجل" (ملف PDF) . إيان د. رومانيك / FreeDesktop.org.