diff --git a/01/README-fa.md b/01/README-fa.md new file mode 100644 index 0000000..241ecc4 --- /dev/null +++ b/01/README-fa.md @@ -0,0 +1,47 @@ +# شروع +## فرگمنت شیدر چیست؟ + +در قسمت قبل شیدر ها را معادل دستگاه گوتنبرگ برای گرافیک توصیف کردیم. چرا؟ و مهم تر اینکه: شیدر چیست؟ + +![From Letter-by-Letter, Right: William Blades (1891). To Page-by-page, Left: Rolt-Wheeler (1920).](print.png) + +اگر تجربه نقاشی در کامپیوتر را داشته باشید میدانید که در این فرایند، دایره، مستطیل و خط هارا یکی پس از دیگری میکشید تا شکل مورد نظر خود را نهایی کنید، این فرایند شبیه نوشتن کتاب است، در واقع این کار ها مجموعه ای از دستور العمل ها هستند که وظایف را یکی پس از دیگری انجام میدهند. + +شیدر ها هم مجموعه ای از دستور العمل ها هستند، اما دستور المل هایی که به یکباره برای هر پیکسل روی صفحه اجرا میشود. این بدان معناست، کدی که مینویسید بسته به موقعیت پیکسل روی صفحه نمایش باید رفتار متفاوتی انجام دهد. برنامه شما مانند تابعی کار میکند که موقعیت را دریافت میکند و یک رنگ را بر میگرداند، زمانی که کد شما کامپایل میشود، این عملیات بسیار سریع انجام میشود. + +![Chinese movable type](typepress.jpg) + +## چرا شیدر ها سریع هستند؟ + +برای پاسخ به این سوال من شگفتی پردازش موازی را به شما معرفی میکنم. + +پردازه مرکزی(CPU) رایانه خود را به عنوان یک لوله بزرگ صنعتی در نظر بگیرید، و هر تسکی را مانند چیزی که از داخل آن عبور میکند بپندارید. بعضی تسک ها بزرگ تر از بقیه هستند پس زمان و انرژی بیشتری برای پردازش آن ها نیاز است. به نوعی میگوییم این نوع تسک ها به قدرت پردازش بالاتری نیاز دارند. به دلیل معماری رایانه ها تسک ها مجبور هستند به صورت سری اجرا شوند، تسک ها باید یک به یک تمام شوند. رایانه های مدرن معمولا دارای گروه های چهارتایی از پردازنده ها هستند، که مانند این لوله ها کار میکنند و وظایف را یکی پس از دیگری انجام میدهد تا کار ها بدون مشکل انجام شود، هر لوله را به عنوان یک ترد(thread) هم میشناسند. + +![CPU](00.jpeg) + +بازی های ویدئویی و سایر برنامه های گرافیکی به پردازش بیشتری نسبت به برنامه های معمول نیاز دارند. به دلیل محتویات زیاد، آن ها باید باید مقادیر زیادی عملیات پیکسل به پیکسل انجام دهند. هر یک از پیکسل ها باید محاسبه شوند، همچنین در بازی های سه بعدی باید عملیات های بیشتری مثل محاسبات هندسی و پرسپکتیو هم انجام شود. + +بیاید به استعاره خود در مورد لوله ها و تسک ها برگردیم، هر پیکسل رو صفحه نمایش یک تسک کوچک و ساده را نشان میدهد، به طور جداگانه تسک هر پیکسل برای CPU مسئله ای نیست. اما اینکه این تسک های کوچک باید برای هر پیکسل انجام شود برای CPU مشکل ساز است. این یعنی در صفحات قدیمی 800x600 باید 480,000 پیکسل در هر فریم پردازش شود که به معنی 14,400,000 محاسبه در ثانیه است! بله این مقدار به قدری بزرگ هست که یک ریزپردازنه را سرریز کند. در یک نمایشگر مدرن 2880x1800 با نرخ 60 فریم بر ثانیه، این محاسبات به 311,040,000 محاسبه در ثانیه میرسد. چگونه مهندسان گرافیک این مشکل را حل میکنند؟ + +![](03.jpeg) + +این زمانی است که پردازش موازی به یک راه حل خوب تبدیل میشود، منطقی است که به جای داشتن چند ریز پردازنده بزرگ یا قدرتمند(لوله)، ریزپردازنده های کوچکتری و بیشتری به صورت موازی کار کنند.واحد پردازنده گرافیکی(GPU) همین طور عمل میکند. +![GPU](04.jpeg) + +ریز پردازنده های کوچک را مانند جدولی از لوله ها وداده های هر پیکسل را مانند یک توپ تصور کنید، 14,400,000 توپ میتواند هر لوله های را مسدود کند، اما میتوان یک جدول از 800x600 لوله کوچک را که 30 موج 480,000 تایی پیکسل در ثانیه دریافت میکند را به راحتی کنترل کرد. در وضوح بالاتر هم به همین صورت عمل میکند. هرچه سخت افزار های موازی بیشتری داشته باشید، به همان نسبت جریان بیشتری را میتوانید مدیریت کنید. + +از دیگر قدرت های فوق العاده GPU عملکرد های ویژه ریاضی آن است که از طریق سخت افزار سریع تر میشود، یعنی این عملیات ریاضی به جای استفاده از نرم افزار مستقیما توسط میکرو تراشه حل میشوند، به عبارتی عملکرد های مثلثاتی و ماتریسی به سرعت الکتریسیته میتواندد سریع باشند. + +## GLSL چیست؟ + +مخفف OpenGL Shading Language است. که استانداری خاص از برنامه های شیدر هست و در فصل بعدی خواهید دید. بسته به سخت افزار و سیستم عامل ها انواع دیگر شیدر نیز وجود دارند. در اینجا ما با OpenGL تنظیم شده توسط گروه Khronos کار خواهیم کرد. دانستن تاریخچه OpenGL میتواند به درک بیشتر قرار داد های عجیب و غریب آن مفید باشد، برای همین توصیه میکنیم نگاهی به این موضوع داشته باشید: [openglbook.com/chapter-0-preface-what-is-opengl.html](http://openglbook.com/chapter-0-preface-what-is-opengl.html) + +## چرا شیدر ها به دردناک بودن معروفند؟ + +همانطور که عمو بن گفت:"قدرت زیاد، با مسئولیت بزرگی همراه است"، و محاسبه موازی ازین قاعده پیروی میکند، طراحی معماری قوی GPU محدودیت ها و خصوصیات مخصوص به خودش را دارد. + +برای این که به صورت موازی هر لوله یا ترد اجرا شود. باید از هر ترد دیگری مستقل باشد، ترد ها نسبت به آنچه بقیه ترد ها انجام میدهد نا آگاه هستند. این محدودیت نشان میدهد که همه داده ها باید در یک جهت جریان داشته باشند. پس بررسی نتیجه یک ترد دیگر، اصلاح داده های ورودی و یا انتقال نتیجه یک ترد به ترد دیگر غیر ممکن است. اگر به ترد ها اجازه ارتباط داده شود، یکپارچگی داده ها در معرض خطر قرار خواهد گرفت. + +همچنین GPU پردازنده های موازی را به طور مداوم مشغول نگه میدارد، به محض اینکه آزاد میشوند، داده های جدید برای پردازش دریافت میکنند. برای یک ترد غیر ممکن است که بداند که لحظه قبلی چه کاری انجام داده. عملیات قبلی آن میتواند کشیدن یک دکمه برای UI سیستم عامل بوده باشد یا رندر یک آسمان در بازی ویدئویی. هر ترد نه تنها کور(Blind) است(نا آگاه از عملیات ترد های دیگر) بلکه بی حافظه نیز هست. علاوه بر دانستن مفهوم نحوه کد نویسی بر اساس موقعیت هر پیکسل، این کور بودن و بی حافظه بودن، باعث میشود، شیدر ها در میان برنامه نویسان تازه محبوبیت نداشته باشد. + +نگران نباش در فصل های بعد، گام به گام یاد خواهیم گرفت چگونه محاسبات ساده تا پیشرفته شیدر را انجام دهیم. اگر از مرورگر های مدرن استفاده میکنی، میتوانی از مثال های تعاملی هم استفاده کنی، برای شروع روی کلید بعدی بزن. diff --git a/02/README-fa.md b/02/README-fa.md new file mode 100644 index 0000000..03b36b0 --- /dev/null +++ b/02/README-fa.md @@ -0,0 +1,53 @@ +## Hello World + +معمولا عبارت "Hello World" مثالی از اولین قدم برای یادگیری یک زبان جدید است. + +در مورد ما ارائه یک متن کار پیچیده ای برای قدم اول است، در عوض یک رنگ روشن را به عنوان شور و شوق اولین کدمان اجرا میکنیم! + +
+ +اگر این کتاب را در یک مرورگر مدرن میخوانید، کد بالا قابل تغییر است، تغییرات شما بلافاصله کامپایل و به شما نمایش داده میشوند، سعی کنید خط 8 را تغییر دهید. + +البته این خطوط ساده به نظر نمیرسند، اما میتوان مفاهیم قابل توجهی از آنها استباط کرد: + +1. برنامه نویسی شیدر یک عملکرد اصلی 'main' دارد، که در انتها یک رنگ برمیگرداند. شبیه زبان C. + +2. رنگ نهایی پیکسل به متغیر گلوبال gl_FragColor اختصاص داده شده است. + +3. این زبان شبه C با متغیر ها و تابع های مختلف ساخته شده و استفاده میشود. در این مورد ما با vect4 آشنا شدیم که مخفف یک بردار 4 بعدی با دقت شناور(float) است. انواع بیشتری ازین متغیر ها مانند vect2, vect3 و bool, int, float در آینده خواهیم دید. + +4. اگر به vect4 دقت کنیم مییابیم این 4 آرگومان به کانال های RGBA پیکسل مورد نظر پاسخ میدهند. همچنین این مقادیر نرمال شده اند یعنی بین 0تا1(نه بین 0 تا 255)، بعدا خواهیم آموخت چگونه نرمال سازی مقادیر، ترسیم مقادیر بین متغیر ها را آسان میکند. + +5. یکی از دیگر ویژگی های مشابه C مثال بالا وجود ماکرو ها هستند. با استفاده از آنان میتوان متغیر های جهانی را تعریف کرد و یا برخی عملیات شرطی اساسی را انجام داد(ifdef and #endif#). تمام دستورات کلان(ماکرو) با هشتگ شروع میشوند. ماکرو ها قبل از کامپایل اجرا میشوند، شرایط را بررسی میکند(ifdef and #endif#) و ارجاعات به defines# را کپی میکند. مثلا در مثال بالا ما خط 2 را در صورت تعریف GL_ES وارد میکنیم. که معمولا در هنگام کامپایل این کد در تلفن های همراه و مرورگر ها اتفاق میافتد. + +6. شناور ها(float) در شیدر ها حیاتی هستند، بنابراین سطح دقت بسیار مهم است. دقت پایین تر به معنای رندر سریع تر است، همچنین کیفیت کمتر. میتوانید مثل خط دو مثال بالا متغیر ها را شناور با دقت متوسط درنظر بگیرید(precision mediump float)، همچنین میتوانید متغیر شناور با دقت پایین(precision lowp float) یا بالا(precision highp float)هم در نظر بگیرید. + +7. آخرین و شاید مهمترین نکته در مثال بالا اینکه در GLSL تضمین نمیشود که متغیر ها به طور خودکار تغییر نوع داده(casting) رویشان اعمال شود. این به چه معناست؟ تولید کنندگان رویکرد های مختلفی برای سرعت بخشیدن روند پردازش کارت های گرافیکی دارند، و مجبورند حداقل مشخصات را تضمین کنند. کستینگ ازین رویکرد ها نیست. در مثال بالا vect4 دارای نقطه شناور است و برای آن انتظار میرود که به متغیر های شناور انتساب شود. اگر میخواهید کد سازگار خوبی ایجاد کنید و ساعت ها وقت صرف دیبگ کردن آن نکنید، عادت کنید در float ها از نقطه(.) استفاده کنید. + +```glsl +void main() { + gl_FragColor = vec4(1,0,0,1); // ERROR +} +``` + +اکنون که مهم ترین عناصر مثال بالا را با هم مرور کردیم، وقت آن است که روی کد کلیک کنید و چیز هایی که یاد گرفتیم را پیاده کنیم. توجه کنید که در صورت خطا برنامه صفحه سفید را به شما نشان میدهد. بعضی چیز های جالب وجود دارد که باید امتحان کنید، مثلا: + +* شناور ها را با اعداد صحیح(int) جایگزین کنید، کارت گرافیک شما معلوم نیست بتواند این کد را اجرا کند یا خیر. + +* سعی کنید خط 8 را کامنت کنید و هیچ مقدار پیکسلی به تابع اختصاص ندهید. + +* سعی کنید یک تابع جداگانه ایجاد کنید که رنگ خاصی را برگرداند و از آن داخل main استفاده کنید، به عنوان یک راهنمایی در اینجا کد مربوط به تابعیست که رنگ قرمز را بر میگرداند. + +```glsl +vec4 red(){ + return vec4(1.0,0.0,0.0,1.0); +} +``` + +* روش ها مختلفی برای ساخت vect4 وجود دارد، سعی کنید راه های دیگر را پیدا کنید، یکی از آن ها به این صورت است: + +```glsl +vec4 color = vec4(vec3(1.0,0.0,1.0),1.0); +``` + +اگرچه این مثال خیلی هیجان انگیز نیست، اما ابتدایی ترین مثال است. ما تمام پیکسل های داخل کنوس(canvas) را به یک رنگ تغییر میدهیم. در فصل بعد نحوه تغییر رنگ پیکسل را با استفاده از دو نوع ورودی دیگر میبینیم. فضا(محل و مختصات پیکسل روی صفحه) و زمان(مقدار زمان از لحظه بارگیری صفحه بر حسب ثانیه).