المظللات في OpenGL

تحدثنا في مقالة سابقة عن أساسيات التصوير ثلاثي الأبعاد, والآن سنتحدث بتفصيل أكبر عن المظللات وطريقة عملها.

التصوير هو عملية تحويل بيانات الكائن لصورة, وتتكون هذه العملية من العديد من الأجزاء التي يتحكم كل منها في الشكل النهائي للكائن, ويمكن برمجة بعض هذه الأجزاء لإنتاج الصورة التي نريدها للكائنات, وهذه الأجزاء القابلة للبرمجة تسمى المظللات Shaders, ويتم برمجتها في OpenGL بلغة شبيهة جدًا بلغة ++C تسمى GLSL أو GL Shading Language, ونستطيع كتابة برامج بهذه اللغة بحيث تقوم OpenGL بإدخال المدخلات لها وقراءة نواتج تنفيذها أثناء عملية تصوير الكائن, وتُقسم عملية تصوير الكائن لعدة أقسام تختلف بإختلاف إصدار OpenGL, والصورة التالية تظهر أقسام عملية التصوير حسب الإصدار 4 من OpenGL:

(المصدر GeeksForGeeks.org , تحت رخصة CC BY-SA 4.0)

يهمنا في الصورة السابقة الأقسام الملونة باللون الرمادي وهي المظللات, وسنشرح في هذه المقالة عن المظللين الأساسيين والأكثر استخداماً وهما الأول والأخير.


مظلل النقاط Vertex Shader

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

توفر OpenGL ثلاثة مصفوفات تقوم كل واحدة منها بنقل النقاط من فضاء لفضاء آخر, وهي كالتالي:

  • Model Matrix
  • View Matrix
  • Projection Matrix

 

مصفوفة النموذج Model Matrix

عند ضرب النقطة الموجودة في فضاء الكائن بهذه المصفوفة ستنتج لدينا نقطة تعبر عن مكان النقطة القديمة بالنسبة للعالم (World) الذي يتواجد فيه الكائن.

مصفوفة المَنظور View Matrix

عند ضرب نقطة موجودة في العالم بهذه المصفوفة تنتج نقطة تعبر عن مكان النقطة القديمة بالنسبة للكاميرا.

مصفوفة الإسقاط Projection Matrix

عند ضرب نقطة موجودة بالنسبة للكاميرا بهذه المصفوفة تنتج نقطة تعبر عن مكان النقطة القديمة على الشاشة, وإن وقعت هذه النقطة خارج الشاشة يتم إهمالها. تقع أي من الأبعاد الثلاثة للنقطة بالنسبة للشاشة بين 1- و 1, ويسمى هذا الإحداث Normalized Screen Coordinate.

تتمثل العملية الطبيعية لمظلل النقاط بضرب النقطة الممررة بالمصفوفات الثلاثة السابقة وإعادة الناتج إلى OpenGL, لكن يمكن تخصيص هذا المظلل للتحكم في مكان النقاط, فمثلًا يمكننا كتابة مظلل نقاط لمجسم قلب بحيث يقوم المظلل بمحاكاة حركة القلب في الانقباض مثلاً, ويمكن تحريك النقاط لمحاكاة بعض الحركات (Animations) بالطرق التي تحدثنا عنها في المقالة السابقة, إذ أن تنفيذ جميع المظللات يتم في بطاقة الرسوميات عوضاً عن المعالج مما يخفف عبء تنفيذ الحركات على المعالج وتسمى هذه العملية Hardware Skinning.

 

تجميع الأشكال Primitives Assembly

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

 

التنقيط Rasterization

هو عملية تحديد البيكسلات التي تغطيها الأشكال الأساسية الناتجة من الخطوة السابقة, فعندما يغطي الشكل النقطة الموجودة في منتصف البيكسل يتم تحديد ذلك البيكسل على أنه داخل الشكل الهندسي. يقوم مظلل النقاط في بعض الأحيان بإرسال متغيرات Vertex Attributes إلى مظلل الأجزاء (سنتحدث عنه بعد قليل), وهذه المتغيرات تكون ناتجة عن حسابات أجريت على كل نقطة Vertex, ولكي تعطي OpenGL بعض النعومة تقوم بعملية حسابية لكل بيكسل بحيث يتم عمل تدريج Interpolate للمتغيرات تبعاً لموقع البيكسل بالنسبة للنقاط الثلاثة المكونة للمثلث, فمثلاً إذا إفترضنا في الصورة التالية أن النقطة في أعلى المثلث مررت اللون الأخضر لمظلل الأجزاء, والنقطتين في الأسفل مررتا اللون الأصفر, حينها في عملية التنقيط سيتم مزج اللونين الأخضر والأصفر في كل بكسل حسب قربه أو بعده من باقي النقاط ثم يتم تمرير القيمة الناتجة لمظلل الأجزاء مع بيانات ذلك البيكسل.


مظلل الأجزاء Fragment Shader

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

 

تطبيقات عملية على لغة GLSL

سنقدم الآن أمثلة حقيقية لمظللات مبنية بلغة GLSL, ولغة GLSL لغة شبيهة بلغة ++C و يمكنك قراءة الدليل الخاص بها لتعلمها.

يمكنك عزيزي القارئ تجربة المظللات التالية على موقع ShaderFrog والذي يوفر محرراً للمظللات.

يتم بناء المواد Materials من مجموعة المظللات, وتحوي أي مادة مظللاً للنقاط ومظللاً للأجزاء على الأقل, وسنكتب الآن مظللي النقاط والأجزاء بأبسط صورة ممكنة ونعرض النتيجة.

uniform mat4 modelMatrix;
uniform mat4 projectionMatrix;
uniform mat4 viewMatrix;
attribute vec3 position;
void main() {
  gl_Position = projectionMatrix * viewMatrix * modelMatrix * vec4( position, 1.0 );
}

مظلل النقاط هذا يقوم بضرب متجه المكان position للنقطة بالمصفوفات الثلاثة لتحديد موقع النقطة على الشاشة ثم يعطي النتيجة للمتغير gl_Position والذي ستقوم OpenGL بقراءته.

void main() {
    gl_FragColor = vec4( 0, 0, 1, 1.0 );
}

مظلل الأجزاء هذا يقوم بتمرير اللون الأزرق للمتغير gl_FragColor والذي ستقوم OpenGL بقراءته لتلوين الكائن, وسيكون شكل المجسم كرة إذا طبقنا عليه هذين المظللين كما في الصورة التالية.

فلنجرب الآن اللعب قليلاً بمظلل الأجزاء.

uniform float time;
void main() {
    gl_FragColor = vec4( 0, 0, 1.0, 1.0 ) * abs(sin(time)) + vec4(1.0, 0, 0, 1.0) * abs(cos(time));
}

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



يتضمن: C++ , OpenGL

آخر تحديث: 19-12-2021

الكاتب

رامي عبدالله

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

تعليقات 2

أضف تعليق

يجب تسجيل الدخول حتى تتمكن من إضافة تعليق أو رد.

تقييم المقال

لم تقم بتقييم المقال بعد!

الدورات

أدوات مساعدة

أقسام الموقع

دورات
مقالات كتب مشاريع أسئلة