Shader (شیدر) — برنامهای است که روی GPU برای پردازش دادههای گرافیکی اجرا میشود: رئوس، فرگمنتها یا وظایف محاسباتی. برخلاف کد معمولی روی CPU، شیدر به صورت موازی روی صدها هسته کار میکند و هر عنصر را مستقل پردازش میکند. طبق دادههای Khronos Group (2025)، شیدرها در 100% برنامههای مدرن سهبعدی استفاده میشوند — از بازیهای موبایل تا جلوههای UI در برنامههای سیستمی. توسعهدهندگان شیدرها را به زبانهای تخصصی مینویسند: GLSL، HLSL، Metal Shading Language یا SPIR-V.
نکات اصلی
Shader — برنامه کوچکی است که به زبان تخصصی نوشته شده و روی GPU اجرا میشود. هر شیدر یک عنصر داده — راس، فرگمنت (پیکسل) یا عنصر کاری — را مستقل از دیگران پردازش میکند. موازیسازی GPU امکان اجرای همزمان هزاران نمونه شیدر را فراهم میکند.
این اصطلاح توسط Pixar در دهه 1980 برای توصیف برنامههایی که ظاهر سطوح را در RenderMan کنترل میکنند، معرفی شد. شیدرهای بلادرنگ با NVIDIA GeForce 3 (2001) — اولین کارت گرافیک با خط لوله قابل برنامهریزی — ظاهر شدند. قبل از شیدرها، گرافیک از طریق پارامترهای ثابت پیکربندی میشد: رنگ، بافت، حالت ترکیب.
طبق دادههای Unity Technologies (2025)، یک بازی موبایل معمولی از 50–200 شیدر استفاده میکند. هر شیدر با واریانتهایی (variants) برای پلتفرمهای مختلف، سطوح کیفیت و پیکربندیهای نورپردازی نمایش داده میشود. تعداد واریانتها میتواند به 10 000 در هر پروژه برسد.
معماری شیدر به دادههای ورودی (ویژگیها، متغیرهای uniform، بافتها)، کد برنامه و دادههای خروجی (رنگ، موقعیت) تقسیم میشود. متغیرهای uniform قبل از اجرای شیدر از CPU تنظیم میشوند و برای همه عناصر فریم بدون تغییر میمانند. ویژگیها دادههای هر عنصر هستند (مختصات راس، نرمال، مختصات UV).
SIMT (Single Instruction, Multiple Threads) — مدل اجرای شیدرها روی GPU. یک دستور یک بار بارگذاری میشود و توسط صدها رشته روی دادههای مختلف اجرا میشود. مثلاً Fragment Shader برای 1000 پیکسل، 1000 رشته را با کد یکسان اجرا میکند، اما هر رشته مختصات UV و ویژگیهای درونیابی شده خود را دریافت میکند.
نتیجه مهم SIMT: انشعابات در شیدرها گران هستند. اگر داخل بلوک if نیمی از رشتهها یک مسیر و نیمی دیگر مسیر دیگر را بروند، GPU هر دو مسیر را به صورت ترتیبی برای همه رشتهها اجرا میکند. عملکرد به 50% کاهش مییابد. از انشعابات پویا در شیدرها خودداری کنید یا آنها را از طریق محاسبات اولیه روی CPU به حداقل برسانید.
GPUهای مدرن چندین نوع شیدر را پشتیبانی میکنند که هر کدام برای مرحله خاصی از خط لوله گرافیکی یا محاسباتی هستند. انواع اصلی را بررسی میکنیم: راس، فرگمنت، compute و mesh-شیدرهای مدرن.
| نوع شیدر | مرحله خط لوله | پردازش میکند | زبان |
|---|---|---|---|
| Vertex Shader | راس | هر راس | GLSL, HLSL |
| Fragment Shader | فرگمنت | هر پیکسل | GLSL, HLSL |
| Compute Shader | محاسباتی | دادههای دلخواه | GLSL, HLSL |
| Geometry Shader | هندسی | اولیهها | GLSL, HLSL |
| Tessellation Shader | تقسیمبندی | وصلهها | GLSL, HLSL |
| Mesh Shader | خط لوله مش | Task + Mesh | HLSL, MSL |
Vertex Shader هر راس هندسه را پردازش میکند: مختصات را تبدیل میکند، نورپردازی را محاسبه میکند، دادهها را به فرگمنت شیدر منتقل میکند. این یک مرحله اجباری خط لوله گرافیکی است — بدون آن رئوس روی صفحه ظاهر نمیشوند. Vertex Shader برای هر راس هر فریم فراخوانی میشود.
Fragment Shader (یا Pixel Shader) — پرمصرفترین مرحله از نظر منابع. رنگ نهایی هر فرگمنت را با استفاده از بافتها، نورپردازی و مواد محاسبه میکند. Fragment Shader برای هر پیکسل پوشیده شده توسط هندسه، با در نظر گرفتن تمام بافتها و جلوههای اعمال شده، اجرا میشود. بهینهسازی این شیدر بیشترین افزایش عملکرد را به همراه دارد.
Compute Shader — شیدر جهانی برای محاسبات دلخواه روی GPU. برخلاف شیدرهای گرافیکی، به هندسه یا پیکسلها وابسته نیست. Compute Shader با بافرهای داده دلخواه از طریق گروههای کاری کار میکند. برای فیزیک، شبیهسازی ذرات، پساثرها و استنتاج شبکههای عصبی استفاده میشود.
Mesh Shader — جدیدترین نوع شیدر که در NVIDIA Turing (2018) و Metal 3 ظاهر شد. Mesh Shader جایگزین شیدرهای راس، هندسی و تقسیمبندی با یک خط لوله مش واحد میشود. همراه با Task Shader کار میکند: Task Shader تصمیم میگیرد کدام گروههای مش رندر شوند، Mesh Shader هندسه را در لحظه تولید میکند.
شیدرها به زبانهای تخصصی نوشته میشوند که به کد ماشین GPU کامپایل میشوند. انتخاب زبان به پلتفرم و API بستگی دارد. زبانهای اصلی را بررسی میکنیم: GLSL، HLSL، Metal Shading Language و فرمت میانی SPIR-V.
GLSL — زبان شیدر برای OpenGL، OpenGL ES و WebGL. نحو بر پایه C با اضافه شدن انواع برداری (vec2, vec4, mat4) و توابع داخلی (texture, normalize, reflect). GLSL ES — نسخه برای دستگاههای موبایل با دقت محدود (lowp, mediump, highp). طبق دادههای Khronos (2025)، GLSL به دلیل قابلیت cross-platform رایجترین زبان شیدر باقی مانده است.
#version 300 es
precision mediump float;
in vec2 v_texCoord;
uniform sampler2D u_texture;
out vec4 fragColor;
void main() {
fragColor = texture(u_texture, v_texCoord);
}
یک فرگمنت شیدر ساده رنگ را از بافت بر اساس مختصات UV میخواند. precision mediump به GPU دستور میدهد از دقت نصف برای float استفاده کند — اجرا را روی دستگاههای موبایل 25–40%تسریع میبخشد.
HLSL — زبان شیدر مایکروسافت برای DirectX. نحو نزدیکتر به C++ با پشتیبانی از کلاسها، ساختارها و قالبها. HLSL در برنامههای Windows استفاده میشود و از طریق Shader Model 6.7+ از Ray Tracing، Mesh Shaders و Sampler Feedback پشتیبانی میکند. برای توسعه موبایل HLSL مستقیماً استفاده نمیشود، اما برای Vulkan به SPIR-V کامپایل میشود.
MSL (Metal Shading Language) — زبان شیدر اپل، مبتنی بر C++14. برخلاف GLSL و HLSL، MSL همراه با برنامه کامپایل میشود که کامپایل JIT روی دستگاه را حذف میکند. MSL از اشارهگرها، قالبها و کتابخانه استاندارد C++ پشتیبانی میکند. روی همه دستگاههای اپل استفاده میشود: iPhone، iPad، Mac، Apple TV.
#include <metal_stdlib>
using namespace metal;
struct VertexOut {
float4 position [[position]];
float2 texCoord;
};
fragment float4
myFragment(VertexOut in [[stage_in]],
texture2d<float> tex [[texture(0)]]) {
constexpr sampler s = sampler(filter::linear);
return tex.sample(s, in.texCoord);
}
MSL از ویژگیهای [[position]]، [[stage_in]] و [[texture(N)]] برای اتصال منابع استفاده میکند. کامپایلر اپل کد بهینهشده برای GPU فعلی را با در نظر گرفتن تعداد ثباتها و حافظه نهان تولید میکند.
SPIR-V — فرمت باینری میانی شیدرها، استاندارد برای Vulkan. شیدرها به GLSL یا HLSL نوشته میشوند، به SPIR-V کامپایل میشوند و در برنامه Vulkan بارگذاری میشوند. SPIR-V به زبان خاصی وابسته نیست — کامپایلرهایی از Rust، Python، OpenCL C به SPIR-V وجود دارند.
شیدرها در پلتفرمهای موبایل در مقایسه با رومیزی محدودیتهایی دارند: ثباتهای کمتر، دقت محدود و عدم پشتیبانی از برخی دستورات. ویژگی شیدرها در Android (Vulkan/OpenGL ES) و iOS (Metal) را بررسی میکنیم.
Android از GLSL ES برای OpenGL و SPIR-V برای Vulkan استفاده میکند. OpenGL ES 3.2 از شیدرها با دقت پیشفرض mediump پشتیبانی میکند. Vulkan نیاز به کامپایل صریح GLSL به SPIR-V از طریق glslangValidator دارد. در Android شیدرها از منابع رشتهای یا فایلهای SPIR-V کامپایلشده بارگذاری میشوند.
Qualcomm Adreno GPU شیدرها را در سطح درایور بهینه میکند. توصیهها: برای رنگ و UV از mediump، فقط برای موقعیتها از highp استفاده کنید؛ از نمونهبرداری بافت در شیدرهای راس خودداری کنید؛ محاسبات را در بردارها گروهبندی کنید (vec4 به جای 4x float). طبق دادههای Qualcomm (2025)، این بهینهسازیها 30–50% بهبود میدهند.
iOS منحصراً از Metal Shading Language استفاده میکند. شیدرها از طریق Xcode همراه با برنامه به کد ماشین کامپایل میشوند. Metal Shader Debugger و GPU Capture را برای پروفایل شیدرها فراهم میکند. Apple GPU (TBDR) بهینهسازیهای خاصی دارد: early fragment test، memoryless render targets و ترکیب قابل برنامهریزی.
طبق دادههای Apple WWDC 2024، برای شیدرهای iOS استفاده از half به جای float، محدود کردن فشار ثبات (حداکثر 64 ثبات) و اجتناب از نمونهبرداریهای وابسته بافت حیاتی است. شیدرهای iOS باید جمعوجور باشند — اندازه بهینه 50–100 دستور ALU.
موتورهای بازی Unity و Unreal Engine ویرایشگرهای بصری شیدر (Shader Graph, Material Editor) و زبانهای انتزاعی (ShaderLab, USF) ارائه میدهند. توسعهدهنده شیدر را به زبان سطح بالا مینویسد و موتور برای پلتفرم مورد نظر کامپایل میکند. Unity از HLSL به عنوان زبان میانی استفاده میکند، Unreal — USF (Unreal Shader Format).
بهینهسازی شیدرها — مرحله کلیدی توسعه گرافیک برای دستگاههای موبایل. یک شیدر بد میتواند FPS را از 60 به 20 کاهش دهد. قوانین و تکنیکهای اصلی بهینهسازی را بررسی میکنیم.
از حداقل دقت کافی استفاده کنید: lowp برای رنگ و UV، mediump برای نرمالها و نورپردازی، highp فقط برای موقعیتها و ماتریسها. طبق دادههای ARM (2025)، عملیات mediump روی Mali GPU 2 برابر سریعتر از highp است. در GLSL ES این با استفاده از precision-qualifierها تنظیم میشود.
نمونهبرداری بافت — گرانترین عملیات در شیدر (10–30 چرخه در مقابل 1–2 برای دستور ALU). تعداد نمونهبرداریها را کاهش دهید: بافتها را در اطلسها ترکیب کنید، به جای بافتها از ذخیرهسازی در آرایههای uniform استفاده کنید، نتایج پیکسلهای مجاور را از طریق دستورات مشتق کش کنید.
انشعابات پویا (if با متغیر uniform) عملکرد خط لوله SIMT را کاهش میدهند. انشعابات را با توابع ریاضی جایگزین کنید: mix()، step()، smoothstep() و clamp(). این توابع در 1–2 دستور اجرا میشوند، در حالی که انشعاب ممکن است به دلیل واگرایی رشتهها 8–16 دستور هزینه داشته باشد.
// بد: انشعاب پویا در شیدر
if (u_enableLight) {
color *= computeLighting(normal);
}
// خوب: جایگزینی ریاضی انشعاب
color *= mix(1.0, computeLighting(normal),
float(u_enableLight));
mix() درونیابی خطی بین دو مقدار انجام میدهد. وقتی u_enableLight=0، 1.0 برگردانده میشود — رنگ تغییر نمیکند. وقتی u_enableLight=1، نتیجه نورپردازی برگردانده میشود. بدون انشعاب — همه رشتهها کد یکسان را اجرا میکنند.
نمونههای عملی شیدرها برای توسعه موبایل را بررسی میکنیم — از سایهزنی ساده تا تولید رویهای بافت. هر نمونه یک تکنیک خاص را نشان میدهد.
مدل Phong — مدل کلاسیک نورپردازی با مؤلفههای پخش و بازتابی. Vertex Shader نورپردازی را برای هر راس محاسبه میکند، Fragment Shader فقط نتیجه را درونیابی میکند (Gouraud shading). به دلیل هزینه کم برای دستگاههای موبایل مناسب است.
#version 300 es
layout(location = 0) in vec4 a_position;
layout(location = 1) in vec3 a_normal;
uniform mat4 u_mvp;
uniform mat4 u_modelView;
out vec3 v_color;
void main() {
vec3 normal = normalize(mat3(u_modelView) * a_normal);
vec3 lightDir = normalize(vec3(0.0, 1.0, 1.0));
float diff = max(dot(normal, lightDir), 0.0);
v_color = vec3(0.8, 0.2, 0.2) * (0.3 + diff * 0.7);
gl_Position = u_mvp * a_position;
}
شیدر نورپردازی diffuse را محاسبه میکند: حاصل ضرب نقطهای نرمال و جهت نور. نتیجه با مؤلفههای ambient (0.3) و diffuse (0.7) ترکیب میشود. 10–15 دستور ALU برای هر راس اجرا میکند — برای 100 000 چندضلعی در 60 FPS روی GPU موبایل قابل قبول است.
بافتهای رویهای در Fragment Shader بدون بارگذاری از فایل تولید میشوند. در حافظه ویدیویی صرفهجویی میکند و انیمیشن را ساده میکند. مثال — صفحه شطرنج با اندازه خانه قابل تغییر. فقط چند دستور ALU — حداقل بار روی GPU.
#version 300 es
precision mediump float;
in vec2 v_uv;
uniform float u_cells;
out vec4 fragColor;
void main() {
vec2 cell = floor(v_uv * u_cells);
float isWhite = mod(cell.x + cell.y, 2.0);
fragColor = mix(vec4(0.1, 0.1, 0.1, 1.0),
vec4(0.9, 0.9, 0.9, 1.0),
isWhite);
}
8 دستور ALU — شیدر ایدهآل برای دستگاههای موبایل. u_cells تعداد خانهها را در هر محور تعیین میکند. floor و mod — عملیات ارزان، در 1 چرخه روی همه GPUهای موبایل اجرا میشوند.
سؤالات متداول
Shader روی GPU در حالت SIMT اجرا میشود — یک دستور برای صدها رشته. برنامه معمولی C++ — روی CPU در حالت MIMD. شیدر به سیستم فایل، ورودی/خروجی و حافظه پویا دسترسی ندارد. دادهها را از طریق بافرها و بافتها دریافت میکند و موقعیت یا رنگ را برمیگرداند.
GLSL — برای OpenGL ES و WebGL، cross-platform. Metal Shading Language — برای iOS. HLSL — پایه Unity و Unreal Engine. با GLSL شروع کنید — درک اصول به هر زبان شیدر منتقل میشود.
دلایل اصلی: دقت بالا (highp به جای mediump)، نمونهبرداری بیش از حد بافت، انشعابات پویا و فراتر رفتن از حد ثبات. از RenderDoc یا Xcode GPU Frame Debugger برای تحلیل شیدرها استفاده کنید.
Compute Shader — شیدر برای محاسبات دلخواه روی GPU: فیزیک ذرات، پردازش تصویر، شبیهسازی پارچه. برخلاف Fragment Shader، به پیکسلها وابسته نیست و میتواند در بافرهای دلخواه بنویسد.
بله، از طریق ویرایشگرهای بصری: Shader Graph در Unity، Material Editor در Unreal Engine یا Metal Shader Converter. آنها کد شیدر را بر اساس نمودار گرهی تولید میکنند. برای بهینهسازی عمیق به درک زبان شیدر نیاز است.
نتیجهگیری
ما یک اپلیکیشن موبایل به صورت کلید در دست توسعه خواهیم داد
IT Sectr از سال 2017 برنامههای iOS و Android را برای استارتاپها و کسبوکارها ایجاد میکند. ما به شما مشاوره میدهیم و بهترین راهحل را پیشنهاد خواهیم کرد.
همچنین بخوانید