گیمولوژی | رسانه تحلیلی بازی سازی | مقدمات شِیدر نویسی در یونیتی
GPU چیست؟
Graphics Processing Unit) GPU) یک واحد پردازش است که مسئولیت سرعت بخشیدن و بهبود عملیاتهای گرافیکی کامپیوتر را بر عهده دارد. GPU ابزاری اختصاصی برای رندرهای گرافیکی در کامپیوترهای شخصی و کنسولهای بازی است. این واحد گاهی اوقات واحد پردازش بصری یا VPU نیز نامیده میشود. ویژگیهای GPUهای جدید برای پردازش و ارائه دادن کارهای گرافیکی، آنها را بسیار کارآمدتر از واحدهای پردازش مرکزی یا CPU در پردازش الگوریتمهای پیچیده کرده است.
مقایسه ی سرعت پردازش GPU و CPU
یک CPU با چهار (یا 8 یا 10) هسته ای که در آن است.
یک GPU با هزاران هسته که در آن است.
چگونه GPU در مقایسه با CPU سریع تر است؟
هسته CPU برای انجام عملیاتهای سریالی (ترتیبی) طراحی شده است در حالی که هسته GPU برای عملیات موازی یا به طور همزمان طراحی شده است.
شیدر چیست؟
هنگامی که ما کامپیوتر را به انجام هرگونه عملیاتی وادار میکنیم، در واقع باید یک سری دستورالعملهایی به آن بدهیم که این دستورالعملها برنامه (Program) نامیده میشوند. برای کمک به سایه زدن یا رسم چیزی روی صفحه نمایش از برنامهای به نام شیدر استفاده می شود.
شیدر مجموعه ای از دستورالعملها است که بر روی GPU (واحد پردازش گرافیکی) اجرا میشود.
انواع shaderهای مبتنی بر قابلیت های خود را میتوان براساس قابلیتها یا هدف شید به شکل زیر دستهبندی کرد:
1.Vertex shader (شیدر رئوس)
2.Pixel shader (شیدر پیکسل)
3 .Geometry shader (شیدر اشکال هندسی)
4.Compute shader (شیدر محاسبه)
5. Tesselation shader (شیدر موزاییک)
وقتی بخواهیم روی صفحه نمایش جسمی را رسم کنیم، باید آن را در قالب اشکال هندسی اولیه یا Mesh نشان دهیم.
Mesh چیست؟
Mesh از راس یا شکلهای هندسی اولیه تشکیل شده است. اگر ما بخواهیم شکل هندسی آبجکتی را در بازی رسم کنیم، آن شکل باید از Mesh ساخته شده باشد. علاوه بر این میتوان یک بافت (texture) را در Mesh استفاده کرد یا میتوان برای متحرک کردن کراکتر، Mesh را اسکلت بندی کرد(rigging). در سادهترین مرحله حتی اگر ما بخواهیم که بافتی را رسم کنیم، مجبوریم که یک Mesh کارت و پس از آن تکسچر را رسم کنیم. اگر بخواهیم چیزی را سایه بزنیم، باید یک شی را رسم کنیم (مانند Mesh آن اول) و سپس آن را سایه بزنیم.
شکلهای هندسی اولیه (Primitive) واحد اصلیMesh عبارتند از:
– Triangle مثلث
– Line(خط)
– Point (نقطه)
چگونه یک مثلث را بر روی صفحه نمایش رسم کنیم و سایه بزنیم؟
به منظور رسم یک مثلث بر روی صفحه نمایش، ما اول باید رئوس را به عنوان Mesh (که از رئوس تشکیل شده است) رسم کنیم. برای رسم رئوس باید از اولین نوع شیدرمان(Vertex Shader) استفاده کنیم. ما اطلاعاتِ موقعیت راس را جمع آوری میکنیم (علاوه بر آن میتواند شامل مقدار نرمال و اطلاعات رنگ باشد) و به شیدر ورتکس میدهیم تا روی صفحه نمایش نشان داده شود.
مشکل بعدی ما این است که چگونه منطقه ی بین این رئوس را پر کنیم. به عبارت دیگر، چگونه پیکسلهای صفحهی نمایش را در ناحیهی هندسی سایه بزنیم. برای انجام این کار، ما از Pixel Shaders استفاده میکنیم تا عملیات را اجرا کنیم. یک Pixel Shader، همچنین به عنوان Fragment Shader شناخته میشود که نوعی شیدر است که روی پیکسل یا یک فرگمنت کار میکند.
Fragment Shader: برای تعریف یک المان که در نهایت به رنگ نهایی پیکسل تبدیل میشود کمک میکند.
Tessellation Shader : همچنین به عنوان Hull Shader شناخته شده است. Shaderهای نسبتا جدیدی است که به OpenGL 4 و Directx 3d 11 اضافه شده است. به طور خلاصه Tessellation Shader به منظور تقسیم مش استفاده میشود.
شیدر با تابع ثابت (Fixed Function Shader): شیدری که قابل برنامهنویسی نیست و در داخل سخت افزار تعبیه شده است.
در Rendering Pipeline (خط لوله ی رندرینگ)، یک شیدر هندسی بین شیدر رأس و شیدر پیکسل قرار دارد.
Geometry Shader (شیدر هندسی): به عنوان یک پیشنهاد، برای تغییر در ساختار و دستکاری شکل هندسی استفاده میشود. شیدر هندسی، یک شکل اولیه را به عنوان ورودی دریافت میکند (که آن را به عنوان Vertex shader -شیدر رئوس- یک رأس در نظر میگیرد) و در نهایت آن را به Pixel Shader جهت نمایش بر روی صفحهی نمایش منتقل میکند.
Compute Shader: شیدر محاسبه، هدف عمومی شیدر میباشد که در خارج Rendering Pipeline استفاده میشود. یعنی دیگر در آن از شکل اولیه یا شیدر پیکسل استفاده نمیشود. در عوض، با استفاده از شیدرهای محاسبه (Compute Shader) از قابلیت پردازش موازی GPU برای انجام وظایف عمومی استفاده میکند.
بیایید برای فهم عمل پردازش با مثال رسم Mesh Triangle شروع کنیم:
هر Mesh از تعدادی رئوس تشکیل شده است، به همین دلیل برای رسم یک Mesh برای اولین بار، قبل از ارسال آن به شیدر رأس به اطلاعات رئوس آن نیاز داریم.
این اطلاعات شامل:
– موقعیت (position value of the vertex)
– رنگ رأس (color value of the vertex)
– و مقدار نرمال رأس (normal value of the vertex) میباشند.
کارخانه ی Vertex shader
Vertex Shader به عنوان یک ماشین پردازشگر، دادههای ارسالی را داخل هر بسته به عنوان دستور، پردازش میکند. بعد از اینکه پردازش vertex shader تمام شد، آن اطلاعات پردازش شده را در قالب بسته دیگری به نام “خروجی ورتکس” (Vertex Output) فراهم میکند، سپس خروجی ورتکس بهRasterizer (رسام) میرود.
Rasterizer
ورودی ورتکس و ورتکس خروجی باید حداقل اطلاعات موقعیت (Position) رأس را داشته باشد که بعداً آن را به Rasterizer منتقل کند. معمولا، ورتکس شیدر موقعیت شی(Object-Space) را به موقعیت فضای طرح (Projection-Space) تبدیل میکند. در Vertex Shader، ما میتوانیم مختصات هر رأس را تغییر دهیم.
به عنوان مثال برای اینکه شیدر پرچم را ایجاد کنیم میتوانیم رئوس Mesh پرچم را بر مبنای تابع موج سینوسی حرکت دهیم.
رسام سخت افزاری است که بر اساس موقعیت رئوس Mesh تعیین میکند که پیکسلهای صفحه برای نمایش Mesh چگونه پوشش داده شوند. در رسام مشخص است که پیکسل در داخل منطقه هندسی است. قوانین شطرنجیسازی تعیین میکند که کدام پیکسلها باید توسط هندسه پوشش داده شود و یکی از آنها قوانین نمونه است. در فرآیند نمونه برداری، نمونه به هر پیکسل داده شده است.
رسام تعیین میکند که کدام یک از پیکسلهای صفحهی نمایش در ناحیهی هندسی پوشیده میشود و هر پیکسل مقادیر Interpolation (درون یابی) خود را دارد. برای هر پیکسل تعیین شده، Fragment/Pixel Shader اجرا میشود. Vertex-Output مجموعه اطلاعاتی است که خارج از Vertex-Shader میباشد که به Rasterizer میرود و در نهایت به Fragment/Pixel ارسال میشود.
هنگامی که یک رسام با استفاده از فرآیند نمونه گیری برای پیدا کردن پیکسلها، یک منطقه هندسی را پوشش میدهد، به هر پیکسل یک نمونه داده میشود و اشعه(Ray) از نقطه نمونهگیری عبور داده میشود. اگر پرتو با شکل هندسی برخورد کند این بدان معناست که پیکسل تحت پوشش شکل هندسی یا در داخل منطقه هندسی است.
نقش دیگرRasterizer این است که دادهها را برای پیکسلهای بین رئوس درون یابی کند (Interpolate).
Interpolation
در محاسبات عددی، Interpolation (درون یابی) روشی است برای یافتن مقدار تابع درون یک بازه، زمانی که مقدار تابع در تعدادی از نقاط گسسته معلوم است.
اگر ما یک مثلث داشته باشیم با اطلاعات موقعیت (Position)، میتوانیم آن را به Vertex Input راهی کنیم. سپس آن Rasterizer (رسام) اطلاعات هر ورتکس را دریافت میکند و اینکه کدام پیکسل صفحه ی نمایش باید با Mesh پوشش داده شود را کشف میکند .وقتی مثلث روی صفحه نمایش رسم شود رسام مقدار نرمال هر پیکسل را براساس مقدار نرمال خوانده شدهی هر ورتکس ارائه میدهد.
مقدار X رأس بالا برابر 0 و مقدار رأس X پایین برابر 1 است بنابراین مقدار وسطی برابر 0.5 می باشد.
به طور مشابه، مقدار Y راس بالا 1 و مقدار Y راس پایین 0 است، در نتیجه مقدار Y وسطی برابر 0.5 است.
درنتیجه مرکز این خط خواهد شد – (0.5، 0.5، 0). در این روش، مقدار برای هر پیکسل توسط رسام محاسبه میشود.
Fragment/Pixel shader اطلاعات را به عنوان دستور می خواهد و مقدار رنگ و آلفا را برای پیکسل هایی که در نهایت به رنگ نهایی پیکسل بر روی صفحه نمایش کمک می کند خروجی می دهد.
ترجمه از: لینکدین Chayan Vinayak