خیلی زمان زیادی برای صحبت در مورد بردار های GLSL نداریم، اما قبل از ادامه دادن، یادگیری آنان مهم است و رنگ ها راهی خوب برای فهمیدن و کسب اطلاعات بیشتر در مورد آنان است.
آگر با برنامه نویسی شی گرا آشنا هستید مشاهده کردید که ما مانند ساختار های استراکت زبان C به مقادیر داخل بردار ها دسترسی داریم.
vec3 red = vec3(1.0,0.0,0.0);
red.x = 1.0;
red.y = 0.0;
red.z = 0.0;
تعریف مقادیر رنگ با x, y, z میتواند گمراه کننده باشد، برای همین روش های دیگری برای دسترسی به این مقادیر وجود دارند، مقادیر x ,y ,z را میتوان با r ,g ,b هم صدا زد. و حتی s, t, p (معمولا برای مختصات فضای یک تکستچر ازین نام ها استفاده میشود، در فصل بعدی خواهید دید). حتی با مکان مقدار مورد نظرتان هم میتوان از آنان استفاده کرد مثلا [1] , [2], [3].
مقدار های داخل هر خط در مثال زیر با هم برابر هستند:
vec4 vector;
vector[0] = vector.r = vector.x = vector.s;
vector[1] = vector.g = vector.y = vector.t;
vector[2] = vector.b = vector.z = vector.p;
vector[3] = vector.a = vector.w = vector.q;
این روش های مختلف برای دسترسی به داده ها، برای کمک به شما در نوشتن کد های واضح تر است. این منعطف بودن زبان شیدر ها دریچه ای برای شماست که در مورد مختصات رنگ و فضا تفکر کنید.
از دیگر ویژگی های GLSL این است که میتوان، این مقادیر را به هر ترتیبی استفاده کرد. این ویژگی باعث میشود، مقادیر به راحتی ترکیب شوند.اسم این قابلیت swizzle هست.
vec3 yellow, magenta, green;
// Making Yellow
yellow.rg = vec2(1.0); // Assigning 1. to red and green channels
yellow[2] = 0.0; // Assigning 0. to blue channel
// Making Magenta
magenta = yellow.rbg; // Assign the channels with green and blue swapped
// Making Green
green.rgb = yellow.bgb; // Assign the blue channel of Yellow (0) to red and blue channels
اکنون که میدانید رنگ ها چگونه تعریف میشوند، وقت آن است، از دانش های قبلیمان استفاده کنیم. در GLSL فانکشن مفیدی به نام mix() وجود دارد، که به شما این امکان را میدهد دو مقدار را با درصد خاصی با هم مخلوط کنید. آیا میتوانید حدس بزنید دامنه مقدار چقدر است؟ بله بین 0.0 تا 1.0 . بعد از تمرین های گذشته که آن ها هم با اعداد بین 0 تا 1 مرتبط بودند. وقت آن است دوباره از آنان استفاده کنید.
به خط 18 نگاه بیاندازید که چگونه، از قدر مطلق مقادیر سینوس برا ترکیب رنگ A و B استفاده شده است.
مهارت های خود را توسط نکته زیر به نمایش بگزارید:
- ِیک طیف رنگی ایجاد کنید. به یک احساس خاص فکر کنید. چه رنگی به ذهنتان میآید؟ چگونه محو و ظاهر میشود؟ به احساسی دیگر و رنگ متناسب با آن فکر کنید. ابتدا و انتهای کد بالا را تغییر دهید تا با آن احساس مطابقت داشته باشد، سپس این طیف را با استفاده از توابع دیگر متحرک کنید. رابرت پنر مجموعه توابع شکل دهی معروفی را برای انیمیشن و متحرک سازی ایجاد کرده است، که به عنوان توابع ease شناخته میشوند easing functions, میتوانید از این مثال برای آموزش و الهام استفاده کنید، اما قطعا بهترین نتیجه، نتیجه کار خودتان است.
فانکشن mix()
قابلیت های بیشتری دارد. به جای یک عدد شناور، میتوان یک متغیر که مطابق دو آرگومان اول باشد را ، به آن منتقل کنیم, در مثال ما یک vector 3 هست. با این کار قابلیت کنترل هر یک از کانال های r, g و b را داریم.
به مثال زیر نگاه بیاندازید. مانند مثال های فصل قبل، ما مختصات x را به صورت نرمالایز شده استفاده و آن را با یک خط نشان میدهیم. در حال حاضر تمام کانال ها از آن خط عبور میکنند. حال خط 25 را از حالت کامنت خارج کنید و تغییرات را مشاهده کنید، برای خط های 26 و 27 هم نیز همین کار را انجام دهید. یادتان باشد مقدار خط، نشان دهنده ترکیب رنگ های A,B بر حسب هر کانال است.
احتمالا سه تابع شکل دهی را در خطوط 25 تا 27 تشخیص داده اید. با آنها بازی کنید. وقت آن است که مهارت های فصل قبل را کاوش کرده و به نمایش بگذارید، سعی کنید شیب های گوناگون و جالب تری ایجاد کنید. تمرینات زیر را امتحان کنید:
-
گرادیانی شبیه غروب خورشید ویلیام ترنر بسازید.
-
با استفاده از
u_time
انتقال بین طلوع و غروب را متحرک کنید. -
آیا با استفاده از آنچه تا کنون یاد گرفته اید، میتوانید رنگین کمان بسازید؟
-
از تابع
step()
برای ساخت پرچم های رنگا رنگ استفاده کنید.
برای آشنایی بیشتر با رنگ ها، با فضای رنگ ها باید آشنا شویم. همانطور که میدانید علاوه بر کانال های R, G, B روش های دیگری برای سازماندهی رنگ وجود دارد.
HSB مخفف رنگ، اشباع، و روشنایی است، که یک سازماندهی مفید تر برای رنگ هاست. به توابع rgb2hsv() و hsv2rgb() در کد زیر دقت کنید.
با نگاشت موقعیت x با مقدار Hue(رنگ) و مقدار y به روشنایی، طیف خوبی از رنگ ها قابل مشاهده اند. این نوع توزیع فضایی رنگ میتواند بسیار مفید باشد. انتخاب رنگ با HSB نسبت به RGB ملموس تر است.
HSB در ابتدا برای مختصاب قطبی(بر اساس زاویه و شعاع) به جای مختصات دکارتی طراحی شده است. برای ترسیم عملکرد HSB در مختصات قطبی، نیاز به فاصله و زاویه از مرکز بیلبورد تا مختصات پیکسل مورد نظر داریم. برای این منظور نیاز به استفاده از تابع length()
و تابع atan(y,x)
داریم.
هنگام استفاده از بردار ها مثل vect2, 3, 4 حتی اگر نمایانگر رنگ باشند، باز هم به عنوان بردار با آنان رفتار میشود. ما در مورد رنگ ها و بردار ها به طور مشابه رفتار میکنیم، شما خواهید دید این انعطاف پذیری مفهمومی بسیار مفید است.
** نکته:** توابع هندسی بیشتری علاوه بر length
وجود دارند مانند: distance()
, dot()
, cross
, normalize()
, faceforward()
, reflect()
و refract()
. همچنین GLSL دارای توابع مخصوص برداری هستند مانند:: lessThan()
, lessThanEqual()
, greaterThan()
, greaterThanEqual()
, equal()
و notEqual()
.
وقتی مقدار طول و زاویه را بدست آوردیم باید آن هارا بین 0.0 و 1.0 نرمالایز کنیم. در خط 27, atan(y,x)
زاویه ای بین PI و _PI (-3.14 تا 3.14) برمیگرداند, پس باید آنان را بر TWO_PI
تقسیم کنیم(در بالای کد تعریف شده است) تا مقداری بین 0.5 و -0.5 بدست بیاوریم, که میتوان آن را به راحتی به بازه 0.0 تا 1.0 تبدیل کرد. ماکسیمم مقدار شعاعی که میتوان به دست آورد 0.5 است، چون شعاع را از وسط صفحه محاسبه میکنیم، پس باید این بازه را در 2 ضرب تا مقدار ماکسیمم یک را بتوان از آن گرفت.
همانطور که میبینید همه چیز حول انتقال و مپ کردن در بازه 0.0 و 1.0 است، همانطور که ما دوست داریم.
تمرین های زیر را امتحان کنید:
-
مختصات قطبی را تغییر دهید که مثال بالا به دور محورش بچرخد، مانند آیکون انتظار موس.
-
برای گسترش مقدار یک رنگ خاص و فشرده کردن بقیه، از یک تابع شکل دهی به همرا تبدیل HSB به RGB استفاده کنید.
- اگر با دقت به چرخ رنگی که در برنامه های انتخاب رنگ استفاده میشود نگاه کنید، آنان از فضای رنگی دیگری یعنی، RYB استفاده میکنند، برای مثال رنگ روبروی قرمز در تصویر زیر سبز است، اما در مثال بالا روبروی قرمز فیروزه ای است. آیا میتواید با استفاده از توابع شکل دهی، مثال بالا را مانند شکل زیر کنید؟
- کتاب Josef Albers' book Interaction of Color را بخوانید ، همچین شیدر های زیر را برای تمرین مرور کنید.
قبل از رفتن به فصل بعدی، بایستی به عقب برگردیم، و توابع مثال های قبل را ببینیم. متوجه in قبل از آرگومان های ورودی تابع شدید؟. آن یک qualifierاست و در این حالت مشخص میکند، متغیر فقط خواندنی است. در مثال های آینده میبینیم که آرگومان ها را به عنوان out
و یا inout
هم میتوان مشخص کرد. آخری یعنی, inout
مشابه انتقال آرگومان از طریق رفرنس است، که امکان تغییر یک متغیر عبور داده شده را میدهد.
int newFunction(in vec4 aVec4, // read-only
out vec3 aVec3, // write-only
inout int aInt); // read-write
شاید باورتان نشود اما هم اکنون تمام عناصر لازم جهت کشیدن تصاویر باحال را دارید. در فصل بعدی خواهیم آموخت چگونه با ترکیب فضا، همه ترفند های خود را برای ساخت فرم های هندسی ترکیب کنیم