خاصية التحويل : دورة 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 الرياضية.

حيث تساعد GLM في أداء أعمال أكثر حرفية.

بعد أن قمنا بربط مكتبة 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]


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


نجري الآن تعديلات أكثر جمالية على كود تم إعداده في أجزاء سابقة من هذه الدورة ، حيث يتضمن ذلك التحجيم والتدوير مع عقارب الساعة.[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);.

 

\"نتائج

المراجع

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

اترك تعليقاً

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