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

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

السلام عليكم ورحمة الله وبركاته

تحية طيبة للسيد وسام البهنسي وبعد

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

نرجو اطلاعنا على الآلية المستخدمة ولكم جزيل الشكر

Husam Zakaria
Game Programmer

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

عفواً من الأخ وسام

إن معلومات الرأس الواحد ليست 4 بايت بل 4 أرقام عشرية ولكل رقم عشري كما نعلم 4 بايت

ولكن مع ذلك يظل السؤال قائماً: كيف استطعنا تخفيض حجم معلومات الرأس الواحد إلى 4 أرقام عشرية فقط ؟

خطر في بالي هذا الحل البسيط:
يتم وضع معلومات الموضع (x,y,z) ضمن الأرقام العشرية الثلاث الأولى
ويتم وضع معلومات (u,v) ضمن الـ w بحيث يكون للـ u حجم 16 bit و للـ v كذلك الأمر
ويتم الحصول على المعلومات الـ normal من خلال normal map باستخدام نفس الـ uv السابق

أرجو أن أكون قد حصلت الإجابة.

مع كامل التحيات

Husam Zakaria
Game Programmer

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

شكراً حسام على سؤالك وملاحظاتك القيمة. بالفعل أنا ارتكبتُ خطأ في حجم معلومات الرأس، فهي ليست 4 بايتات، وإنما 8، وقد قمتُ بتعديل التدوينة لتوضح المعلومة الصحيحة.

أما الآن فلنناقش الحل الذي توصلتَ أنت إليه:
 
التوزيع الذي قمتَ بطرحه سليم تماماً، مع ملاحظة أنه يشترط أن يكون إكساء النواظم (normal map) محفوظ في مبدأ الإحداثيات المحلي (object space) وليس مبدأ الإحداثيات المماسي (tangent space) كما هو شائع في الإضاءة باستخدام إكساءات النواظم. فهذا الأخير يتطلب حفظ معلومات الناظم والمماس لكل رأس.
بهذا الأسلوب تكون قد وفرت 8 بايتات من الحجم الكلي (24 بايت)، مع ملاحظة أنك أهملت حفظ قيمة لونية كنتُ قد ذكرتها أنا ضمن المعلومات اللازمة في كل رأس.
 
في حالة مكتب عنبر، فإن الرأس يحتاج لثمان بايتات فقط لحفظ الآتي:

- موقع الرأس الفراغي (ثلاثي الأبعاد)
- قيمة لونية بمجال محدود (أحمر، أخضر، أزرق)
- إحداثيات إكساء (ثنائية الأبعاد)
 
في الحالة العادية نعبر عن هكذا رأس بالبنية الآتية في ++C:


struct VTX
{
  float x,y,z;
  DWORD color;
  float u,v;
};
 
لكن في مكتب عنبر نستخدم البنية التالية:


struct VTX { short pos[3]; short clr; };
 
أربعة متغيرات من نوع short، كل منها بعرض بايتين فقط، يتم زج المعلومات فيها بالترتيب الآتي:


XXXXXXXX XXXXXXXX UYYYYYYY YYYYYYYY ZZZZZZZZ ZZZZZZZZ RRRRRVGG GGGBBBBB
 
حيث XYZ هي بتات الموقع و UV هي بتات إحداثيات الإكساء و RGB هي القيمة اللونية. هذه الطريقة في التوصيف تستعمل متغيرات صحيحة فقط ولا تعتمد على المتغيرات العشرية بأي شكل من أشكالها.
 
اللون مكمم لـ 15 بت فقط، وهو أكثر من كافٍ لحالتنا هذه إذا تذكرنا أن هذه الألوان تقع على الرؤوس، ويقوم معالج الرسوميات بتوليد التدريجات الناعمة ضمن المثلثات، لذلك لا يمكن للمستخدم ملاحظة أية تشوهات ناجمة عن التكميم.
 
إحداثيات الإكساء تحتاج إلى 2 بت فقط، وذلك لأن أوراق الشجر تستعمل القيم 0 و 1 حصراً لكل من U و V، لذلك لا داعي لاستخدام بتات أكثر لحفظ قيم بينية.
 
أخيراً فإن إحداثيات موقع الرأس تحتل 16:15:16 بتاً، وهي الحصة الكبرى طبعاً، وذلك بسبب كون هذه المعلومات حساسة جداً للتكميم وتتسبب بتشوهات واضحة في المجسم إن تم تكميمها كثيراً. الإحداثي Y حصل على 15 بت بعد تجارب توزيع مختلفة راقبتُ من خلالها مقدار التشوه الناتج وصولاً إلى نتيجة أن Y هو أكثر الأبعاد قدرة على تحمل التكميم لـ 15 بت.

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

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

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

شكراً لك على هذا الشرح المفصل، لقد استفدت من هذه المعلومات كثيراً

إذا هذه الطريقة التي اتبعتها تم تطبيقها على أوراق النباتات فقط وليس لباقي مجسمات المشهد، فهل هناك أي عملية ضغط للمجسمات الأخرى تم تطبيقها في هذا المشروع؟

السؤال الثاني:
هل هذه الطريقة نتجت عندما اكتشفت أن مجسمات أوراق النباتات يكون فيها الـ u و الـ v فقط إما صفر أو واحد ؟ أم أن التصميم قد قام على اعتبار هذا الأمر؟

هناك ملاحظة طريفة لاحظتها ضمن الصور الموجودة ضمن المقالة وهي أن رسم المشهد مع تفعيل رسم الماء أخذ 10.3 ms على الـ GPU بينما رسم المشهد بدون الماء أخذ 10.4 ms أي أن تفعيل رسم الماء سيزيد من سرعة الرسم، لذلك ينصح بوضع المسطحات المائية دائماً ضمن المشهد لزيادة الأداء D: ☺

السؤال الثالث:
كيف قمت بقياس زمن المعالجة على الـ GPU ؟ هل اعتبرت أن الزمن بين تعليمة BeginScene وتعليمة EndScene هي زمن المعالجة على الـ GPU ؟

مع كامل التحيات

Husam Zakaria
Game Programmer

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

أما في 10/ربيع الأول/1431 01:20 ص، فقد تنهد حسام زكريا بارتياح وهو يرد:

إذا هذه الطريقة التي اتبعتها تم تطبيقها على أوراق النباتات فقط وليس لباقي مجسمات المشهد، فهل هناك أي عملية ضغط للمجسمات الأخرى تم تطبيقها في هذا المشروع؟

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


في 10/ربيع الأول/1431 01:20 ص، غمغم حسام زكريا باستغراب قائلاً:

هل هذه الطريقة نتجت عندما اكتشفت أن مجسمات أوراق النباتات يكون فيها الـ u و الـ v فقط إما صفر أو واحد ؟ أم أن التصميم قد قام على اعتبار هذا الأمر؟

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


بتاريخ 10/ربيع الأول/1431 01:20 ص، قطب حسام زكريا حاجبيه بشدة وهو يقول:

هناك ملاحظة طريفة لاحظتها ضمن الصور الموجودة ضمن المقالة وهي أن رسم المشهد مع تفعيل رسم الماء أخذ 10.3 ms على الـ GPU بينما رسم المشهد بدون الماء أخذ 10.4 ms أي أن تفعيل رسم الماء سيزيد من سرعة الرسم، لذلك ينصح بوضع المسطحات المائية دائماً ضمن المشهد لزيادة الأداء D: ☺

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


وفي 10/ربيع الأول/1431 01:20 ص، أعرب حسام زكريا عن رأيه بالموقف كالآتي:

كيف قمت بقياس زمن المعالجة على الـ GPU ؟ هل اعتبرت أن الزمن بين تعليمة BeginScene وتعليمة EndScene هي زمن المعالجة على الـ GPU ؟

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

والسلام عليكم ورحمة الله وبركاته...

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