خاصية التحويل : دورة OpenGL لغة c++ الدرس العاشر


خاصية التحويل هي إحدى المهام التي تستند عليها مكتبة OpenGL في الوصول إلى مشاهد عرض متعددة وغنية عن التعريف. لقد تمكننا في الدروس السابقة من إضافة كائنات وتعديل الألوان مع تمكين بعض خصائص المظهر على البرامج وهذا أمر جيد.[1]لكن لا تزال بعض المهام تفتقر إلى التفاعل مع بعضها البعض نظرا للمتغيرات الثابتة.[1] خاصية التحويل تمنحك إمكانية التعديل والتغيير على الإحداثيات , بالتالي إعادة ضبط المخزنات buffers في كل إطار جديد.

يعتبر ذلك صعب للغاية دون وجود مكتبة OpenGL وذلك لأنها وفرت لنا طرق متعددة لإجراء خاصية التحويل على الكائنات باستخدام المصفوفات المتعددة.[1]

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


 

يعتبر هذا الدرس بمثابة مهارات رياضية قبل البدء في التطبيق , لذا يتطلب منك التركيز جيدًا.

 


المتجهات (Vectors)



لا يتم التعبير عن المتجهات بأكثر من اتجاهات لحدود الرسم, بينما يتم الإشارة إلى magnitude بأنها معايير للقوة أو طول المتغير. يمكنك حقا إدراك بأن المتجهات هي اتجاهات مستمرة على الخريطة.[1] على سبيل المثال وعلى أرض الواقع تعبر الشوارع في المدن عن متجهات ثابتة تسير عليها المركبات.[1]

هناك بعض الشوارع تتطلب منك المسير على نحو 2 كم ثم الاتجاه يمينا ثم إلى اليسار وثم الوقوف.[1] وكذلك الأمر بالنسبة للمتجهات. حيث أنها تقوم بذلك الدور لكن على فضاء شاشة العرض ليس إلا.[1]

عند الخوض في خاصية التحويل ستدرك أنا المتجه يتكون من ثلاثة متغيرات من نوع vector ويشار إليها بالأبعاد. وفي حال استخدام متغير من نوع vec2 فإن ذلك يشير إلى كائن ثنائي الأبعاد.[1] بينما في حال العمل على vector ثلاثي أو رباعي , فإن ذلك يفيد بعالم ثلاثي الأبعاد.[1]

تختلف طريقة استخدام المتجهات وفقا للمشهد و النموذج المطبّق , على سبيل المثال تشير الإحداثيات XYZ إلى متجه ثلاثي الأبعاد.[1] تقوم كل من حزمة المتغيرات بتحديد الإتجاهات لكن تبقى  نقطة الأصل ثابتة دون تغيير ويشار إليها بمصطلح Origin.[1]

يتم وصف المتجهات في خاصية التحويل على أنها قيم يتم التأثير فيها وفقًا لطبيعة المشهد. ويتم الإشارة إلى نقطة الأصل بالإحداثيات (0,0,0) أو (0,0) في عرض 2D.[1] وعلى فرض أننا قمنا بتعيين متجه بقيمتي (3,5) فإن ذلك يشير إلى نقطة النهاية في حين أن نقطة الأصل هي (0,0).[1]


خاصية التحويل للعمليات الحسابية


تخضع المتجهات إلى المعاملات الرياضية متمثلة بالجمع والطرح والضرب والقسمة.[1] حيث أن scalar هو عدد فردي يتكون من عنصر واحد فقط.[1] عند إجراء العمليات الحسابية على متجه فإن العملية تنطبق على كامل العناصر الموجودة , بالتالي يجب أن يتم مطابقة العناصر.[1]

 

لا يمكن إجراء عمليات حسابية على متجهات غير متطابقة إلا في حالات خاصة تتعلق بالمتجه ذاته , على سبيل المثال لا تستطيع القيام بجمع متجه vec2 مقابل vec3.

 

لا بد لنا من الإشارة بأن المتجهات تقبل إجراء العمليات الحسابية على قيم مطلقة أو سالبة.[1] على سبيل المثال عند إجراء عملية جمع على إحدى قيم المتجه 1 + (-4)  فإن النتيجة ستكون هي – 3 بناء على قوانين رياضية قديمة.[1]

 


طول المتجه



يتبع طول المتجه منطق Pythagoras theorem في استخدام الرياضيات و لتبسيط المسألة أكثر فأكثر يتم استخدام الجذر التربيعي لكل من مجموع عناصر XY تربيع.[1] على سبيل المثال , تخيل أن لدينا متجه يتكون من قيمة x=4 و  y = 2 , فإن تربيع القيمتين سينتج لدينا x = 16 و y = 4 وبالتالي فإن نتيجة جمع المتغيرات تحت الجذر تنتهي بالقيمة 4.47.[1]

سوف يتم استخدام الجذر التربيعي كثيرًا في عملية استخراج طول المتجهات.[1]

 


المتجه الواحدي



عند استخدام خاصية التحويل لا بد أن نتطرق إلى استخدام المتجه الواحدي , حيث أنه خاصية إضافية يتم الوصول لها عن طريق قسمة المتجه على القيمة الناتجة من استخراج الطول له.[1] على سبيل المثال , فإن قيمة unit vector لإحدى المتجهات هي ناتج قسمة المتجه x = 4 و y = 2 على ناتج الطول 4.47 الذي حصلنا عليه عن طريق الجذر التربيعي.[1]

 


خاصية Dot product



يتم استخدام dot product كثيرا في خاصية التحويل فهي ليست ناتج ضرب المتجهات ببعضها فحسب. بينما تعتمد على ضرب متجهين بعضهما البعض بالإضافة إلى ضرب الناتج في جيب تمام الزاوية.[1] بالتالي يمكن الإشارة إلى الزاوية الواقعة بين المتجهات بـ theta بينما تساعد عملية dot product في تحديد الزاوية بين هذين المتجهين.[1]

 


استخراج Cross product



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

يؤدي احتساب Cross product إلى الخوض في الجبر الخطي المعقد , وبذلك يعتمد هذا العلم على معادلة واحدة فقط إن أدركتها سوف يسهل العمل عليها ببقية مراحل التطوير.[1]

 


 خاصية التحويل والمصفوفات



تمثل المصفوفات عامل مهم عند إجراء خاصية التحويل على المشهد , فهي باختصار مصفوفة مستطيلة من الأرقام يطلق على كل قيمة بداخلها عنصر أو Element.[1] على سبيل المثال , على فرض أن هناك مصفوفة 2X3 فإن ذلك يعني أنها مكونة من صفين وثلاث أعمدة. وكذلك الأمر بالنسبة لأنواع أخرى منها.[1]

في الجبر الخطي يتم الإشارة إلى الصفوف بالحرف i بينما يدل الحرف j على الأعمدة. وتدل المصفوفة 2X3 على أبعاد ثنائية حيث تدل الصفوف على ذلك.[1]

عند العمل بالمصفوفات في خاصية التحويل يتطلب منا الأمر القيام ببعض العمليات الحسابية مثل جمع رقم أو طرح رقم.[1] ونضع في الحسبان أن عمليات الجمع والطرح تتطلب إجراء تغيير على جميع العناصر. على سبيل المثال , لو قمنا لو أن لدينا المصفوفة 2X3 فإن جمع عنصر سيتطبق على جميع عناصرها في الصف الأول والثاني منها , وكذلك الأمر بالنسبة للمصفوفات الثلاثية.[1]

 

عادة ما يتم استخدام مصفوفة 4X4 لأسباب عديدة وأهمها العمل في المصفوفات الرباعية مع ضرورة وجود Identity matrix.[1] حيث أنها مصفوفة يتم تطبيق معادلات الرسم عليها في شتى نماذج العرض.[1]

 

وقد تتساءل عن مدى أهمية Identity matrix في المشروع بينما في الحقيقة تشير إلى نقطة البداية في الفضاء التي سيتم نثر النماذج بداية منها. ستجد في جميع برامج الرسم الرسومية مثل محرك يونيتي و غيرها نقطة البداية دائمًا تقع في وسط الفضاء لكن هي في الحقيقة إحداثية  Identity matrix. التي يتم من خلالها عمليات تحريك النماذج وصقلها في المشروع.[1]


خاصية التحجيم (Scaling)



يعد التحجيم أحد أشهر العمليات التي يتم استخدامها في خاصية التحويل وعند تحجيم المصفوفات فإنه في غالب الأمر يتم إجراء زيادة على طول متغيراتها في الإحداثيات مع بقاء الاتجاه كما هو في الفضاء. وبالتالي يتم إجراء التحجيم على جميع الإحداثيات متمثلة بــ عناصر XYZ.[1]

نضع في الحسبان بأن مكتبة OpenGL تتعامل مع التحجيم في عناصر 2D و 3D وفي حال تم إجراء التحجيم على إحداثيات 3D فإن العنصر Z سيتأثر بذلك أيضًا.[1]

 


الإزاحة (Translation)



تتمثل خاصية التحويل في عمليات الإزاحة أيضًا وهي إجراء حسابي بسيط يقوم بإضافة متجه آخر إلى نقطة الأصل ليضع الكائن في مكان مختلف.[1]

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

 

لا يتم تطبيق خاصية الإزاحة transition على متجهات 3X3 من المصفوفات بينما يتطلب مصفوفة تدعم أبعاد رباعية تدعم أبعاد المشهد w.[1]

 


التدوير (Rotation)



يعد التدوير إحدى أدوار خاصية التحويل وهو صعب الإستخدام ويعاني جميع المبرمجين من ذلك , هو يتعلق في الجبر الخطي على وجه التحديد.[1] لا بد أن ندرك بأن تدوير المتجهات مرتبط بزاوية تأخذ درجات من الدائرة الواحدية وقوانينها. البعض من المطورين يعمل بقيمة الــ PI بينما البعض الآخر يفضل الدرجات radians عوضًا عنها.[1]

التدوير بمعدل نصف دائرة يعني قسمة الدرجات 360 على 2 ليعطينا الناتج 180 درجة والتدوير بمقدار الخمس يعني قسمة 360 درجة على 5 ليظهر الناتج 72 درجة.[1] وبالتالي فإن التدوير في عالم 3D معلوم بإجراء التعديل على إحداثيات x فهي تقوم بتدوير الكائن على محور السينات.[1]

لكن يختلف الأمر قليلا عند تدوير متجهات ثنائية البعد 2X2 في فضاء 3D حيث يتم إجراء التغيير على إحداثيات محور z من الرسم.[1]

يعتبر استخدام علم المثلثات طريقا شائعا في خاصية التحويل التي تطرأ على عمليات Rotation وذلك استنادا على الزاوية الواقعة على النموذج.[1] وبالتالي يتم استخدام طرق ذكية في دمج وظائف جيب وجيب تمام الزاوية على الكائن. على سبيل المثال فإن تدوير المصفوفة يعتمد بشكل أساسي على محاور الرسم جميعها في الفضاء 3D عندما تمثل الزاوية منطقة theta.[1]

باستخدام مصفوفات التدوير نستطيع إجراء خاصية التحويل على مواقع إحداثيات المتجه على محور العناصر الثلاثة XYZ.[1] على سبيل المثال , في حال أردنا إجراء تدوير على محور x فإن جيب وجيب تمام الزاوية سيطرأ على محاور Y و Z وكذلك الأمر بالنسبة لبقية الإحداثيات من المتجه.[1]

 


خاصية التحويل ومكتبة GLM



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

تستطيع تضمين المكتبة بنفس الطرق التي قمنا بشرحها في الدرس الأول من هذه الدورة.[1] بعد أن قمنا بربط مكتبة GLM نقوم بتضمين كل من الملفات التالية في المشروع:

#include <glm/glm.hpp>
#include <glm/gtc/matrix_transform.hpp>
#include <glm/gtc/type_ptr.hpp>

تستطيع إجراء اختبار للمكتبة عن طريق الكود التالي:

glm::vec4 vec(1.0f, 0.0f, 0.0f, 1.0f);
    glm::mat4 trans;
    trans = glm::translate(trans, glm::vec3(1.0f, 1.0f, 0.0f));
    vec = trans * vec;

في المثال السابق لقد قمنا بتعيين متجه باسم vec باستخدام مكتبة GLM ثم بعد ذلك قمنا بتحديد مصفوفة رباعية تأخذ identity matrix كقيمة افتراضية.[1] لقد استندنا على خاصية التحويل عن طريق تمرير المصفوفة trans إلى وظائف المكتبة translate لذلك فهي تتولى عمليات الإزاحة أو غيرها.[1]

السطر الثالث من الكود يقوم بإجراء عملية إزاحة عن طريق ضرب إحداثيات المتجه القديمة بعمليات الإزاحة الجديدة.[1] بينما يدل السطر الأخير على استخراج القيم الجديدة وطباعتها.[1]

يجب أن تدرك بأن مكتبة GLM ليست سوى آلة حسابية تقوم بتنفيذ أعقد عمليات الرسم عبر وظائفها.[1] فهي تغني المبرمجين بشكل كبير عن الخوض في أعماق الرسوميات. ربما سنقوم باستخدامها كثيرًا عند الوصول إلى واجهات GUI.[1]

 


تطبيق المعادلات على الكود



سوف نجري الآن تعديلات أكثر جمالية على كود تم إعداده في أجزاء سابقة من هذه الدورة , حيث يتضمن ذلك التحجيم والتدوير مع عقارب الساعة.[1] بداية يجب أن نضيف مصفوفة التحويل على الكود الخاص بــ c++ ليشمل بعض المتغيرات التالية:

glm::mat4 trans;
trans = glm::rotate(trans, 90.0f, glm::vec3(0.0, 0.0, 1.0));
trans = glm::scale(trans, glm::vec3(0.5, 0.5, 0.5));

تقوم الوظائف السابقة بإجراء تدوير على النموذج الخاص بنا على محور Z من الرسم ليصل إلى مقدار 90 درجة. ثم بعد ذلك نجري تحجيم على المصفوفة بمقدار 0.5 درجة على كافة المحاور.[1] بالتالي سوف تخضع المصفوفات إلى عمليات حسابية من ضرب وجمع وغيرها دون الخوض في الشروحات السابقة وذلك اختصار للوقت والجهد.

لا ننسى أن لغة GLSL تلعب دورًا هامًا في تعيين المصفوفات ومن متغيراتها mat4 التي يجب أن ترافقها أولا في ملف vertex shader. ولذلك سنقوم بتعريفه في صفحة Vertex كما هو في السطر التالي:

uniform mat4 transform;

يتطلب منا التعديل في دالة void main الخاصة بــ vertex shader , وذلك عن طريق ضرب الـ uniform في المصفوفة transform.

gl_Position = transform * vec4(position, 1.0f);

بعد أن قمنا بإضافة يونيفورم مضروب في موقع النموذج , يجب علينا الاتصال بتلك الخصائص من كود c++ وذلك من خلال الكود التالي.

GLuint transformLoc = glGetUniformLocation(ourShaders->Program, "transform");
    glUniformMatrix4fv(transformLoc, 1, GL_FALSE, glm::value_ptr(trans));

 

في حال عدم دعم المكتبة إلى identity matrix بشكل تلقائي , قم بإضافة constructor للمتغير glm::mat4 trans ليصبح هكذا glm::mat4 trans(1.0f);.

 

خاصية التحويل
صورة يظهر فيها نتائج تطبيق خاصية التحويل على مشروع OpenGL.

 

المراجع
  1. [1]^ كتاب ـــــــ offline learn OpenGL created by Joey de Vries.
  2. [2]^ مصادر مكتبة GLM ـــــــــ OpenGL Mathematics.

اترك تعليقاً

لن يتم نشر عنوان بريدك الإلكتروني. الحقول الإلزامية مشار إليها بـ *