تعظيم الاستفادة من النماذج ثلاثية الأبعاد لمشهد اللعبة

تكمل هذه المقالة سلسلة من المنشورات من Krasnodar studio Plarium حول جوانب مختلفة من العمل مع النماذج ثلاثية الأبعاد في الوحدة. المقالات السابقة: "ميزات العمل مع Mesh in Unity" ، و "Unity: التحرير الإجرائي لـ Mesh" ، و "استيراد النماذج ثلاثية الأبعاد إلى Unit و pitfalls" ، و "المسافة البادئة للبيكسل في مسح الملمس" .

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



المحاصيل في المشهد


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

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

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

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


مثال على الاستيفاء اللوني عند عرض المضلعات ذات الرؤوس الشائعة

لذلك ، من الضروري تقسيم الشبكة بطريقة ما إلى مضلعات مستقلة منفصلة ، مع الحفاظ على طوبولوجيا وهندسة الكائن. القول المأثور. نقوم بتحويل صفائف المثلثات والرؤوس بحيث يتم إنشاء كل رأس مثلث 3 فريد ، يتم تحديد موقعه بواسطة القمم المقابلة للشبكة الأصلية. تجدر الإشارة إلى أنه في الحالة العامة ، سيكون لهذه الشبكة عدد أكبر بكثير من الرؤوس مقارنة بالأصل. وإذا تجاوز هذا الرقم 65 535 ، فعند إنشاء الشبكة ، يجب عليك تحديد تنسيق الفهرسة المناسب.

قم بتحويل الشبكة الأصلية إلى شبكة ذات رؤوس فريدة لكل مضلع
private static Mesh GetNotSmoothMesh(Mesh origin) { var oVertices = origin.vertices; var oTriangles = origin.triangles; var vertices = new Vector3[oTriangles.Length]; var triangles = new int[oTriangles.Length]; for (int i = 0; i < triangles.Length; i++) { vertices[i] = oVertices[oTriangles[i]]; triangles[i] = i; } return new Mesh() { indexFormat = vertices.Length > 65535 ? IndexFormat.UInt32 : IndexFormat.UInt16, vertices = vertices, triangles = triangles }; } 


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


شبكة البايت الملونة

تلوين شبكي ينتمي فيه كل رأس إلى مضلع واحد فقط
 private static void ColorizePolygons(Mesh mesh) { var pColors = ColorsOfPolygons(mesh); var colors = new Color[mesh.vertexCount]; for (int i = 0; i < colors.Length; i++) { colors[i] = pColors[i / 3]; } mesh.colors = colors; } private static Color[] GetColorsOfPolygons(Mesh mesh) { var colors = new Color[mesh.triangles.Length / 3]; for (int i = 0; i < colors.Length; i++) { var color = Int2Color(i);//         ,     Color2Int //      ,       int     Color32 colors[i] = color; } return colors; } 


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

قراءة وتخزين الألوان من زوايا الكاميرا المختلفة
 // CameraTransform —         //      SetCameraTransform private static HashSet<Color> GetVisibleColors(Camera camera, CameraTransform[] cameraTransforms) { var renderTexture = new RenderTexture(1920, 1080, 24);//for example var rtRect = new Rect(0, 0, renderTexture.width, renderTexture.height); var frame = new Texture2D(renderTexture.width, renderTexture.height, TextureFormat.RGB24, false);//    -  RGB24   ,    RGBA32 var visibleColorsSet = new HashSet<Color>(); foreach (var cameraTransform in cameraTransforms) { SetCameraTransform(camera, cameraTransform); CreateScreenShot(camera, renderTexture, frame, rtRect); visibleColorsSet.UnionWith(GetTextureColors(frame)); } return visibleColorsSet; } public static void SetCameraTransform(Camera camera, CameraTransform camTransform) { camera.transform.position = camTransform.Position; camera.transform.rotation = camTransform.Rotation; camera.fieldOfView = camTransform.FieldOfView; camera.orthographic = camTransform.IsOrthographic; camera.nearClipPlane = camTransform.NearClippingPlane; camera.farClipPlane = camTransform.FarClippingPlane; } private static HashSet<Color> GetTextureColors(Texture2D texture) { return new HashSet<Color>(texture.GetPixels()); } private static void CreateScreenShot(Camera cam, RenderTexture renderTexture, Texture2D screenShot, Rect renderTextureRect) { cam.targetTexture = renderTexture; cam.Render(); RenderTexture.active = cam.targetTexture; screenShot.ReadPixels(renderTextureRect, 0, 0); RenderTexture.active = null; cam.targetTexture = null; } } 


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

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

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

3D المحاصيل


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

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

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

ومع ذلك ، أثناء تنفيذ البرنامج النصي ، تم العثور على عيب كبير من حيث المهمة. تفقد أدوات التحديد في Blender (تحديد المستطيل وحدد الدائرة) الدقة مع زيادة عدد العناصر المحددة لكل وحدة مساحة من الشاشة (تظل بعض المضلعات غير محددة) ، مما يجعل استخدامها في أدوات التشغيل الآلي لدينا مستحيلًا. حقيقة مثيرة للاهتمام: في نفس 3ds ماكس لم يلاحظ مثل هذه المشكلة.


تسليط الضوء من بعيد في Blender


نتيجة الاختيار

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

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

كانت هذه الطريقة ، في رأي الفنانين ، عدوانية للغاية ، لذلك قررنا التركيز على اقتصاص الأوجه الخلفية فقط.

استنتاج


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

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

وبالتالي ، بعد أن تمت مناقشة الشروط والأدوات في هذه المقالة ، فإننا نلتزم بالقواعد التالية. إذا كان من المفترض أن النموذج الذي تم إنشاؤه سيتم تشغيله دائمًا من جانب واحد للمستخدم ، وأيضًا إذا كان التداخل بين بعض أجزاء النموذج من قِبل الآخرين ضئيلًا جدًا ، يستخدم الفنان أداة القطع الخلفية في المحرر ثلاثي الأبعاد ، ويتحقق من الصحة ويستمر في تطوير التغليف UV- . إذا كان النموذج غالبًا ما يستخدم في مواضع مختلفة أو بهندسة أكثر تعقيدًا ، فبعد الاستيراد في المشروع ، نقوم بتشغيل الخوارزمية الموضحة في الجزء الأول من المقالة ، ونقوم بمعالجة جميع الكائنات الساكنة في المشهد معها.

Source: https://habr.com/ru/post/ar484792/


All Articles