بازی و سرگرمی

گیمولوژی | رسانه تحلیلی بازی سازی | شیدر نویسی در یونیتی (بخش دوم)

قبل از شروع شیدر نویسی بهتر است به چند سوال متداول پاسخ دهیم:

 

شیدر چیست و چه لزومی دارد که از آنها استفاده کنیم؟

 

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

 

چه نیازی به یادگیری شیدرنویسی داریم در صورتی که می توانیم از شیدر های آماده و پیش فرض استفاده کنیم؟

 

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

 

تعاریف شیدر، متریال و تسکچر

 

شیدر یک کد است که رفتار نورپردازی و ویژگی های رندر آبجکت یا افکت های دوربین را توصیف می کند اما متریال تعیین می کند که چگونه یک سطح باید رندر شود. متریال ها می توانند داده های مختلفی را برحسب نیاز سایه زن در خود نگه دارند از جمله رفرنس بافت استفاده شده، اطلاعات کاشی کاری (Tiling Information)، رنگ و غیره .

 

بافت ها (Textures) تصاویر Bitmap هستند. یک متریال ممکن است رفرنس به یک بافت داشته باشد به طوری که شیدرِ متریال در هنگام محاسبه می تواند رنگ سطحی یک شی را از بافت ها استفاده کند. علاوه بر رنگ پایه (Albedo)، بافت ها می توانند بسیاری از جنبه های دیگر سطح متریال مانند زبر و مات یا صیقلی و براق بودن را تعیین کنند.

 

نکات:

 

گزینه های موجود در یک متریال بستگی به شیدر استفاده شده در متریال دارند. شیدر یک یا چند متغیر بافتی که انتظار می رود استفاده شود را مشخص می کند و Inspector Material  در Unity به شما اجازه می دهد که ورودی های بافت خود را به این متغیرهای بافت اختصاص دهید.

 

اين نكته را مد نظر قرار دهید که شیدرها اغلب برای کنترل نور و اثرات سایه ای استفاده می شوند اما هیچ دلیلی وجود ندارد که توانایی آن ها به همین موارد محدود شود.

 

آیا دانستن برنامه نویسی برای نوشتن شیدر امری ضروری است؟ زبان شیدر نویسی در یونیتی چیست؟

 

برای شروع شیدر نویسی بهتر است مشکلی در برنامه نویسی نداشته باشید تا مسیر برای تان هموارتر گردد. یادگیری زبان شیدر مانند روال یادگیری زبان برنامه نویسی جدید است. مفاهیم زبان های برنامه نویسی تقریباً یکسان است؛ بنابراین همان طور که برای یادگیری برنامه نویسی لازم است از قواعد دستوری (Syntax) و معناشناسی (Semantics) آن زبان پیروی کنید، برای شیدرنویسی هم باید همین روال را طی کنید.

 

تفاوت شیدر و متریال در چیست؟

 

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

 

شاید شما علاقه ای به کدنویسی نداشته یا دنبال راه های ساده تری برای نوشتن شیدر باشید، در این صورت باید این نکته را هم مدنظر قرار داد که شما می توانید شیدر را به صورت بصری ایجاد کنید (Visual Programming ). این کار نه تنها آسان تر است بلکه دیگر نیاز به نوشتن کدهای طولانی ندارید. ابزارهایی نظیر ShaderForge و Amplify Shader Editor دارای محیطی گرافیکی هستند که شما را قادر می سازد تا با استفاده از اتصال یکسری Nodeهای مختلف، شیدر خود را به راحتی ایجاد کنید.

 

برنامه نویسی شیدر چه پیش نیازهایی دارد؟

 

در برنامه نویسی شیدر لازم است تا با مفاهیم اولیه ی گرافیک کامپیوتری و ریاضی (ماتریس ها، نسبت های مثلثاتی و…) آشنا باشید تا درک بهتری از اصطلاحات گرافیکی ، توابع و الگوریتم های ریاضی داشته باشید.

 

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

 

تصویر بالا سیر تکامل زبان شیدرنویسی را نشان می دهد

 

آناتومی شیدر

 

Unity3D از دو نوع مختلف شیدر پشتیبانی می کند: Surface Shader و Fragment and Shader Vertex. نوع سومی هم به نام شیدرهای تابع ثابت (Fixed Function Shaders) وجود دارد، اما آنها اکنون منسوخ شده و در این سری از پست ها پوشش داده نخواهند شد. صرف نظر از این که کدام نوع متناسب با نیازهای شماست، آناتومی یک شیدر برای همه آنها یکسان است:

 

 

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

 

Properties

 

ویژگی های (Properties) شیدر شما به نوعی معادل با فیلدهای Public در اسکریپت #C است؛ آنها در Inspector متریال ظاهر شده و به شما این امکان را می دهد تا آنها را تغییر بدهید.

 

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

 

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

 

 

نوع دوبعدی که در خطوط 34 استفاده شده، نشان می دهد که پارامترها بافت هستند. آنها می توانند به سفید، سیاه یا خاکستری روشن مقداردهی اولیه شوند. شما همچنین می توانید از Bump برای مقداردهی استفاده کنید تا تکسچر به عنوان نرمال مپ استفاده شود. در این مورد، آن به صورت خودکار به رنگ # 808080 (خاکستری) مقداردهی اولیه می شود. بردارها و رنگ ها همواره دارای چهار عنصر XYZW و RGBA هستند.

 

تصویر زیر نشان می دهد که چگونه این ویژگی ها زمانی که شیدر به یک متریال متصل است در Inspector نمایش داده می شود.

 

 

متاسفانه تعریف ویژگی ها به تنهایی کافی نیست. بخش Properties در واقع توسط Unity3D برای دسترسی از Inspector به متغیرهای پنهان در یک شیدر استفاده می شود. این متغیرها هنوز باید در قسمت اصلی شیدر تعریف شوند که در قسمت SubShader موجود است. یعنی هر ویژگی ای که تعریف می شود باید یک متغیر متناظر هم برای آن تعریف کنیم.

 

 

نوع مورد استفاده برای بافت Sampler2D است. بردارها Float4 هستند و رنگ ها به طور کلی Half4 هستند که از 32 و 16 بیت استفاده می کنند.

 

با این حال، انواع داده لازم نیست: شما هیچ خطایی برای اعلام _MyRange به عنوان half به جای float نخواهید داشت. در حین کار شاید به مواردی نسبتاً گیج کننده برخورد کنید؛ به عنوان مثال اگر بتوانید یک ویژگی از نوع Vector را تعریف کنید که به متغیر float2 مرتبط است، دو ارزش اضافی توسط Unity3D نادیده گرفته می شود.

 

دستور رندر

 

همان طور که قبلا ذکر شد، بخش SubShader حاوی کد اصلی شیدر است که در Cg / HLSL نوشته شده و بسیار شبیه به C است.

 

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

 

بدنه ی شیدر، به طور معمول به گونه ی زیر تعریف می شود:

 

 

خطوط 811 شامل کد اصلی Cg است. بخش توسط دستورالعمل CGPROGRAM و ENDCG اعلام شده است.

 

خط 3 قبل از بدنه ی واقعی، مفهوم برچسب ها (Tags) را معرفی می کند. برچسب ها یک راه برای گفتن ویژگی های خاص شیدری است که آن را می نویسیم. به عنوان مثال، برچسب مربوط به ترتیب رندر شدن (Queue) و نحوه رندر کردن آن (RenderType) است.

 

نکته: RenderType برای Replacement Shaders استفاده می شود. به این صورت که شیدر جایگزین این برچسب ها را خوانده و سپس از یک شیدر مناسب دیگر استفاده می کند. حتی اگر از شیدر های جایگزین استفاده نکنید بهتر است که شیدرهای خود را برای استفاده در آینده برچسب دار کنید. لینک

 

GPU هنگام رندر معمولا آن ها را با توجه به فاصله خود از دوربین مرتب می کند، به طوری که بیشتر آن ها برای اولین بار رسم می شوند. این کار برای رندر اشیای جامد هندسی(Solid Geometries)  کافی است اما اغلب اشیای شفاف با شکست مواجه می شود.

 

Background (پس زمینه) (1000): مورد استفاده برای پس زمینه و skyboxes.
Geometry (هندسه) (2000): برچسب به طور پیش فرض مورد استفاده برای بیشتر اجسام جامد.
Transparent (شفاف (3000):( مورد استفاده برای متریال هایی که ویژگی شفافیت دارند، مانند شیشه، آتش، پارتیکل ها و آب.
Overlay (روکش) (4000): مورد استفاده برای جلوه هایی مانند شعله ور شدن لنز، عناصر رابط کاربری گرافیکی و متون.

 

یونیتی همچنین اجازه می دهد تا دستورات مرتبط مانند  Background+2 که ترتیب مقدار 1002 را نشان می دهد را مشخص کنید. از دست دادن ترتیب می تواند شرایط تند و زننده ای تولید کند که در آن یک شی همیشه رسم شده است. حتی زمانی که آب باید توسط مدل های دیگر پوشش داده شود.

 

ZTEST

 

نکته ی مهمی که باید به یاد داشته باشید این است که یک شیء شفاف، لزوما همیشه زودتر از یک شیء هندسی ظاهر نمی شود.

 

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

 

Surface versus vertex and fragment

 

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

 

The Surface Shader

 

هرگاه متریالی که می خواهید شبیه سازی کنید به تأثیرات نورپردازی واقعی نیاز داشت ، بهتر است از Surface Shader استفاده کنید.

 

Surface Shaders  محاسبات چگونگی بازتاب نور را پنهان می کرده و اجازه می دهد تا ویژگی های “بصری” مانند albedo ، normals ، بازتاب و غیره را در یک تابع به نام surf مشخص کنیم. این مقادیر سپس به یک مدل نورپردازی متصل می شوند که مقدار RGB نهایی را برای هر پیکسل نشان می دهد. همچنین شما می توانید مدل نورپردازی خود را بنویسید، اما این فقط برای اثرات بسیار پیشرفته مورد نیاز است.

 

کد Cg یک surface shader معمولی به گونه ی زیر تعریف می شود:

 

 

 

خط 5 یک بافت را وارد می کند و سپس به عنوان ویژگی Albedo  متریال در خط 12 تعریف می شود. شیدر از مدل نورپردازی Lambertian (خط 3) استفاده می کند که روشی بسیار معمول برای مدل سازی چگونگی بازتاب نور روی یک شی است. شیدرهایی که فقط از ویژگی های albedo استفاده می کنند معمولا diffuse نامیده می شوند.

 

The Vertex and Fragment Shader

 

شیدرهای Vertex and fragment خیلی نزدیک به کاری است که نحوه پردازش گرافیکی مثلث ها (triangles) می کنند و هیچ مفهوم ساخته شده در مورد چگونگی رفتار نور را ندارد. هندسه مدل شما برای اولین بار از یک تابع به نام vert عبور داده می شود که می تواند رأس های آن را تغییر دهد. سپس مثلث ها به طور جداگانه از طریق تابع دیگری به نام frag عبور داده می شود که رنگ RGB نهایی را برای هر پیکسل تعیین می کند. این شیدرها برای اثرات دوبعدی، پس پردازش(postprocessing) و جلوه های ویژه سه بعدی مفیدند که در نظر گرفتن آنها به عنوان Surface Shaders بسیار پیچیده است(چون Surface Shaders مدل های نورپردازی از قبل تعریف شده و کارهای طولانی را خلاصه کرده، لذا برای نوشتن شیدری متفاوت نیاز دارید تا از fragment shader استفاده کنید و شیدرتان را از صفر بنویسید).

 

vertex and fragment shader زیر به سادگی یک شی یکنواخت را قرمز و بدون نور می کند.

 

 

 

خطوط 1517 خطوط را از فضای محلی بومی خود به حالت دوبعدی نهایی روی صفحه تبدیل می کنند.

 

یونیتی UNITY_MATRIX_MVP  را برای این تعریف کرده است تا ریاضی پشت آن را پنهان کند. پس از این، خط 22 به هر پیکسل رنگ قرمز می دهد. فقط به یاد داشته باشید که بخش Cg در vertex and fragment shaders باید در بخش عبور قرار گیرد (ورتکس و فرگمنت شیدر را باید پاس بدهید، ولی سرفیس شیدر را بدون پاس همان طور در ساب شیدر می نویسید).این مورد برای شیدرهای ساده ی surface shaders نیست، یعنی با آن یا بدون آن هم کار می کند.

 

نکته: mul(UNITY_MATRIX_MVP, float4(pos, 1.0)) با UnityObjectToClipPos معادل است. (لینک)

 

نکته: ماتریس مدل، مشاهده و طرح ریزی (Model View Projection) سه ماتریس جداگانه است که مدل را از فضای مختصات محلی (Local Position) جسم به فضای جهان(World Position)، نمایش (View) از فضای جهان به فضای دوربین و طرح ریزی از دوربین به صفحه نمایش را تعیین می کند.

 

Model Space, World Space, View Space

 

 

 

منابع :

 

Unity 5.x Shaders and Effects Cookbook

 

thebookofshaders

 

https://docs.unity3d.com/Manual/SL-ShadingLanguage.html

 

https://unity3d.com/learn/tutorials/topics/graphics/gentle-introduction-shaders

 

https://gamedevelopment.tutsplus.com/tutorials/a-beginners-guide-to-coding-graphics-shaders-cms23313

 

https://docs.yoyogames.com/source/dadiospice/002_reference/shaders/index.html

 

A gentle introduction to shaders in Unity3D

 

https://en.wikipedia.org/wiki/Shader

مقالات مرتبط

دیدگاهتان را بنویسید

نشانی ایمیل شما منتشر نخواهد شد. بخش‌های موردنیاز علامت‌گذاری شده‌اند *

دکمه بازگشت به بالا