الشبكة العربية لمطوري الألعاب

مبتدئ  بلال بوزيــــــــاني مشاركة 1

السلام عليكم ورحمة الله وبركاته
 
لدي سؤال في عالم صناعة محرك رسومي rendering engine قد حيرني مند أشهر و لم اجد له جواب يشفي هذه الحيرة , مند فترة و انا أبحث في عدة كتب في مقالات في منتديات متخصصة  ,قرأت كثيرا , الا ان جواب دقيقا لم أجد له سبيل.
 
السؤال عن كيفة الرسم المجسمات بطريقة فعالة المستخدمة في المحركات الحديثة  Rendering Primitives Efficiently  , أبحث عن الطرق الحديثة في كيفة وترتيب المجسمات للحصول على أحسن أداء.
 
في المقالات و الكتب التي قرأت يركزون دائما على تحسين أداء الرسم على مستوى ما يسمى ب Seangraph و Spatial Data Structure  وما يسمى ب Traversals ,  ويغفلون  الحديث  عن الرسم بفعالية في المستوى المنخفض فيrendering subsytem
 
أرجو المساعدة في هذا المجال , كذالك أبحث عن كتب أو مقالات تتكلم هن هذه الامور المهمة ,طرق الرسم طرق تحسين أداء محرك الرسوم , ادارة الموارد الخ...
 
أخوكم بلال

خبير مدير وسام البهنسي مشاركة 2

بتاريخ 23/ذو الحجة/1432 03:55 م، قطب بلال بوزيــــــــاني حاجبيه بشدة وهو يقول:

السؤال عن كيفة الرسم المجسمات بطريقة فعالة المستخدمة في المحركات الحديثة  Rendering Primitives Efficiently  , أبحث عن الطرق الحديثة في كيفة وترتيب المجسمات للحصول على أحسن أداء.

الموضوع واسع وبالفعل تفاصيله تحتاج إلى كتب. لكن المبدأ العام لأغلب تحسينات الأداء والرسم الفعال هو في المقولة: 
"أسرع كود هو الكود الذي لا يـُـنــَـفــَّـذ"
 
لذلك تجد أن الكثير الأساليب تؤدي في النهاية إلى تفادي رسم ما لا يفيد رسمه. الفعالية القصوى في الرسم هي معرفة اللون النهائي لكل بكسل على الشاشة دون إضاعة الوقت في أية حسابات لن تظهر نتائجها للمستخدم النهائي... مثلاً، لو لدينا مجموعة مكعبات تحتوي بعضها البعض، فإنه من غير المفيد أبداً رسم المكعبات الداخلية، لأنها لن تظهر للمستخدم، وإنما يكتفى برسم المكعب الأكبر منها فقط.
 
هناك أساليب عديدة يتم تطبيقها على نواحي ومستويات مختلفة من البرنامج. عادة تزداد فاعلية الأسلوب كلما ارتفع مستواه. أعتقد أن أوسع كتاب يتحدث عن هذه الأمور هو كتاب Real-time Rendering بإصداره الثالث.
 
بالمناسبة، مخطط المشهد (Scene graph) هو ليس أسلوب تحسين أداء أو رسم بفاعلية بالدرجة الأولى، وإنما طريقة للتعبير عن المشاهد في الحاسوب. تعتمد على مبدأ علاقة الأب-الابن للتعبير عن العلاقات بين مكونات المشهد من أضواء وكاميرات ومجسمات. هذه الأسلوب مستخدم بشكل رئيسي في برامج التصميم ثلاثي الأبعاد.
 
إن كانت لديك أية أسئلة عن أسلوب معين فأنا جاهز للإجابة إن شاء الله...

وسام البهنسي
مبرمج في إنفيديا وإنفريمز

مبتدئ  بلال بوزيــــــــاني مشاركة 3

جزاك الله كل خير أخي وسام
 
صحيح الظاهر ان الموضوع واسع , حيث تحسين أداء الرسم يكون في عدة مستويات.
 
حاليا ما أود الوصول اليه هو الفصل بين النظام الفرعي محرك الرسم (  rendering subsystem) وما يسمى مخطط المشهد ( Scene graph )  كما تفضلت به أخي وسام , فالكتب و المقالات التي وجدتها اغلب الحلول المعروضة فيها يمزجون ين المكونين , بحيث أي تحديث في مخطط المشهد و ما يتعلق به يأدي الى التغير في النظام الفرعي محرك الرسم هذا أولا
 
الان أنا مركز أكثر على محرك الرسم , أعرف بوجود Frustum culling و Occlusion culling , هذه التقنيات المطبقة على الاجسام قبل دخول مسار التصيير , فهي مهمة جدا حسب فهمي , لاكن ما أريد فهمه الان ما يسمى ب Batching Primitives , يعني تحسين الاداء على مستوى الرؤوس , كل مجموعة رؤوس لها خصائص واحداثيات الخامات الى غير ذلك , ما فهمته أنه يجب تقليل تغييرRendering States و التقليل من نداء دوال الرسم أي الرسم بالجملة.
 
جزاك الله كل خير مرة ثانية. وارجو من الله عز وجل اني بطرحي لهذه التساؤلات ان تعم الفائدة من النقاشات

مبتدئ  حسام زكريا مشاركة 4

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

setMaterial material1
setTexture texture1
drawObject object1
setMaterial material2
setTexture texture2
drawObject object2
setMaterial material1
setTexture texture1
drawObject object3

لاحظ أن object1 و object3 يستخدمان نفس المادة ونفس الاكساء لذلك لاحظ كيف سنقوم بتسريع رسم المشهد السابق بإعادة ترتيب الاستدعاءات:

setMaterial material1
setTexture texture1
drawObject object1
drawObject object3
setMaterial material2
setTexture texture2
drawObject object2

لاحظ أننا قمنا برسم نفس المشهد بعدد أقل من التعليمات وهذا الأمر سيسرع كثيراً رسم المشاهد التي تكون فيها العناصر تشترك بعدد معين من المواد والاكساءات، هذا الأمر وجدته مطبق في Quake 3 Engine و Ogre3d و crystal space و cry engine ( إذا قمت باستخدام Pix على لعبة FarCry ستلاحظ ترتيب عمليات الرسم ) وكثير من الألعاب الأخرى وحتى الحديثة منها
هذا الأمر لا ينطبق على رسم العناصر الشفافة إذ أننا مجبرون بهذه الحالة على رسمها من الأبعد إلى الأقرب عن الكاميراً بغض النظر عن المواد والإكساءات الخاصة بها
يمكنك الإطلاع على الكثير من النقاشات والتجارب في هذا المجال Render Sorting في موقع www.GameDev.net وحتى هناك مثال ضمن DirectX sdk يقوم بتطبيق هذا الأمر تحت عنوان StateManager
هذه أحد الأمور التي تسرع عملية الرسم وهناك أمور أخرى سنأتي عليها في وقت آخر إن شاء الله

Husam Zakaria
Game Programmer

خبير مدير وسام البهنسي مشاركة 5

وفي 24/ذو الحجة/1432 05:35 م، قال حسام زكريا متحمساً:

أحد الأساليب المستخدمة هو ترتيب رسم العناصر حسب المواد والاكساءات وذلك لتخفيف من الاستدعاءات التي تؤدي إلى تغيير حالة الاكساء أو المادة مثال:
رسم المشهد بدون ترتيب سيؤدي إلى الاستدعاءات التالية...

حسناً، سأعلق على هذه التفصيلة كي تكتمل المعلومة.

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

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

هناك كلفتين في الحقيقة لتغيير حالة جهاز الرسم (rendering device): كلفة تزمين معالج الرسوميات (GPU Sync)، وكلفة تغيير الحالة نفسها (State Change). الأولى ستدفعها في كل الأحوال باستثناء حالات خاصة جداً ودقيقة سأذكرها في التدوينة إن شاء الله. لكن عموماً نقول، بمجرد أن قمتَ برسم مجسم، ثم انتقلت لرسم مجسم آخر، حتى وإن لم تقم بتغيير إكساء أو أي حالة أخرى فإنك قد تدفع كلفة تزمين معالج الرسوميات. لتفادي هذه الكلفة يضطر المبرمج للقيام بعمليات بهلوانية كثيرة في المحرك، وهو أمر غير مبهج عندما تضطر للقيام به (صدقني).
 

الكلفة الثانية -وهي ما تم الحديث عنه هنا- تقول أن هناك كلفة مصاحبة لكل أمر تغيير حالة في جهاز الرسم (rendering device state change command). مثلاً، تغيير إكساء مكلف أكثر من تغيير حالة الضباب وهو مكلف أكثر من تغيير قيمة ثابت في مظلل وهو مكلف أكثر من .... الخ. الكلفة الزمنية الفعلية تختلف طبعاً من بطاقة عرض إلى أخرى، حتى إن الترتيب نفسه ليس ثابتاً. بعض المعماريات حساسة لتغييرات في حالة معينة أكثر من معماريات أخرى. حتى فترة قريبة، كان هناك إجماع أن كلفة تغيير الإكساء هي الأعلى بين أقرانها، لكن كلفة تغيير المظلل دخلت في المنافسة هي الأخرى، وذلك لأن برامج التشغيل (drivers) غالباً ما تقوم ببعض عمليات السحر الأسود حالما تستلم طلب تغيير المظلل (مثلاً إعادة ترجمة المظلل لسبب ما).
 

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

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

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

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

وسام البهنسي
مبرمج في إنفيديا وإنفريمز

مبتدئ  بلال بوزيــــــــاني مشاركة 6

السلام عليكم
 
بارك الله فيك أخي حسام 😄 , بارك الله فيك أخي وسام 😄
 
هذا بالضبط الموضوع الذي أبحث عنه .
 
معلومات جد جميلة حقيقة و تنزع الكثير من الابهام و تأكد الكثير من المعلومات أيضا   , في انتظار التدوينة و معلومات اكثر في هذا الموضوع المهم.
 
 
أخوكم بلال

مبتدئ  بلال بوزيــــــــاني مشاركة 7

السلام عليكم
,
استكمالا لهذا الموضوع لدي بضعة اسالة :
 
1-     هل وضع نفس قيمة حالة جهاز الرسم (rendering device)مرة ثانية تأدي الى تزمين معالج الرسوميات , ودفع كلفة وضعها (State change)   في هذه الحالة أضطر الى اجراء المقارنات حالات جهاز الرسم لتفادي هذا الامر ؟.
 
2-     بعد انتهاء معالج الرسوميات من امر رسم ما , هل يحتاج هذا الاخير الى التزامن مع المعالج المركزي او ينتقل الى تنفيذ امر اخر ؟
 
3-     كذلك هل يحتاج معالج الرسوميات الى التزامن مع المعالج المركزي بعد تنفيذ أمر Present  ؟.
 
أخوكم بلال

خبير مدير وسام البهنسي مشاركة 8

في 17/ربيع الثاني/1433 04:55 ص، قال بلال بوزيــــــــاني بهدوء وتؤدة:

1-     هل وضع نفس قيمة حالة جهاز الرسم (rendering device)مرة ثانية تأدي الى تزمين معالج الرسوميات , ودفع كلفة وضعها (State change)   في هذه الحالة أضطر الى اجراء المقارنات حالات جهاز الرسم لتفادي هذا الامر ؟.

عموماً لست بحاجة لتفادي تكرار إرسال أوامر تعديل الحالة. فدايركت ثري دي نفسه يقوم بهذه المهمة ضمنياً في كافة إصداراته باستثناء حالة واحدة في دايركت ثري دي 9. حيث هناك وضعية إنشاء لجهاز الرسم تدعى "الوضعية الصافية" (pure mode). ضمن هذه الوضعية لن يقوم دايركت ثري دي بتصفية نداءات تعديل الحالة، وإنما يفترض أنك أنت من ستقوم بذلك. كما أن برنامج التشغيل في أغلب الحالات يقوم بهذه العملية أيضاً ☺
 


في 17/ربيع الثاني/1433 04:55 ص، عقد بلال بوزيــــــــاني حاجبيه بتفكير وقال:

2-     بعد انتهاء معالج الرسوميات من امر رسم ما , هل يحتاج هذا الاخير الى التزامن مع المعالج المركزي او ينتقل الى تنفيذ امر اخر ؟

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


وفي 17/ربيع الثاني/1433 04:55 ص، قال بلال بوزيــــــــاني متحمساً:

3-    كذلك هل يحتاج معالج الرسوميات الى التزامن مع المعالج المركزي بعد تنفيذ أمر Present  ؟.

كلا. لكن عند نداء الإجراء Present في دايركت ثري دي، فإن المعالج المركزي _قد_ ينتظر معالج الرسوميات هنا إن تمت تعبئة طابور الأوامر بعدد من اللقطات (عادة 3). هذا الرقم يمكن للمستخدم التحكم به من خلال لوحة التحكم المتقدمة لبرنامج التشغيل (Maximum Frame Queue Number). 
إن حدث هذا فإن هذا يعني أن المعالج المركزي لا يقوم بأي عمل يذكر، بينما معالج الرسوميات غارق حتى أذنيه في العمل... وهو وضع نادر في الألعاب الفعلية...
 
 
أودّ أخيراً أن أنوه أن كلفة تزمين معالج الرسوميات عند تغيير حالة ما فيه ليست كبيرة لدرجة خطرة أبداً. الحالة القصوى التي تبدأ فيها هذه الكلفة بالظهور، هي عندما تقوم برسم عدد كبيييير من المجسمات الصغيرة، وكل منها يتم رسمه على حدة، وبين الواحد والآخر تقوم بتغيير حالة ما في جهاز الرسم. هنا يلجأ لحل الاستنساخ (instancing).

وسام البهنسي
مبرمج في إنفيديا وإنفريمز

مبتدئ  بلال بوزيــــــــاني مشاركة 9

شكرا أخي وسام  😄
 
في الحقيقة لدي الكثير من التساؤلات في صدد هذا الموضوع , الذي كلما غصت فيه تبين لي ان الطريق طويـــــــــــــــــــــــل , لاكن على العموم سأكتفي الان بهذه الاجوبة الشافية ان صح التعبير 😳 .
 
أخوكم بلال.