چرا طراحان بازی باید انیمیشن یاد بگیرند؟

فرناز حقیقت

۱۳۹۵/۱۲/۰۹

روابط عمومی
b

آنالیز: صنعت بازی سازی لهستان – قسمت سوم (آخرین قسمت)

رهام سجادی

۱۳۹۵/۱۲/۱۳

عضو تحریریه
b

سرگردان در بازی؛ آشنایی با بازی‌های جهان باز

رهام سجادی

۱۳۹۵/۱۱/۲۸

عضو تحریریه
b

خنک بنوشید؛ گزارش جنجالی پازل از برگزاری رویداد گیمیکس و فرمول محرمانه معجون بازی‌سازی

پازل

۱۳۹۵/۱۱/۲۴

آشنایی با ارزش طول عمر کاربر و نحوه محاسبه آن

حسین مزروعی

۱۳۹۵/۱۱/۱۶

آنالیز: صنعت بازی‌سازی لهستان - قسمت اول

تحریریه گیمولوژی

۱۳۹۵/۱۱/۰۴

روایت در بازی‌های رایانه‌ای – قسمت دوم

ماکان علیخانی

۱۳۹۵/۱۰/۲۵

عضو تحریریه
b

گسترش نگاه؛ طعم اولین معجون بازی سازی

علیرضا محمدی

۱۳۹۵/۱۰/۲۱

سردبیر
b

روایت در بازی‌های رایانه‌ای – قسمت اول

ماکان علیخانی

۱۳۹۵/۱۰/۰۶

عضو تحریریه
b

شیدرنویسی در یونیتی (بخش اول)

در مقاله‌ی قبلی توضیحاتی درباره‌ی شیدر و عملکرد GPU و CPU و انواع شیدر را به صورت اجمالی بررسی کردیم.در این مقاله سعی داریم کمی بیشتر وارد جزئیات شویم تا درک بیشتری از لزوم استفاده‌ی شیدر داشته باشیم.

انواع شیدر:

2D Shaders

شیدرهای دوبعدی روی تصاویر عمل می‌کنند و در گرافیک کامپیوتری «تکسچر» (Texture) نیز نامیده می‌شوند. آنها ویژگی‌های پیکسل را تغییر می‌دهند. در حال حاضر تنها شیدر دوبعدی، شیدرهای پیکسلی هستند. 

Pixel Shaders

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

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

چرا شیدر‌ها سریع هستند؟

برای پاسخ دادن به این سوال، بهتر است شگفتی‌های پردازش موازی را با ذکر یک مثال بررسی کنیم: تصور کنید CPU کامپیوتر شما به عنوان یک لوله صنعتی بزرگ و هر کار به عنوان چیزی است که از آن عبور می‌کند - درست مثل یک Pipe Line.

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

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

بیایید به استعاره لوله‌ها و وظایف‌مان بازگردیم. هر پیکسل روی صفحه‌نمایش نشان‌دهنده‌ی یک کار ساده است. به طور جداگانه هر یک از کارهای پیکسل مسئله ای برای CPU نیست، اما (اینجا مشکل است) کار کوچک باید به هر پیکسل روی صفحه اعمال شود!

این بدان معنی است که در صفحه نمایش 800x600 قدیمی، 480،000 پیکسل باید در هر فریم پردازش شود که به معنی 14،400،000 محاسبات در ثانیه است. بله این مسئله به اندازه‌ای بزرگ است که میکروپروسسور را بیش از حد بارگذاری می‌کند. در یک صفحه نمایش شبکیه 2880x1800 مدرن که در محدوده 60 فریم در ثانیه اجرا می‌شود، محسابات تا 311،040،000 در ثانیه افزایش پیدا می‌کند. مهندسان گرافیک چگونه این مشکل را حل کردند؟

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

ریزپردازنده‌های کوچک را به عنوان یک جدول از لوله ها و داده‌های هر پیکسل را به عنوان توپ پینگ پنگ در نظر بگیرید.

14،400،000 توپ پینگ پنگ در یک ثانیه تقریبا می‌تواند هر لوله‌ای را مسدود کند. اما یک میز از 800x600 لوله کوچک دریافت 30 موج 480،000 پیکسل در ثانیه را می‌تواند به صورت روان رسیدگی کند. این در رزولوشن‌های بالاتر هم کار می کند. جریان سخت‌افزار موازی شما، می‌تواند بزرگ‌تر باشد.

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

 Pixel Shaders، که همچنین به عنوان Fragment Shaders شناخته می‌شوند، محاسبه رنگ و ویژگی‌های دیگر هر پیکسل را بر عهده دارند. ساده‌ترین نوع این شیدر، خروجی یک پیکسل صفحه‌نمایش، به عنوان یک رنگ است؛ شیدرهای پیچیده‌تر با چند ورودی/خروجی نیز امکان پذیر است. شیدرهای پیکسلی همیشه از یک رنگ یکسان، برای اعمال مقدار نوردهی، برای انجام Bump Mapping، سایه، برجستگی‌های ظریف، شفافیت و سایر پدیده‌ها استفاده می‌کنند. آن‌ها می‌توانند عمق فرگمنت (برای Z-buffering) یا خروجی بیش از یک رنگ را اگر چندین هدف رندر فعال باشند تغییر دهند. شیدر برای هر راس را Vertex Shader و برای هر پیکسل بافت را Fragment Shader می‌نامند.

به طور کلی حتی رسم یک مثلث دارای بافت (Textured Triangle) نیاز به یک شیدر دارد. در گرافیک سه بعدی، پیکسل شیدر به تنهایی نمی‌تواند جزئیات بسیار پیچیده‌ای اعمال کند، زیرا تنها در یک قطعه واحد (Single Fragment)، بدون اینکه از هندسه صحنه استفاده کند عمل می‌کند. با این حال، شیدرهای پیکسلی دانش هماهنگی صفحه نمایش را دارند و می‌توانند یک تکسچر را دریافت و به شیدر منتقل کنند. این تکنیک می‌تواند طیف گسترده‌ای از اثرات پس پردازش (Postprocessing) دو بعدی، مانند تاری یا تشخیص/تقویت لبه برای سایه‌های کارتونی را فعال کند. Pixel Shaders ممکن است در مراحل متوسط به هر یک از تصاویر دوبعدی یا بافت‌ها در خط لوله اعمال شود، در حالی که Vertex Shaders همیشه به یک صحنه‌ی سه‌بعدی نیاز دارد.

3D Shaders

شیدرهای سه بعدی بر روی مدل‌های سه بعدی یا هندسه‌های دیگر عمل می‌کنند اما ممکن است به رنگ‌ها و بافت‌های مورد استفاده برای طراحی مدل یا مش دسترسی پیدا کنند.

Vertex Shader

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

هر راس دارای مجموعه‌ای از ویژگی‌های ورودی تعریف شده توسط کاربر است. به عنوان مثال: موقعیت، بردار نرمال و مختصات بافت (Texture Position). شیدرهای ورتکس همچنین به متغیرهای یکنواخت دسترسی دارند که به عنوان متغیرهای جهانی (Read-Only Global ) برای تمام رئوس در یک رسم صدا زده می‌شوند.

Geometry Shaders

شیدر‌های هندسی نسبتا نوع جدیدی از شیدر هستند که در Direct3D 10 و OpenGL 3.2 معرفی شدند. قبلا در OpenGL 2.0+ با استفاده از Extensionsها موجود بوده است. این نوع شیدر می‌تواند شکل‌های اولیه‌ی گرافیکی جدیدی مانند نقاط، خطوط و مثلث را از شکل‌های اولیه که به ابتدای خط لوله گرافیکی ارسال می‌شود، تولید کند.

برنامه‌های Geometry Shader پس از Vertex Shaders اجرا می‌شوند. آن‌ها به عنوان ورودی یک شکل اولیه، این امر را با اطلاعات مجاور ممکن می‌سازند. به عنوان مثال، زمانی که در مثلث عمل می‌کند، سه رأس؛ ورودی شیدر هندسی است. پس از آن شیدر می‌تواند صفات اولیه یا بیشتر را که شطرنجی شده‌اند و قطعات آنها (Fragments)، در نهایت به یک Pixel Shader منتقل  می‌شود را منتشر کند.

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

 Point Sprite Generation, Geometry Tessellation, Shadow Volume Extrusion and Single Pass Rendering to a Cube Map

Tessellation shaders

همانطور که OpenGL 4.0 و Direct3D 11 به عنوان کلاس جدید شیدر نامیده می‌شوند، یک Tessellation Shader اضافه شده است. این دو مرحله جدید، شیدر را به مدل سنتی اضافه می‌کند: شیدرهای کنترل تسلیت (همچنین به عنوان شیدرهای بدنه - Hull Shaders - شناخته می‌شود) و شیدرهای ارزیابی تسلیت (همچنین به عنوان شیدر‌های دامنه - Domain Shaders - شناخته می‌شوند)، که به موجب آن می‌توانند مش‌های ساده‌تر را به مش‌های ظریف‌تر مطابق تابع ریاضی در زمان اجرا تقسیم کنند.

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

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

Primitive Shaders

معماری AMD Vega میکرو برای یک مرحله جدید شیدر/شیدر‌های اولیه اضافه شده است.

Compute Shaders به برنامه‌های گرافیکی محدود نمی‌شود، بلکه از منابع مشابه برای General Purpose GPU) GPGPU) استفاده می‌شود. آن‌ها ممکن است در خطوط گرافیکی مورد استفاده قرار گیرد. به عنوان مثال برای مراحل اضافی در انیمیشن یا الگوریتم‌های روشنایی مانند رندر پیش رونده (Tiled Forward Rendering). برخی از APIهای رندر اجازه می‌دهد که شیدر‌ها را محاسبه کنید تا به آسانی منابع داده‌ها را با خط لوله گرافیکی به اشتراک بگذارید.

هر بازی‌سازی که با انجین یونیتی کار می‌کند، با کمپوننت‌ها آشنا می‌باشد. کمپوننت چارچوبی است که از اجزای بسیار متفاوت تشکیل شده است.

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

 هر شی باید تنها یک MeshRenderer داشته باشد اما خود MeshRenderer می‌تواند چندین متریال داشته باشد. به طور کلی هر متریال یک جلد برای یک شیدر است.

 درک تفاوت بین این کمپوننت‌ها برای درک اینکه شیدر‌ها چگونه کار می‌کنند ضروری است.

نمودار زیر به راحتی بیانگر سه نهاد مختلف است که در گردش کار (Workflow) یونیتی نقش اصلی را بازی می‌کند:

مدل‌های سه بعدی اساساً مجموعه‌ای از مختصات سه بعدی به نام رأس هستند. آن‌ها برای ایجاد مثلث‌ها (Triangles) به یکدیگر متصل شده‌اند. هر رأس می‌تواند چندین اطلاعات دیگر مانند رنگ‌، جهت آن به سمت نقطه (نرمال) و برخی از مختصات برای ساخت بافت‌ها بر روی آن (به نام داده‌های UV) را داشته باشد.

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

دیدگاه‌ها

پاسخ
٠
٠

مهدی   |   ۱۳۹۶/۰۷/۲۷   |   ۲۰:۱۳

ممنون از شما عالیه

پاسخ
٠
٠

مرتضی کارگر   |   ۱۳۹۶/۰۸/۱۴   |   ۱۵:۴۲

واووووو...
ضمن تشکر بابت این مقاله تخصصی....ولی موضوعات خیلی پیچیده بود!
مقاله رو خوندم یه سوال برام پیش اومد و اگه جواب بدین ممنون میشم:
فرض کنیم یه گروهی درگیر توسعه موتور بازی‌سازی خودشون هستند، برای ساختن بخش گرافیکی موتور دقیقا با همین مباحثی که گفتین درگیرند یا این که این چیزا از قبل آماده‌اند (همانند Direct3D 10 و OpenGL 3.2) و اونا کافیه از این چیزای از پیش ساخته شده استفاده کنند؟ فکر کنم از جواب این سوال بفهمم چقدر از مقاله رو فهمیدم :)

پاسخ
٠
٠

Erfan   |   ۱۳۹۶/۰۸/۱۹   |   ۱۵:۵۷

بسیار قلم روان و خوبی بود
ممنون از شما