رسومات الكمبيوتر ، كما تعلمون ، هي أساس صناعة الألعاب. في عملية إنشاء محتوى رسومي ، نواجه حتماً صعوبات مرتبطة بالفرق في عرضه في بيئة الإنشاء وفي التطبيق. تضاف إلى هذه الصعوبات مخاطر الإهمال البشري البسيط. بالنظر إلى حجم تطور اللعبة ، تنشأ مثل هذه المشكلات بشكل متكرر أو بأعداد كبيرة.
قادتنا هذه الصعوبات إلى التفكير في الأتمتة وكتابة المقالات حول هذا الموضوع. ستتناول معظم المواد العمل مع
Unity 3D ، حيث إنها أداة التطوير الرئيسية في Plarium Krasnodar. فيما يلي ، سيتم اعتبار النماذج والأنسجة ثلاثية الأبعاد كمحتوى رسومي.
في هذه المقالة ، سنتحدث عن ميزات الوصول إلى البيانات التي تمثل كائنات ثلاثية الأبعاد في
الوحدة . ستكون المادة مفيدة بشكل أساسي للمبتدئين ، وكذلك للمطورين الذين نادراً ما يتفاعلون مع التمثيل الداخلي لهذه النماذج.

حول النماذج ثلاثية الأبعاد في الوحدة - لأصغرها

في الطريقة القياسية ، تستخدم
الوحدة مكونات
MeshFilter و
MeshRenderer لتقديم النموذج. يشير MeshFilter إلى أصل
Mesh الذي يمثل النموذج. بالنسبة لمعظم التظليل ، تعد المعلومات الهندسية مكونًا أدنى إلزاميًا لتقديم نموذج على الشاشة. قد لا تتوفر بيانات مسح النسيج وعظام الرسوم المتحركة إذا لم تكن متورطة. كيف يتم تنفيذ هذه الفئة في الداخل وكيف يتم تخزين كل شيء ، هناك لغز
للمبلغ التاسع في سبعة أختام.
في الخارج ، توفر الشبكة ككائن الوصول إلى مجموعات البيانات التالية:
- القمم - مجموعة من مواقع القمم الهندسية في مساحة ثلاثية الأبعاد لها أصلها ؛
- المألوف ، الظلال - مجموعات من المتجهات العادية واللامسية إلى القمم التي يشيع استخدامها لحساب الإضاءة ؛
- uv ، uv2 ، uv3 ، uv4 ، uv5 ، uv6 ، uv7 ، uv8 - مجموعات الإحداثيات لمسح الملمس ؛
- الألوان ، الألوان 32 - مجموعات من قيم ألوان القمم ، مثال على ذلك كتاب مدرسي يخلط القوام بالقناع ؛
- يربط - مجموعات من المصفوفات لتحديد موضع القمم بالنسبة للعظام ؛
- الأوزان العظمية - معاملات تأثير العظام على القمم ؛
- مثلثات - مجموعة من مؤشرات قمة الرأس تعالج 3 في وقت واحد ؛ يمثل كل ثلاثية مثل مضلع (في هذه الحالة ، مثلث) من النموذج.
يتم تنفيذ الوصول إلى المعلومات حول القمم والمضلعات من خلال الخصائص المطابقة ، حيث يُرجع كل منها مجموعة من الهياكل. بالنسبة لشخص
لا يقرأ الوثائق التي نادراً ما يعمل مع الشبكات في
Unity ، فقد لا يكون من الواضح أنه كلما تم الوصول إلى قمة في الذاكرة ، يتم إنشاء نسخة من المجموعة المقابلة في شكل صفيف بطول يساوي عدد الرؤوس. يعتبر هذا فارق بسيط في
كتلة صغيرة
من الوثائق . التعليقات حول خصائص فئة
Mesh المذكورة أعلاه تحذر أيضًا من هذا. سبب هذا السلوك هو ميزة
الوحدة المعمارية في سياق وقت التشغيل
Mono . من الناحية التخطيطية ، يمكن تمثيل ذلك على النحو التالي:

جوهر المحرك (UnityEngine (الأصلي)) معزول عن البرامج النصية للمطورين ، ويتم الوصول إلى وظائفه من خلال مكتبة UnityEngine (C #). في الواقع ، إنه محول ، حيث أن معظم الطرق تعمل كطبقة لتلقي البيانات من النواة. في الوقت نفسه ، فإن النواة وبقيةها ، بما في ذلك البرامج النصية الخاصة بك ، تدور في إطار عمليات مختلفة ويعرف جزء البرنامج النصي قائمة الأوامر فقط. وبالتالي ، لا يوجد وصول مباشر إلى الذاكرة المستخدمة من قبل النواة من البرنامج النصي.
حول الوصول إلى البيانات الداخلية ، أو كيف يمكن أن تكون الأشياء السيئة
لشرح مدى سوء الأشياء ، دعونا نحلل مقدار الذاكرة التي تم مسحها بواسطة Garbage Collector باستخدام مثال من الوثائق. لبساطة التوصيف ، قم بلف نفس الكود في طريقة التحديث.
public class MemoryTest : MonoBehaviour { public Mesh Mesh; private void Update() { for (int i = 0; i < Mesh.vertexCount; i++) { float x = Mesh.vertices[i].x; float y = Mesh.vertices[i].y; float z = Mesh.vertices[i].z; DoSomething(x, y, z); } } private void DoSomething(float x, float y, float z) {
قمنا بتشغيل هذا البرنامج النصي مع بدائية قياسية - كرة (515 رأسًا). باستخدام أداة
Profiler ، في علامة تبويب
Memory ، يمكنك معرفة مقدار الذاكرة التي تم وضع علامة عليها لجمع البيانات المهملة في كل إطار. على آلة العمل لدينا ، كانت هذه القيمة ~ 9.2 ميغابايت.

هذا كثير جدًا حتى بالنسبة للتطبيق الذي تم تحميله ، وهنا أطلقنا مشهدًا يحتوي على كائن واحد حيث يتم تثبيت البرنامج النصي البسيط عليه.
من المهم الإشارة إلى ميزات برنامج التحويل البرمجي
.Net وتحسين التعليمات البرمجية.
بالانتقال إلى سلسلة المكالمات ، ستجد أن استدعاء
Mesh.vertices يستلزم استدعاء الطريقة الخارجية للمحرك. هذا يمنع المحول البرمجي من تحسين التعليمة البرمجية داخل أسلوب
Update () الخاص بنا ، على الرغم من أن
DoSomething () فارغ وأن المتغيرات
x و y و z غير مستخدمة لهذا السبب.
الآن نحن نخزن مجموعة من المواقف في البداية.
public class MemoryTest : MonoBehaviour { public Mesh Mesh; private Vector3[] _vertices; private void Start() { _vertices = Mesh.vertices; } private void Update() { for (int i = 0; i < _vertices.Length; i++) { float x = _vertices[i].x; float y = _vertices[i].y; float z = _vertices[i].z; DoSomething(x, y, z); } } private void DoSomething(float x, float y, float z) {

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

هنا ، تمثل فئة
CustomMesh الشبكة نفسها. بشكل منفصل ، في شكل
الأداة المساعدة ، قمنا بتنفيذ التحويل من
UntiyEngine.Mesh والعكس بالعكس. يتم تعريف شبكة من قبل مجموعة من المثلثات. يحتوي كل مثلث على ثلاثة حواف بالضبط ، والتي يتم تحديدها بدورها برأسين. قررنا أن نضيف إلى القمم فقط المعلومات التي نحتاجها للتحليل ، وهي: موضع ، طبيعي ، قناتان للمسح الضوئي (
uv0 للنسيج الرئيسي ،
UV2 للإضاءة) ولون.
بعد بعض الوقت ، نشأت الحاجة إلى رفع التسلسل الهرمي. على سبيل المثال ، لمعرفة ذلك من المثلث الذي ينتمي إليه. بالإضافة إلى ذلك ، بدا
خفض التصنيف من
CustomMesh إلى
Vertex مدللاً ، وأصبحت الكمية غير المعقولة والمهمة من القيم المكررة تثير أعصابي. لهذه الأسباب ، كان يجب إعادة تصميم الهيكل.

تطبق
CustomMeshPool أساليب الإدارة المريحة والوصول إلى جميع
CustomMesh معالجتها. نظرًا لحقل
MeshId ، يمكن لكل كيان الوصول إلى معلومات الشبكة بالكامل. يفي هيكل البيانات هذا بمتطلبات المهام الأولية. من السهل توسيعها عن طريق إضافة مجموعة البيانات المناسبة إلى
CustomMesh والأساليب اللازمة إلى
Vertex .
تجدر الإشارة إلى أن هذا النهج ليس الأمثل في الأداء. في الوقت نفسه ، تركز معظم الخوارزميات التي قمنا بتطبيقها على تحليل المحتوى في محرر
Unity ، وهذا هو السبب في أنك لا تضطر في كثير من الأحيان إلى التفكير في مقدار الذاكرة المستخدمة. لهذا السبب ، نقوم حرفيًا بتخزين كل شيء ممكن. نقوم أولاً باختبار الخوارزمية المنفذة ، ثم نقوم بإعادة تشكيل أساليبها ، وفي بعض الحالات ، نقوم بتبسيط هياكل البيانات لتحسين وقت التشغيل.
هذا كل شيء الآن. في المقالة التالية ، سنتحدث عن كيفية تحرير النماذج ثلاثية الأبعاد التي تمت إضافتها بالفعل إلى المشروع ، وسوف نستخدم بنية البيانات المدروسة.