آموزش بازی سازی: ‌آشنایی با رندرینگ و بهینه‌سازی آن

جمعه ۲۵ اسفند ۱۳۹۶ - ۱۷:۵۹
مطالعه 19 دقیقه
بازیسازی
در این قسمت از سری مقالات آموزش بازی‌سازی ضمن آشنایی با روش رندر شدن یک فریم، به توضیح روش‌های بهینه‌سازی این فرآیند می‌پردازیم.
تبلیغات

در بیشتر مواقع و به خصوص در زمان‌هایی که بازی ما یک محصول کوچک و محدود است، صرف پیروی از یکسری گام‌های مشخص و تعیین شده می‌تواند برای دست‌یابی به هدف نهایی کافی باشد و در این میان هیچ نیازی هم به درک دقیق و فنی کارهای گفته شده نیست. به عنوان مثال در بیشتر آموزش‌های بازی‌سازی آموزگار صرفا کارکرد اولیه ابزار درون موتور بازی‌سازی را به ما یاد می‌دهد و ما هم بدون این که از نحوه‌ی عملکرد دقیق این موارد آگاهی داشته باشیم، صرفا با تکرار همان گام‌های آموزگار سعی می‌کنیم در انتها مثلا یک بازی دوبعدی برای خودمان بسازیم.

به خاطر همین مسئله در بیشتر موارد اولین تغییرات ما در اجزای بازی به یکباره ما را با سیل مشکلات عجیب و غریبی مواجه می‌کند که نه می‌دانیم مربوط به کدام قسمت از بازی ما هستند و نه می‌دانیم که باید چگونه آن‌ها را برطرف کنیم. به همین جهت یکی از اولین گام‌های آموزش عیب یابی و رفع مشکلا بازی صحبت در مورد سازوکار عملکرد موتور ساخت بازی در فرآیند اجرای اجزای آن است. یکی از مهم‌ترین این موارد نحوه‌ی پردازش اجزای بازی به منظور رندر کردن (Render) نمای نهایی آن است. همه‌ی ما به خوبی می‌دانیم که بازی در نهایت در قالب فریم‌هایی آماده در اختیار گیمر قرار می‌گیرد و هر فریم در نگاه ساده هیچ تفاوتی با یک عکس ندارد. اهمیت این موضوع در این است که ما باید بازی خود را به گونه‌ای آماده کنیم که بتواند حداقل ۳۰ یا در صورت نیاز ۶۰ فریم در ثانیه را تحویل ما بدهد. برای همین در این مقاله می‌خواهیم با بررسی مکانیزم تولید یا همان رندر شدن یک فریم به شایع‌‌ترین مشکلاتی که در این زمینه به‌وجود می‌آیند اشاره کرده و راه‌حل برطرف کردن آن‌ها را هم برای شما توضیح دهیم.

آشنایی اولیه با مبحث رندر کردن

به صورت خلاصه و در اولین گام این پردازنده‌ی مرکزی یا CPU است که مشخص می‌کند چه چیزی و آن هم چگونه باید ترسیم شود. سپس در قدم بعدی و پس از مشخص شدن این موارد، پردازنده‌ی مرکزی دستورالعمل‌های مرتبط را آماده و دسته‌بندی کرده و آن‌ها را برای واحد پردازش گرافیکی یا همان GPU ارسال می‌کند. در قدم بعدی هم GPU یا همان کارت‌گرافیک خودمان بر اساس دستورالعمل‌های رسیده، تمامی موارد مشخص شده را ترسیم کرده و در قالب فریم‌های نهایی برای نمایشگر ارسال می‌کند. همین چند جمله‌ی کوتاه به خوبی جایگاه و اهمیت پردازنده‌ی مرکزی در فرآیند تولید فریم‌های نهایی بازی را نشان داده و مشخص می‌کند که تولید تصویر نهایی صرفا به GPU بستگی ندارد. اما بیایید از نزدیک‌تر به این فرآیند نگاه بکنیم.

یکی از اصطلاحات رایجی که در رابطه با فرآیند رندرینگ مورد استفاده قرار می‌گیرد، Rendering Pipline است. در علوم کامپیوتر معمولا به خطوط منطقی یا اجرایی یک فرآیند چند مرحله‌ای و گام‌به‌گام Pipeline می‌گویند.

pipeline

مثلا منظور از Rendering Pipeline تمامی عملیات‌های گام به گامی است که به ترتیب روی یکسری اطلاعات اولیه به منظور تولید نمای نهایی صورت می‌گیرد. در چنین فرآیند‌هایی به دلیل خطی بودن مراحل، وجود یک مشکل در قسمتی از خط عملیات می‌تواند تمامی عملیات را تحت تاثیر قرار داده و مختل کند. این مسئله شباهت زیادی به یک لوله‌ی انتقال آب دارد و وجود نقصی در قسمتی از این لوله می‌تواند تمامی جریان درون آن را تحت تاثیر قرار بدهد. برای همین می‌توانید این گونه تصور کنید که تمامی یک فرآیند رندر کارآمد، در حفظ همین جریان روان عملیاتی خلاصه می‌شود.

برای هر فریمی که رندر می‌شود پردازنده مرکزی کارهای زیر را انجام می‌دهد:

    برای هر Batch که شامل یک Draw Call است پردازنده‌ی مرکزی باید کارهای زیر را انجام بدهد:

      همچنین بد نیست نگاهی به مراحل کاری پردازنده‌ی گرافیکی هم بیاندازیم:

        آن چه که در مراحل بالا توضیح دادیم نگاه مختصری بر فرآیند رندر در موتور یونیتی بود. به این مسئله باید دقت کنید که به خصوص در رابطه با مراحل مرتبط با پردازنده‌ی مرکزی و مدیریت اشیای درون صحنه، معماری موتور ساخت بازی بسیار تاثیر دارد و برای همین ممکن است مطالب گفته شده با تغییر موتور ساخت بازی دچار تغییر شوند که البته همین گونه هم است.

        انواع مشکلات در رندر کردن

        اگر کمی به فرایند‌های گفته شده دقت کرده باشید فهمیده‌اید که برای دست‌یابی به نمای روان و مناسب از بازی هم CPU و هم GPU باید بتوانند کارهای تولید یک فریم را در زمان مناسبی به پایان برسانند. تاخیر در هر کدام از این دو مورد در نهایت منجر به عقب افتادن فرآیند رندر یک فریم و در نهایت نمای بازی ما می‌شود. البته همان گونه که در تست‌های بنچمارک بازی‌ها هم مشاهده کرده‌اید غالبا از دو شاخص میانگین و کمینه‌ی فریم تولیدی برای نشان دادن وضعیت فنی یک بازی استفاده می‌شود و در تمامی بازی‌ها، شاهد کمی افت فریم (کمتر از یک درصد) هستیم. برای همین حد و حدود بهینه‌سازی رسیدن به چنین چیزی است و شما هیچگاه نمی‌توانید به طور صد در صد نرخ فریم بازی خود را قفل کنید.

        نرخ فریم / frame rate

        قالب مشکلات پیش آمده در فرآیند رندر یک بازی به دو دلیل رخ می‌دهد. اولین مورد به دلیل وجود یک نقص در جریان عملیاتی فرآیند رندر است. مثلا ممکن است به هر دلیلی و در یکی از گام‌هایی که در بخش قبلی در مورد آن‌ها صحبت کردیم، مشکلی پیش‌ بیاید و این گونه تمامی جریان روان رندر ما دچار اختلال بشود.

        اما دومین حالت این است که ما بیش از حد ممکن بخواهیم جریانی از اطلاعات را از این خط عملیاتی عبور دهیم. واضح است که حتی بهینه‌ترین خطوط عملیاتی هم دارای محدودیتی در میزان عبور اطلاعات هستند و برای همین اگر چه در حالت قبلی وجود یک تنگه عامل مختل شدن جریان رندرینگ شده بود ولی در این جا بار اضافی و عدم کشش خط عملیاتی، عامل اختلال در جریان رندرینگ است که این وضعیت بیشتر در محصولات تولیدی بازی‌سازان تازه‌کار مشاهده می‌شود.

        همچنین ما بسته به محل وجود تنگه‌ی اشاره شده می‌توانیم دسته‌بندی جدیدی را برای مشکلات گرافیکی بازی در نظر بگیریم که این مسئله در دسته‌بندی بهتر راه‌حل‌های می‌تواند به ما کمک کند. در این حالت مشکلات به دو نوع CPU bound و GPU bound تقسیم می‌شوند. در حالت اول گلوگاه ما در پردازنده‌ی مرکزی و گام‌های مرتبط با آن وجود دارد و این در حالی است که در حالت دوم مشکل پیش آمده در گام‌های مرتبط با پردازنده‌ی گرافیکی است.

        اگر گلوگاه پردازنده‌ی مرکزی باشد

        برای تشخیص محل وقوع مشکل بهتر است مقاله‌ی آشنایی با آنالیز فنی بازی در موتور یونیتی را مطالعه کنید اما به هر جهت اگر از شواهد این گونه برداشت شد که محل وقوع مشکل ما در گام‌های مرتبط با پردازنده‌ی مرکزی است باید به نکات زیر برای حل مسئله توجه کنیم.

        تمام کارهای پردازنده‌ی مرکزی را می‌توانیم در سه دسته‌ی کلی زیر تقسیم‌بندی کنیم:

        • مشخص کردن این که چه چیز‌هایی باید ترسیم شوند
        • آماده‌سازی دستورات برای پردازنده‌ی گرافیکی
        • ارسال دستورات به پردازنده‌ی گرافیکی

        هر کدام از این دسته‌ها خود شامل وظایف متعددی است که انجام تمامی آن‌ها طریق ترد‌ها (Threads) و توسط پردازنده مرکزی صورت می‌گیرد. باید بدانید که ترد‌ها توانایی انجام همزمان چندین کار را برای پردازنده‌ی مرکزی فراهم می‌کنند. مثلا شاید زیاد شنیده‌اید که یک پردازنده‌ چهار هسته‌ای و چهار تردی یا مثلا چهار هسته‌ای و هشت تردی است. در این نقطه شما به عنوان کسی که می‌خواهد عملیات عیب‌یابی را انجام دهید باید به خوبی با این اصطلاحات آشنا شوید.

        عملکرد پردازنده‌های مرکزی سریالی است، یعنی این که در یک زمان صرفا می‌توانند یک دستور مشخص را اجرا کنند و پس از اتمام یک کار به سراغ کار بعدی می‌روند. مثلا اگر پردازنده‌ی ما دارای ۴ هسته باشد می‌تواند ۴ کار را همزمان انجام دهد. اما معمولا پس از انجام هر کار توسط هسته‌های پردازنده، معمولا باید یک عملیات نوشتن و خواندن روی رم کامپیوتر صورت بگیرد تا کار بعدی آماده شده و برای انجام در دسترس پردازنده قرار بگیرد. برای همین برای لحظاتی هم که شده هسته‌ی مورد نظر ما بیکار شده و کاری برای انجام ندارد. اما برای جلوگیری از بیکاری و افزایش راندمان، سازنده‌ها ترد‌ها را طراحی کرده‌اند که شباهت بسیار زیادی به تصویر زیر دارند.

        ترد / thread

        در این حالت همانند این می‌ماند که ما دو نفر را مسئول آوردن و بردن کارهای محول شده به یک هسته‌ از پردازنده در اختیار داشته باشیم و برای همین در این حالت ما هیچ گاه شاهد بیکار شدن پردازنده نخواهیم بود و گویی در یک زمان هر پردازنده در حال انجام دو کار است. قبول داریم که این توضیحات آنچنان دقیق و فنی نیستند اما برای پیش‌برد مباحث همین مقدار برای ما کافی است.

        اما ترد‌ها از این جنبه برای ما اهمیت دارند که مثلا در فرآیند رندرینگ، موتور یونیتی تمامی کارها را با سه نوع ترد Main Thread یا ترد اصلی، Render Thread یا ترد رندر و Worker Thread یا ترد کارگر انجام می‌دهد. ترد اصلی عمده وظایف مربوط به پردازنده‌ی مرکزی و البته تعدادی از کارهای مربوط به رندر را در بازی ما بر عهده دارد و این در حالی است که ترد رندر صرفا وظیفه‌ی ارسال دستورات را به کارت‌گرافیک یا همان پردازنده‌ی گرافیکی بر عهده دارد. در این میان هم هر یک از ترد‌های کارگر وظیفه‌ی انجام یک کار مشخص را بر عهده دارند که برای پیچیده‌تر نشدن موضوع فعلا به آن‌ها اشاره نمی‌کنیم. اما نکته‌‌ای که در این بین برای ما اهمیت دارد در قدم اول این است که هر چقدر تعداد هسته‌ها و به دنبال آن ترد‌های یک پردازنده‌ی بیشتر باشد، ما ترد‌های کارگر بیشتری را در اختیار داریم و برای همین می‌توانیم کارهای بیشتری را به صورت همزمان انجام دهیم.

        اگر چه وجود ترد‌های کارگر بیشتر می‌تواند برای ما مفید باشد اما همین تمرکز تعدادی از کارها روی یک ترد مشخص (ترد اصلی یا ترد رندر) امروزه باعث شده که پردازنده‌های مرکزی با تعداد هسته‌ها و البته ترد‌های بالا به علت فرکانس کاری پایین‌تر نتوانند بهترین عملکرد را در بازی‌ها برای ما داشته باشند. دلیل این مسئله در این است که همانند موتور یونیتی بیشتر موتورهای بازی‌سازی بخش مهمی از کارهای تولید یک فریم را بر عهده‌ی یک ترد مشخص گذاشته‌اند و یک ترد هم نمی‌تواند با بیشتر از یک هسته پردازنده در ارتباط باشد. حال هر چقدر فرکانس کاری آن هسته بیشتر باشد، او می‌تواند تعداد کارهای بیشتری را در یک ثانیه به انجام برساند. پس هر چقدر عملکرد تک هسته‌ی پردازنده‌ی شما بهتر باشد، عملکرد آن در تولید فریم‌های بازی هم بیشتر خواهد بود و این همان دلیل عمده‌ی برتری پردازنده‌های اینتلی در بازار گیمینگ است.

        البته در این نقطه بد نیست به این مسئله هم اشاره کنیم که امروزه با گسترش APIهایی از قبیل Vulkan که تمرکز خود را روی بهره‌گیری از حداکثر ظرفیت پردازنده‌های چند هسته‌ای گذاشته‌اند، شاهد این هستیم که تعداد هسته‌های بالاتر عملا عملکرد بهتری به نسبت تعداد هسته‌های پایین‌تر حتی با فرکانس کاری بالاتر دارند. نمونه‌ی بارز این مسئله بازی Wolfenstain 2 است که بر اساس معماری گفته شده تولید شده و با این که بازی از گرافیک بالایی هم برخوردار است اما همواره نرخ فریم‌های میانگین و کمینه‌ی آن به مراتب بیشتر از دیگر بازی‌های بازار است.

        اما از این مسائل که بگذریم اهمیت سه دسته ترد‌ اشاره شده در این است که ما می‌توانیم در بخش پروفایل کردن بازی بفهمیم که در انجام وظیفه‌ی کدام یک از این تردها مشکل به‌وجود آمده و این گونه فکری برای حل آن مشکل بکنیم.

        unity profiler

        مثلا اگر ما در بخش پروفایلینگ بازی خود مشاهده کردیم که عملیات Culling (عملیاتی برای شناسایی اشیایی که نباید رندر شوند) که روی یک ترد کارگر در حال اجرا است، عامل کندی اجرای بازی ما است، کاهش مدت زمان ارسال دستورات به پردازنده‌ی گرافیکی که روی ترد رندر در حال انجام است، هیچ کمکی به ما نخواهد کرد.

        با این که موتور یونیتی در به کار گیری بهینه هسته‌ها و ترد‌های متعدد یک پردازنده آنچنان تعریفی ندارد ولی در نسخه‌های جدید آن قابلیت جدیدی به نام Graphics Jobs به صورت آزمایشی قرار داده شده که شما می‌توانید با فعال کردن آن از بخش Player Setting تعدادی از وظایف مرتبط با رندر ترد اصلی یا حتی ترد رندر را به ترد‌های بیکار کارگر بدهید و این گونه راندمان اجرای بازی خود را افزایش دهید. البته همان گونه که اشاره شد این قابلیت آزمایشی است و ممکن است حتی هیچ تاثیری روی راندمان بازی شما نداشته باشد. برای همین با استفاده از ابزار پروفایلر یونیتی تاثیر آن روی بازی خود را حتما بررسی کنید.

        ارسال دستورات به پردازنده‌ی گرافیکی

        این مسئله که کاملا مرتبط به ترد رندر است شایع‌ترین مشکل در دسته مشکلات CPU bound است. هزینه‌برترین عملیات در فرآیند ارسال دستورات، SetPass Call نام دارد و برای همین بهترین گزینه برای رفع مشکلمان کاهش تعداد انجام این عملیات است.

        برای این که بتوانیم تعداد SetPass Calls و البته Batches را مشاهده کنیم می‌توانیم در همان بخش پروفایلر یونیتی به Rendering رفته و با کلیک روی نمودار تولید شده این اطلاعات را مشاهده کنیم.

        unity profiler

        البته صرفا از روی این که چه تعداد SetPass Call یا Batches داریم نمی‌توانیم هیچ گونه نتیجه‌گیری کنیم. چرا که مثلا یک رایانه‌ی قدرتمند توانایی پردازش تعداد بالایی از موارد گفته شده را دارد و این در حالی است که یک رایانه‌ی ضعیف‌تر این گونه نیست. شما مثلا می‌توانید به طور جداگانه و انجام آزمایش روی چند دسته مختلف از سخت‌افزارها، حد و حدود هر کدام را برای خود مشخص کنید.

        رابطه‌ی بین SetPass Calls و Batches تحت تاثیر عوامل متعددی است اما در بیشتر حالات اگر ما بتوانیم بدون تغییر وضعیت رندر تعداد بیشتری از اشیا را رندر کنیم می‌توانیم SetPass Callهای کمتری داشته و عملکرد پردازنده‌ی مرکزی را بهبود ببخشیم. البته گاهی کم کردن تعداد Batch تاثیری روی تعداد SetPass Calls ندارد ولی با این حال همواره تاثیر آن روی عملکرد پردازنده موثر خواهد بود. سه روش کلی کم‌کردن تعداد SetPass Calls به قرار زیر است:

          استفاده از هر کدام از این روش‌ها بستگی به بازی شما دارد و ممکن است هر کدام از این موارد بتواند مختصر تاثیری روی بازی شما داشته باشد.

          کاهش تعداد اشیایی که رندر می‌شوند

          اولین و ساده‌ترین روش برای رسیدن به این مسئله، کم‌کردن واقعی تعداد اشیای درون صحنه است. به عنوان مثال در مقاله‌های قبلی و در رابطه با بازی یکی از دوستان اعلام کرده بودیم که این حجم از جزییات درون بازی آنچنان ضروری نیست و بسیاری از آن‌ها توسط مخاطب تشخیص داده نمی‌‌شوند. حتی مثلا در صحنه‌هایی که جمعیت زیادی در حال حرکت است به راحتی می‌توانیم با تغییر زاویه دوربین و کمی خلاقیت، با تعداد کمی از افراد مثلا یک تظاهرات بزرگ را شبیه‌سازی کنیم و این گونه از اشیایی که در صحنه‌ی ما قرار می‌گیرند کم کنیم.

          Unity / یونیتی

          دومین روش استفاده از همان تعیین فاصله‌ی رندر دوربین در صحنه است که در یونیتی با عنوان Clipping Planes و در آنریل با عنوان Cull Distance Volume در دسترس است. البته در این وضعیت معمولا باید با استفاده از تکنیک‌هایی فاصله‌های رندر نشده را از دید مخاطب پنهان کنیم که به عنوان مثال استفاده از افکت Fog در این زمینه می‌تواند مفید باشد که برای استفاده از این افکت در موتور یونیتی باید نکات مربوط به آن را رعایت کنید.

          البته چون مبنای این مقاله موتور یونیتی است بد نیست بدانید که می‌‌توانید در یونیتی لایه‌های مختلفی را برای تعیین فاصله‌ی رندر تعریف کنید و این گونه مثلا میان حد فاصله‌ی رندر نشدن اشیای کوچک و بزرگ تفاوت قائل شوید. شما می‌توانید این مبحث را از این لینک (Layer Cull Distances) مطالعه کنید. البته در موتور یونیتی شما با استفاده از عنصر نام برده شده می‌توانید به طور اختصاصی برای بخشی از بازی خود و متناسب با اندازه‌ی عناصری که در آن بخش قرار دارند، فاصله‌ی مورد نیاز برای نادیده گرفته شدن هر شی را مشخص کنید که به نسبت موتور یونیتی از ظرافت به مراتب بیشتری برخودار است.

          آخرین راهکار برای کاهش تعداد اشیای رندر شده استفاده از قابلیت Occlusion Culling در موتور یونیتی است که در مورد آن قبلا توضیح داده‌ایم. این قابلیت در یونیتی برای همه صحنه‌ها مفید نیست و حتی ممکن است بار اضافی را بر پردازنده مرکزی تحمیل کند. برای همین طبق اسناد این موتور بهتر است این مقاله را برای استفاده بهتر از این قابلیت مطالعه کنید. البته شما همچنان می‌توانید به صورت دستی هم چنین کاری را برای اشیای درون صحنه‌ی خود انجام دهید که برای انجام این کار باید به دسته بندی و استفاده از تگ‌ها در یونیتی و فعال و غیرفعال کردن قابلیت‌ها از طریق کدنویسی کمی مسلط باشید.

          در انتهای این بخش این نکته را به ذهن بسپارید که حتی خود سازندگان موتورهای بازی‌سازی و از جمله یونیتی به این نکته تاکید کرده‌اند که همواره تنظیمات دستی و تجربه‌‌های شخصی می‌توانند بهتر از فرآیندهای خودکار موتورهایشان عمل کنند و دلیل آن ظرافتی است که در حالت دستی می‌توان در بازی اعمال کرد.

          کاهش تعداد دفعات رندر شدن هر شی

          با این که نورهای پویا، سایه‌ها و بازتاب‌ها جلوه‌های بسیاری باورپذیری را به بازی ما می‌دهند اما استفاده از آن‌ها می‌تواند برای ما بسیار هزینه‌بر باشد. مثلا با هر بار جابجایی مختصر شما درون تصویر سیستم مجبور می‌شود برای محاسبه‌ی تک‌تک این موارد از ابتدا اشیایی بسیاری را دوباره رندر کند که این مهم بسیار هزینه‌بر و سنگین است.

          تاثیر این مسئله به طور مستقیم به نوع Rendering Path انتخابی شما برای بازی بستگی دارد. اصطلاح بیان شده نوع انجام محاسبات لازم برای ترسیم یک صحنه را مشخص می‌کند و تفاوت عمده‌ی مدل‌های مختلف آن در نوع محاسبه‌ی نورهای پویا، سایه‌ها و بازتاب‌ها است. مثلا دو نوع معروف در این زمینه Defferred Rendering و Forward Rendering هستند که بر اساس یک قانون کلی استفاده از Deffered Rendering در سیستم‌‌های بالارده و بازی‌هایی که از سه عنصر گفته شده به فراوان استفاده کرده‌اند توصیه می‌شود. اما در مقابل برای سیستم‌های پایین‌رده و بازی‌هایی که از عناصر گفته شده استفاده نمی‌کنند، Forward Rendering گزینه‌ی مناسب‌تری است. توضیح بیشتر در این رابطه خارج از حال این مقاله است ولی در اهمیت این مبحث همین قدر بدانید که مثلا اگر بخواهید از قابلیت Fog در بازی خود استفاده کنید نمی‌توانید از Defferred Rendering استفاده کنید. پس یا باید این حالت را تغییر داده یا به جای Fog از افکت‌پس‌پردازشی آن درون بازی خود استفاده کنید.

          deferred and forward rendering

          جدای از این که کدام یک از دو حالت گفته شده را انتخاب می‌کنید، باید فکری به حال سه عنصر گفته شده در بازی خود بکنید که تاثیر بسزایی در عملکرد فنی بازی شما دارند. مواردی که نام برده می‌شوند هر کدام دارای توضیحات مرتبط با خودش است که در مواردی ما صرفا شما را به لینک‌های مربوطه برای مطالعه بیشتر ارجاع می‌دهیم.

            ترکیب اشیا در دسته‌های کمتر

            ما با استفاده از تکنیک‌هایی می‌توانیم اشیا را در دسته‌های کم‌تری قرار دهیم ولی برای این کار باید دو مورد زیر رعایت شود:

            • به اشتراک‌گذاری نمونه‌ی یکسانی از یک متریال در میان چند شی
            • داشتن تنظیمات متریال یکسان در میان اشیا

            دسته‌بندی یا همان Batching اشیا می‌تواند روی عملکرد بازی شما تاثیر مثبتی داشته باشد ولی با تمامی این‌ها باید به این نکته توجه کنید که هزینه‌ی انجام خود عمل دسته‌بندی نباید آنقدری بالا برود که خودش برای بازی ایجاد مشکل کند. برای همین همواره سعی کنید از طریق پروفایل کردن بازی این مسئله را زیر نظر داشته باشید.

            Static Batching تکنیکی است که یونیتی با استفاده از آن اشیای نزدیک به یکدیگر و غیرمتحرک را در یک دسته قرار می‌دهد. به عنوان مثال ستون‌های یک ساختمان می‌تواند مثال خوبی برای این مسئله باشد. شما برای هر شی می‌توانید از بخش Inspecter این گزینه را فعال کنید اما برای آشنایی بیشتر با این مسئله می‌توانید از این لینک استفاده کنید. به این مسئله توجه کنید استفاده از این تکنیک میزان مصرف حافظه‌ی رم شما را افزایش می‌دهد. پس این بخش از منابع سخت‌افزاری را در پروفایلر زیر نظر داشته باشید.

            Dynamic Batching تکنیک دیگری است که یونیتی با استفاده از آن تمامی اشیا چه ثابت و چه متحرک را دسته‌بندی می‌کند اما مسئله‌ای که وجود دارد محدودیت‌های این روش است که در این لینک در مورد آن‌ها صحبت شده است. به عنوان مثال این تکنیک صرفا بر مش‌های عمل می‌کند که از تعداد راس کم‌تر از ۹۰۰ عدد تشکیل شده باشند که نکته‌ی قابل توجهی است. این تکنیک به راحتی می‌تواند بیشتر از میزان هزینه‌ای که از پردازنده‌ی مرکزی کم می‌کند خود به آن اضافه کند و برای همین باید در استفاده از آن بسیار هشیار باشید.

            GPU Instancing به ما اجازه می‌دهد که تعداد زیادی از اشیای یکسان را با استفاده از آن دسته‌بندی کنیم. البته محدودیت‌هایی هم بر استفاده از این تکنیک وجود دارد که از نمونه‌های آن می‌توانیم به پشتیبانی نکردن تمامی سخت‌افزارها از این تکنیک اشاره کنیم. شما می‌توانید از این لینک اطلاعات مربوط به این تکنیک را به دست آورید.

            gpu instancing

            Texture Atlasing در مواقعی کاربرد دارد که در آن چندین بافت در قالب یک بافت بزرگ‌تر با یکدیگر ترکیب شده‌اند. با این که غالبا این وضعیت در بازی‌های دوبعدی و رابط‌کاربری‌ها(به دلیل ماهیت دوبعدی آن‌ها) به‌وجود می‌آید ولی همچنان این تکنیک را می‌توان در بازی‌های سه‌بعدی هم مورد استفاده قرار دارد. اگر ما از این تکنیک در هنگام آماده کردن آرت‌های خود استفاده کنیم می‌توانیم مطمئن باشیم که اشیایی که به صورت اشتراکی از این بافت‌ها استفاده می‌کنند به راحتی توسط سیستم پردازنده‌ دسته‌بندی خواهند شد. همچنین بد نیست بدانید که موتور یونیتی دارای ابزاری در این زمینه برای بازی‌های دوبعدی است که با نام Sprite Packer شناخته می‌شود.

            spriter packer

            همچنین شما می‌توانید خودتان هم به صورت دستی عمل دسته‌بندی را انجام دهید که البته کار بی‌خطری هم نیست. این مسئله به راحتی می‌تواند مسائل فنی مرتبط با سایه‌های این اجسام، نورپردازی و حتی نادیده‌گرفته شدن آن‌ها را تحت تاثیر قرار بدهد. مثلا ممکن است در حالی که انجام این کار کمی روی بهبود عملکرد فنی بازی شما تاثیر داشته باشد، عملا امکان نادیده‌گرفتن این اشیا در تصاویر رندری را از شما سلب کند.

            تقریبا تا انتهای این مقاله مطالب مرتبط با بهینه‌سازی یک بازی به خصوص بخش مرتبط با پردازنده‌ی مرکزی آن را در موتور یونیتی پوشش دادیم که البته همان گونه که از ظاهر مطلب پیدا است، برای درک دقیق مطالب آن باید مطالب لینک شده‌ی زیادی را مطالعه کنیم. به هر جهت در مقاله‌ی بعدی با ادامه و تکمیل مبحث بهینه‌سازی در خدمت شما خواهیم بود.

            کپی لینک

            دسترسی به فهرست مقالات بازی‌ سازی

              مقاله رو دوست داشتی؟
              نظرت چیه؟
              داغ‌ترین مطالب روز

              نظرات