Shades of Halftone – وبلاگ ماکسیم هکل

اخیراً، هیجان جدیدی برای پس پردازش مبتنی بر قالب وجود داشته است
افکتها در سرتاسر جدول زمانی من، مانند نرمافزارهایی مانند Paper، Efecto یا Unicorn Studio
استفاده از سایه بان ها را برای طراحان و توسعه دهندگان به طور یکسان دموکراتیک کنید. در حالی که برخی از این مدل ها از راه حل ها به دلیل محدودیتهای فنی که از آن زمان بر آنها غلبه کردهایم، آنها اکنون به عنوان جهت هنری برای ایجاد طرحهای مختلف با محدودیتهای خودخواسته عمل میکنند.
یکی از آن اثراتی که بارها و بارها تکرار می شد این است نیمه صداها، الگوی نقطه کلاسیک، مرتب کردن نقاط با اندازه های مختلف در یک شبکه برای ایجاد توهم نوری یک گرادیان رنگ برای ناظر. این تکنیک در ابتدا برای چاپ تصاویر با رنگ های جوهر محدود استفاده می شد، اما امروزه یک ابزار هنری همه کاره تر است که در رسانه های مختلف استفاده می شود.
و شبکه برای افزودن بافت یا دانه به خروجی های دیجیتال. من شخصاً این تأثیر را پیدا می کنم زیاد جالب است زیرا پیاده سازی آن به شکل کلاسیک ذاتاً آسان است، اما می تواند به سرعت به برخی تجسم های پیچیده و پیچیده منشعب شود.
من در چند ماه گذشته زمان زیادی را صرف امتحان طعم های مختلف آن کرده ام
halftone میتواند آنها را روی تصاویر ثابت، ویدیوها یا صحنههای سه بعدی تعاملی بهعنوان سایهزن بگیرد و بپوشاند.
نقاط ساده روی یک شبکه، جوهر پاشیده، توری ها به صورت زاویه ای روی هم قرار می گیرند که منجر به ایجاد برخی جلوه های Moiré می شود، ترکیب رنگ ها به روش های جالب، شکستن شبکهو غیره
حتی سعی کردم ببینم چگونه می توان نیم تنه را متحرک کرد به روشی سرگرم کننده اما معنادار هر کدام از این گونهها جزئیات عملکرد/تکنیکهای سایهزنی و زیباییشناسی جالب خود را داشتند که فکر میکردم ارزش نوشتن و شکستن آنها را دارد تا ساخت و طراحی نیمتنی در دسترستر باشد.
من به چندین توهم نوری و جلوه های پس از پردازش ترومپ لوئیل در سایه بان های پس از پردازش به عنوان یک رسانه خلاق نگاه کردم که توهم بافت یا متریال را ایجاد می کند، مانند پارچه های قلاب بافی یا شیشه. به اندازه کافی عجیب، halftone چندان متفاوت نیست زیرا به خودی خود یک توهم نوری است.
این افکت با ارائه شبکهای از نقاط با فرکانس بالا، حسی از زنگهای پیوسته/یکدست، شبیه به دوشیدن، ایجاد میکند. از آنجایی که این نقاط می توانند کوچکتر از وضوح فضایی چشم، مغز در نهایت اجرا می کند میانگین فضایی مدل. بنابراین، پس از شعاع نقطه ای مشخص، دیگر نقاط منفرد را که مش را تشکیل می دهند، متوقف می کنیم و در عوض ببینید در نسبت “جوهر” به “فضای خالی” مانند زنگ های صاف
ما از این ویژگیها برای راهنمایی و تجزیهوتحلیل اجرای نیمهتونها بهعنوان سایهزن با GLSL استفاده خواهیم کرد.
رندر کردن شبکه ای از نقاط
برای اینکه این مقاله تا حد امکان برای مبتدیان در دسترس باشد، این افکت را از پایه و با اساسی ترین قسمت های آن شروع می کنیم. همانطور که انتظار دارید، اولین گام این است که یک نقطه یا دایره را با استفاده از مختصات GLSL و UV ارائه دهید.

نمودار بالا دو جنبه کلیدی ترسیم یک دایره در سایه زن قطعه را نشان می دهد:
-
فاصله
dکه فاصله تا نقطه مرکزی است{0.5, 0.5}سیستم مختصات UV ما نتایجی که به این بازده نیز الف می گویند میدان فاصله -
ماسک: آستانه ای که از آن تصمیم می گیریم چیست ج نقطه و آنچه در خارج است.
1
float dist = length(cellUv - 0.5);2
float circle = step(0.35, dist);4
vec3 color = mix(vec3(1.0), vec3(0.0), circle);
با تنظیم عملکرد ماسک، ما همچنین میتوانیم انتخاب کنیم که نتیجه نرمتر یا مشخصتر را ترجیح میدهیم.
1
float dist = length(cellUv - 0.5);2
float circle = smoothstep(0.32, 0.37, dist);4
vec3 color = mix(vec3(1.0), vec3(0.0), circle);
با این کار ما اکنون شکل اصلی را برای جلوه نیمهتون داریم و میتوانیم روی دومین ویژگی اصلی آن تمرکز کنیم. شبکه. در GLSL یک شبکه می تواند توسط fract 1 تابعی که بخش کسری آرگومان عددی خود را برمی گرداند:
-
fract(1.1)برمی گرداند0.1 -
fract(0.9)برمی گرداند0.9 -
fract(20.3)برمی گرداند0.3
اساساً معادل انجام دادن است mod(x, 1)، که یک عدد تصادفی ممیز شناور را برمی گرداند x. البته، اگر ما فقط انجام دهیم fract(uv)، هیچ چیز تغییر نخواهد کرد زیرا UV های ما قبلاً در استاندارد تعریف شده اند 0.0 → 1.0 محدوده
کاری که ابتدا باید انجام دهیم این است مختصات اشعه ماوراء بنفش را با ضرب کردن آنها در اندازه مش خود مقیاس می کنیمو سپس از UV های مقیاس شده به عنوان استدلال استفاده کنید fract، که باعث می شود شیدر قطعه ما مرتب شود. نمودار زیر مختصات UV ما را قبل و بعد از کاشی کاری نشان می دهد.

توجه کنید که چگونه ما اکنون یک مجموعه داریم سلول ها، هر کدام مختصات اشعه ماوراء بنفش خاص خود را دارند 0.0 -> 1.0 و اساسا همان قطعه سایه زن را پیاده سازی می کند. اگر این را با کد دایره ای خود در بالا ترکیب کنیم، هر یک از این سلول ها دایره خود را ترسیم می کنند، بنابراین شبکه نقاط ما را به ما می دهند!
ویجت زیر این را نشان می دهد و به شما امکان می دهد:
در حالی که برخی تغییرات در اندازه نقطه را نیز نشان می دهد، بنابراین می توانید با این مثال بسیار ساده، جلوه نیمه تون را مشاهده کنید.
5
uniform vec2 uResolution;7
uniform float uGridSize;10
vec2 cellUv = fract(vUv * uGridSize);12
float dist = length(cellUv - 0.5);13
float radius = uRadius * max(max(vUv.x, vUv.y), 0.2);15
float circle = smoothstep(radius - 0.01, radius + 0.01, dist);16
vec3 color = mix(vec3(0.4, 0.75, 1.0), vec3(0.0, 0.0, 0.0), circle);17
fragColor = vec4(color, 1.0);
اعمال نیم تن
اگرچه بازی با شعاع های نقطه می تواند منجر به الگوهای زیبایی شود، یکی از مزایای اصلی نیم تنه استفاده از آن به عنوان فیلتر روی صحنه، تصویر یا ویدیوی سه بعدی نتیجه با از دست دادن جزئیات از رسانه های زیرین به دست می آید، اما چیزی که در ازای آن به دست می آوریم نوعی ریزبافت است که فضاهای خالی را با اشکال جالبی که معمولاً رنگ های مسطح را می بینیم، پر می کند.
اگر به سادگی شبکه نقاط قسمت قبل را به عنوان فیلتر اعمال کنیم و نقاط را بر اساس پیکسل های انتخاب شده در آن موقعیت رنگ آمیزی کنیم، خواهیم دید یک ماسک. برای رسیدن به یک افکت نیم تن واقعی، ابتدا باید بافت پایه خود را از طریق پردازش کنیم پیکسل سازی به گونه ای که 1:1 با شبکه امتیازات ما مطابقت دارد.
یک جنبه جالب از این منطق پیکسلی این است که چگونه به آن تکیه می کنیم floor تابع برای تعیین ما pixelatedUV مختصات این تابع اعداد اعشاری را از مختصات UV ما حذف می کند، که اثر معکوس آن است fractو بنابراین تضمین می کند که هر پیکسل در یک سلول مشخص از همان رنگ نمونه برداری می کند و در نتیجه ظاهر و احساسی پیکسلی به بافت ما می دهد.
2
vec2 normalizedPixelSize = uPixelSize / uResolution;3
vec2 uvPixel = normalizedPixelSize * floor(uv / normalizedPixelSize);5
vec4 color = texture(inputBuffer, uvPixel);7
vec2 cellUv = fract(uv / normalizedPixelSize);8
float dist = length(cellUv - 0.5);10
float circle = smoothstep(uRadius - 0.01, uRadius + 0.01, dist);12
color = mix(color, vec4(0.0, 0.0, 0.0, 1.0), circle);
ترکیب این مورد با شبکه نقطهای مانند قطعه کد بالا، ما را یک قدم به جلوه نیمهتون نزدیکتر میکند.
البته، هنوز چیزی در تعریف اصلی ما از نیم تنه وجود ندارد، تغییر اندازه نقطه! ما میتوانیم با استفاده از روشنایی یک پیکسل معین و تنظیم شعاع بر اساس مقدار آن، این را به راحتی پیادهسازی کنیم.
2
vec2 normalizedPixelSize = uPixelSize / uResolution;3
vec2 uvPixel = normalizedPixelSize * floor(uv / normalizedPixelSize);5
vec4 color = texture(inputBuffer, uvPixel);6
float luma = dot(vec3(0.2126, 0.7152, 0.0722), color.rgb);7
float radius = uRadius * (0.1 + luma);9
vec2 cellUv = fract(uv / normalizedPixelSize);10
float dist = length(cellUv - 0.5);12
float circle = smoothstep(radius - 0.01, radius + 0.01, dist);14
color = mix(color, vec4(0.0, 0.0, 0.0, 1.0), circle);
همچنین، اگر میخواهیم یک نسخه خاکستری از halftone را نمایش دهیم، میتوانیم با استفاده از همان مقدار، که نتیجه آن را در زیر مشاهده میکنید، با روشن کردن «شعاع درخشندگی» و تغییر حالت رنگ خروجی، این کار را انجام دهیم.
با معرفی a می توان به تغییرات نیمه آهنگ جالب تری دست یافت افست شبکه، بنابراین نقاط به جای اینکه کاملاً تراز شوند جابجا می شوند. این اجازه می دهد تا چگالی بالاتری از نقاط در قالب ما داشته باشیم و میزان فضای سفید را کاهش دهیم. این افست با تنظیم UV های ما تعریف می شود، بنابراین نه تنها به نحوه قرار دادن نقاط خود، بلکه به نحوه نمونه برداری از بافت و پیکسل بندی آن نیز انتشار می یابد.
2
vec2 normalizedPixelSize = pixelSize / resolution;5
float rowIndex = floor(uv.y / normalizedPixelSize.y);6
if (offset && mod(rowIndex, 2.0) == 1.0) {7
offsetUv.x += normalizedPixelSize.x * 0.5;10
vec2 uvPixel = normalizedPixelSize * floor(offsetUv / normalizedPixelSize);11
vec4 color = texture2D(inputBuffer, uvPixel);
زمین بازی زیر این مورد را برای یک صحنه React Three Fiber 3D اعمال می کند، بنابراین به شما این امکان را می دهد که نه تنها این گزینه را همراه با همه
موارد دیگری را که تاکنون دیدهایم، اما همچنین در حال بازی با بسیاری از تنظیمات در یک صحنه پویا هستیم، جایی که به نظر من نیمهتون بیشترین درخشش را دارد: روی اجسام متحرک ارگانیک، زیباییشناسی متضاد فوقالعادهای را به صحنه میآورد.
نه فقط امتیاز
هنگامی که تیم Paper در نوامبر 2025 از پیش تنظیمهای Halftone خود را اعلام کرد، گزینههای نیمتنی زیادی را که قبلاً ندیده بودم، به نمایش گذاشتند. به نظر می رسد که دایره ها تنها بخشی از طیف گسترده ای از الگوهای نیم تنی موجود هستند، و ما می توانیم تعریف اصلی افکت را با آنچه من نام بردم تغییر دهیم. “نقطه مجاور” فرم ها
امروز ما یک سایه زن نمادین جدید را در @paper راه اندازی می کنیم
محدودیت های دیروز، پورتالی به گذشته، چه می شد اگر کلاسیک ها هرگز محو نمی شدند؟ بیا با هافتون دات بازی کن. هر تصویر را برای ایجاد یک طرح نمادین قرار دهید.
طراحی دوباره شبیه یک بازی است… لینک در پاسخ ها https://t.co/xrI6bOhJ2n
اولین موردی که می توانیم به آن نگاه کنیم مستقیماً از ویدیوی نشان داده شده در توییت بالا الهام گرفته شده است: نقطه و مربع، که ترکیبی از:
-
ما قبلا مدل نقطه کلاسیک را پیاده سازی کرده ایم
-
یک الگوی معکوس که در آن می توانیم نقاط سفید را در داخل پیکسل های رنگی پیدا کنیم. هرچه پیکسل اصلی تیره تر باشد، نقطه سفید بزرگتر است.

این دو مدل به خوبی یکدیگر را تکمیل می کنند و همانطور که در دمو زیر نشان داده شده است، می توان آنها را بر اساس روشنایی ترکیب و مطابقت داد:
این باعث می شود بافت اصلی بسیار بیشتری حفظ شود و در عین حال قسمت های روشن تر آن نیم تنه های استاندارد می شود.
همانطور که در زیر نشان داده شده است، میتوانیم روی یکی از مدلها همه چیز را انتخاب کنیم، جایی که من مدلهای مختلف را روی یک ویدیو قرار دادهام تا بتوانیم تأثیر آن را در پخش روی یک رسانه بسیار پویا ببینیم:
نوع دیگری از نیمهتون که فکر میکردم برجسته کردن آن جالب است نوع حلقه. من در ابتدا از برخی از کارها الهام گرفتم @poetengineer__ که چند رندر نیم تنی غیرمعمول زیبا انجام داد:
☁️ https://t.co/P9jKe6NSBj
ایجاد یک حلقه در واقع ساده تر از آن چیزی است که به نظر می رسد: فقط باید دو دایره را تعریف کرده و با استفاده از آنها ترکیب کنیم A AND NOT B منطق ترکیبی

3
float radius = uRadius * (0.2 + luma);5
float ringThickness = 0.1;6
float innerRadius = radius - ringThickness;8
float outerCircle = smoothstep(radius - 0.01, radius + 0.01, dist);9
float innerCircle = smoothstep(innerRadius - 0.01, innerRadius + 0.01, dist);11
float ring = innerCircle * (1.0 - outerCircle);13
color = mix(vec4(0.0, 0.0, 0.0, 1.0), color, ring);
اعمال این افکت با یک پالت تک رنگ روی یک ویدیو یک نشان می دهد technical/low-res زیبایی شناختی، تقریباً مانند یک ترمینال، برخلاف نقاط روشن چشمگیرتر و با کنتراست بالا در نوع نیم تن استاندارد شما.
هافتون های چند کاناله و تداخل
تا اینجا ما مورد نیمهتون تک رنگ را در نظر گرفتهایم، که در آن تنها با غلظت نقاط در یک شبکه تعیین میشوند. ما همچنین نیمتنهای «رنگی» را امتحان کردیم، اما فقط رنگها را از بافت/رسانه زیرین انتخاب میکردیم و توهم نوری این اثر را تا حد کامل تحت فشار قرار نمیدادیم.
در واقع، به جای اینکه نیمتون را به عنوان یک شبکه ساده در نظر بگیریم، میتوانیم آن را نیز به عنوان یک شبکه در نظر بگیریم انبوهی از میله ها، که در آن هر لایه مربوط به یک کانال رنگی خاص از تصویر پایه است. ما میتوانیم لایههای خود را که با کانالهای رنگی قرمز، سبز و آبی برای نمای RGB تعریف شدهاند، یا فیروزهای، سرخابی، زرد و کلید برای یک چاپ کلاسیک CMYK استخراج کنیم. این تکنیک کاری را که ما میتوانیم در زمینه ساخت سایهبانهای نیمهتون انجام دهیم، گسترش میدهد، اما به قیمت مصنوعات بصری و آشفتگیهایی نیز تمام میشود که ابتدا باید آنها را درک کنیم تا بتوانیم در اطراف آنها کار کنیم.
الگوی مویر
ممکن است گهگاه با الگوهای موآر در رندرهای خود در هنگام آزمایش با الگوهای تکرار شونده مواجه شده باشید. این نوع تداخل زمانی اتفاق میافتد که دو الگوی تقریباً یکسان روی یکدیگر قرار میگیرند 3. از تقریبا یکسان، در اینجا منظورم این است:
-
آنها نمی توانند کاملاً یکسان باشند، برای مثال فرکانس های مختلف.
-
آنها می توانند یکسان باشند، اما باید جابجا یا چرخانده شوند.
این در هر دو رسانه فیزیکی و دیجیتال رخ می دهد و یکی دیگر از توهمات نوری / مصنوع ادراکی به دلیل تلاش مغز ما برای آشتی دادن تلاقی دو مدل رقیب است.
ویجت زیر این اثر را در مثال های بسیار ساده نشان می دهد که می توانید امتحان کنید:
-
ما نسخه ای داریم که در آن دو شبکه روی هم چیده شده اند. چرخاندن یکی باعث ایجاد اختلال بسیار زیادی می شود.
-
مثال دیگر شامل یک توزیع پواسون دو لایه است که در آن کوچکترین چرخش آشفتگی های دایره ای را نشان می دهد.
پیاده سازی GLSL بسیار آسان است و می تواند به عنوان پایه ای برای تجارب Moiré مانند شما باشد.
1
mat2 rotate(float angle) {4
return mat2(c, -s, s, c);7
float circleGrid(vec2 uv, float radius, float angle) {8
vec2 normalizedPixelSize = uPixelSize / uResolution;11
vec2 uvPx = uv * uResolution;12
vec2 rotatedPx = rotate(angle) * uvPx;13
vec2 rotatedUv = rotatedPx / uResolution;15
vec2 cellUv = fract(rotatedUv / normalizedPixelSize);16
float dist = length(cellUv - 0.5);18
float edgeWidth = fwidth(dist);20
float circle = smoothstep(radius - edgeWidth, radius + edgeWidth, dist);28
float circleGridA = circleGrid(uv, uRadius, 0.0)29
float circleGridB = circleGrid(uv, uRadius, radians(uAngle))31
vec3 colorA = mix(vec3(1.0), vec3(0.0), circleGridA);32
vec3 colorB = mix(vec3(1.0), vec3(0.0), circleGridB);34
fragColor = vec4(max(colorA, colorB), 1.0);
این امر ناگزیر در مثالهای این بخش از مقاله اتفاق میافتد، زیرا ما شروع به ساخت یک نیمتن چند کانالی خواهیم کرد. مصنوع را می توان پذیرفت یا به عنوان یک مشکل کاهشی در نظر گرفت، همانطور که صنعت چاپ اغلب با اجرای راه حل ها انجام می دهد.
در مورد ما، ما این مشکل را حل خواهیم کرد اعمال چرخش های خاص برای هر لایه، بنابراین تداخل را به حداقل می رساند. با اجرای آتی نیمتنهای CMYK، این تکنیک را در عمل خواهیم دید.
ترکیب رنگ دیجیتال در مقابل فیزیکی
مورد استفاده اصلی برای اجرای نیم تنه چند کانالی ما این است که هر لایه حاوی یک کانال رنگی خاص باشد و با یکدیگر ترکیب شود. بازتولید اختلاط نوری موجود در چاپ فیزیکی. ما میتوانیم لایههایی را انتخاب کنیم که یکی از آنها را نشان میدهند:
با این حال، ترکیب این دو الگوی رنگ متفاوت است:
-
اولی بر اساس علاوه بر این نوری که از یک صفحه نمایش سیاه شروع می شود. کانال های رنگ قرمز، آبی و سبز رنگ سفید تولید می کنند.
-
آخرین مورد، در تفریق رنگ از نور جذب شده از کاغذ سفید شروع می شود. جوهرهای فیروزه ای، سرخابی و زرد نوری را که به آنها برخورد می کند فیلتر می کنند. هرچه بیشتر همپوشانی داشته باشند، رنگ حاصل تیره تر می شود، زیرا نور بیشتر فیلتر می شود و در نهایت به سیاهی می رسد.
ما میتوانیم این را به صورت دست اول در زیر ببینیم، جایی که من گزینههای ترکیب رنگ RGB و CMY را روی بومهای HTML بازتولید میکنم.
از نظر ریاضی، این چیزی است که اتفاق می افتد. برای نوع RGB، ما به سادگی شدت رنگ هر کانال را اضافه می کنیم، یعنی.
ColorOut = (Ir, 0, 0) + (0, Ig, 0) + (0, 0, Ib). افزودن/ترکیب کانال های رنگی کاری است که ما اغلب در GLSL برای چند اثر مانند شکست یا پراکندگی انجام می دهیم. با نزدیک شدن به ارزش ها 1.0، ترکیب آنها تمایل دارد (1.0, 1.0, 1.0)، یعنی سفید، که در نمودار زیر نشان داده شده است:
برای اختلاط تفریقی CMY، که از نظر ریاضی کمی اشتباه است، می توان آن را با ضرب نشان داد:
ColorOut = White * (1.0 - C) * (1.0 - M) * (1.0 - Y). را تفریق کننده ماهیت این اختلاط به فیزیک جذب نور مربوط می شود: هر کانال رنگی به عنوان فیلتری عمل می کند که طول موج های خاصی از نور سفید را جذب می کند و تنها باقی مانده را به بیننده می گذارد. به همین دلیل است که همپوشانی همه کانال های رنگی باعث سیاهی می شود.

نمودار زیر نمایه بازتاب رنگ های فیروزه ای، سرخابی و زرد را در طیف مرئی و همچنین فیلتر حاصل را نشان می دهد:
توجه کنید که چگونه رنگ حاصل با ترکیب مطابقت دارد ناحیه همپوشانی که بین همه منحنی ها مشترک است.
نیم تن CMYK
تنوع نیمهتونی که میخواهیم پوشش دهیم احتمالاً دلیل اصلی نوشتن مقاله در وهله اول است. من در ابتدا از برخی از کارها الهام گرفتم @floguo که رندرهایی تولید کرد که این مدل واقعاً درخشید.
مطالعه شماره 03 https://t.co/5V6Kf3fabI
این من را مجذوب خود کرد، بنابراین سعی کردم یک سایه زن را برای آن بازتولید کنم، که من را شگفت زده کرد و باعث شد در مورد ترکیب رنگ، موآر و به طور کلی نیم تنه چیزهای زیادی یاد بگیرم. از آنجایی که برای ساختن این افکت باید 4 شبکه جداگانه نقطه را روی هم قرار دهیم، اگر ساده لوحانه این کار را انجام دهیم بلافاصله الگوهای موآری به ما می دهد و رنگ ها را کمی تغییر می دهد. شسته شده. در عوض، ما باید هر لایه را با یک زاویه خاص بچرخانیم، مجموعه ای از زاویه ها، تا تصویری با کمترین مصنوعات ممکن به دست آوریم. ویجت زیر نوع نیمه آهنگ CMYK را با مقادیر زاویه ای از پیش تعیین شده نشان می دهد:
-
15.0برای فیروزه ای -
75.0برای سرخابی -
0.0برای زرد -
45.0برای یک کلید
توصیه می کنم با مقادیر زاویه و چگالی نقطه بازی کنید تا تفاوت ها را در نتیجه ببینید.
همانطور که در بالا می بینید، اندازه تک تک نقاط بسته به رنگ پایه نمونه متفاوت است. فقط با این 4 رنگ و توانایی تغییر اندازه و تراکم هر نقطه، میتوانیم هر نوع سایهای را که برای رندر کردن یک خروجی رنگی لازم است، درست مانند یک چاپ، بدست آوریم!

از منظر اجرایی، میتوانیم روی پایههای نیمهتون کلاسیک خود کار کنیم. با این حال، ابتدا باید رنگ خروجی خود را از RGB به CMYK تبدیل کنیم. من از تابعی از Matt DesLauriers برای انجام آن استفاده کردم:
1
vec4 RGBtoCMYK (vec3 rgb) {5
float k = min(1.0 - r, min(1.0 - g, 1.0 - b));11
cmy.x = (1.0 - r - k) / invK;12
cmy.y = (1.0 - g - k) / invK;13
cmy.z = (1.0 - b - k) / invK;16
return clamp(vec4(cmy, k), 0.0, 1.0);
سپس میتوانیم شبکه نقطهای خود را برای هر کانال جداگانه ایجاد کنیم و پوشش نقطه/شعاع آنها با شدت آن کانال رنگی در آن موقعیت صفحه نمایش داده شده مطابقت داشته باشد.
1
vec2 toGridUV(vec2 uv, float angleDeg) {2
return rot(angleDeg) * (uv * resolution) / pixelSize;5
vec2 getCellCenterUV(vec2 uv, float angleDeg) {6
vec2 gridUV = toGridUV(uv, angleDeg);7
vec2 cellCenter = floor(gridUV) + 0.5;8
vec2 centerScreen = rot(-angleDeg) * cellCenter * pixelSize;9
return centerScreen / resolution;12
float halftoneDot(vec2 uv, float angleDeg, float coverage) {13
vec2 gridUV = toGridUV(uv, angleDeg);14
vec2 distToCenter = fract(gridUV) - 0.5;16
float r = dotSize * sqrt(clamp(coverage, 0.0, 1.0));17
float aa = fwidth(length(distToCenter));18
float d = length(distToCenter);19
return 1.0 - smoothstep(r - aa, r + aa, d);22
void mainImage(const in vec4 inputColor, const in vec2 uv, out vec4 outputColor) {23
vec2 uvC = getCellCenterUV(uv, ANGLE_C);24
vec2 uvM = getCellCenterUV(uv, ANGLE_M);25
vec2 uvY = getCellCenterUV(uv, ANGLE_Y);26
vec2 uvK = getCellCenterUV(uv, ANGLE_K);28
vec4 cmykC = RGBtoCMYK(texture2D(inputBuffer, uvC).rgb);29
vec4 cmykM = RGBtoCMYK(texture2D(inputBuffer, uvM).rgb);30
vec4 cmykY = RGBtoCMYK(texture2D(inputBuffer, uvY).rgb);31
vec4 cmykK = RGBtoCMYK(texture2D(inputBuffer, uvK).rgb);33
float dotC = halftoneDot(uv, ANGLE_C, cmykC.x);34
float dotM = halftoneDot(uv, ANGLE_M, cmykM.y);35
float dotY = halftoneDot(uv, ANGLE_Y, cmykY.z);36
float dotK = halftoneDot(uv, ANGLE_K, cmykK.w);38
vec3 outColor = vec3(1.0);39
outColor.r *= (1.0 - CYAN_STRENGTH * dotC);40
outColor.g *= (1.0 - MAGENTA_STRENGTH * dotM);41
outColor.b *= (1.0 - YELLOW_STRENGTH * dotY);42
outColor *= (1.0 - BLACK_STRENGTH * dotK);44
outputColor = vec4(outColor, 1.0);
نسخه ی نمایشی زیر تجربه شخصی من از افکت نیم تن CMYK برای React Three Fiber است. میتوانید ببینید که چگونه افکت روی صحنههایی که شامل جزئیات پیچیده، جلوههای نوری و حرکت میشود، میدرخشد:
من واقعاً از این واقعیت لذت میبرم که در اینجا از حلقههای زیادی عبور میکنیم، از RGB به CMYK تا RGB شبیهسازی مجدد از طریق اختلاط تفریقآمیز، فقط برای اینکه ظاهر و احساس خاصی داشته باشیم.
تا کنون ما فقط نیمتنهایی را مطالعه کردهایم که در محدودههای یک شبکه کاملاً تعریفشده محدود شدهاند. اما اگر بخواهیم چه می شد تکان دادن چیزهای اطراف؟ آیا میتوانیم نقاطی در یک شبکه افست، همپوشانی یا حتی ادغام با یکدیگر داشته باشیم؟ این بخش پایانی به بررسی برخی از تغییرات غیرمعمول نیمهتونها میپردازد که من در تحقیقات خود با آنها مواجه شدهام و به دنبال پیادهسازی آنها با دور شدن از محدودیتهای شبکه است.
دیواره سلولی
مشکل اصلی شبکه ای که در قسمت 1 این مقاله ایجاد کردیم این است که موقعیت و اندازه نقاطی که می توانند اشغال کنند را محدود می کند. اگر آنها را بیش از حد به اطراف بچرخانید یا آنها را خیلی بزرگ کنید، باعث می شود هنگامی که آنها به مرزهای سلول های مربوطه خود برخورد می کنند.

به جای اینکه هر پیکسل از سلول خود آگاه باشد، باید پیاده سازی خود را تغییر دهیم و شروع به بررسی سلول های مجاور نیز کنیم. با بررسی الف 3x3 در اطراف پیکسل فعلی، می توانیم به نقاط اجازه دهیم نشتی از طریق سلول ها بدون برش.
نمونه برداری از سلول های مجاور
1
vec2 pixelCoord = vUv * uResolution;4
vec2 baseCellIndex = floor(pixelCoord / uPixelSize);6
vec4 finalColor = vec4(0.0);10
const int searchRadius = 1;12
for (int dx = -searchRadius; dx searchRadius; dx++) {13
for (int dy = -searchRadius; dy searchRadius; dy++) {14
vec2 cellIndex = baseCellIndex + vec2(float(dx), float(dy));15
vec2 cellCenter = (cellIndex + 0.5) * uPixelSize;17
vec2 uvPixel = cellCenter / uResolution;18
vec4 texColor = texture(uTexture, uvPixel);20
float dist = length(pixelCoord - cellCenter);22
float radius = uPixelSize * uRadius;24
float aa = fwidth(dist);25
float circle = 1.0 - smoothstep(radius - aa, radius + aa, dist);27
if (circle > maxCircle) {29
finalColor = texColor;34
vec3 bgColor = vec3(0.0);35
vec3 color = mix(bgColor, finalColor.rgb, maxCircle);
-
ما یک حلقه تودرتو معرفی می کنیم که در شعاع 1 سلول در اطراف موقعیت فعلی جستجو می کند.
-
الف را تعریف می کنیم
baseCellبه عنوان سلول فعلی ما برای پیکسل فعلی که shader قطعه ما در حال پردازش آن است. -
محاسبه می کنیم
cellCenterبه هر همسایه در3x3هسته این به ما امکان می دهد فاصله را اندازه گیری کنیمdistبین پیکسل فعلی و تمام مراکز سلول مجاور. -
ما در حال بررسی در دسترس بودن هستیم. رنگ را در مرکز آن همسایه نمونه برداری می کنیم تا رنگ نقطه را مشخص کنیم و بررسی کنیم که آیا آن نقطه همسایه خاص به اندازه کافی بزرگ است که به پیکسل فعلی ما برسد.
این مکانیسمی است که برش را پاک می کند، زیرا هر سلول اکنون می تواند برخی یا همه پیکسل های خود را بر اساس تأثیر سلول های همسایه رنگ آمیزی کند. کارهای زیادی وجود دارد که میتوانیم با این کار انجام دهیم، اولین مورد این است که اندازه دایرههایمان را بیشتر از اندازه سلول افزایش دهیم، که نتیجه زیبایی و تقریباً آبرنگی به دست میدهد.
نیم تن لزج
چه می شد اگر می توانستیم نقاطمان را شبیه جوهر کنیم؟ یا با شبیه سازی نوعی کشش سطحی بین نقاط مجاور آنها را سیال تر جلوه دهید؟
اکنون که میدانیم چگونه نقاط نیمهتون را در خارج از سلولهای شبکهشان رندر کنیم، هیچ چیزی مانع از انجام این کار نیست! با افزودن یک شعاع مبتنی بر درخشندگی برای نقاط ما، و همچنین ترکیب دایره های همپوشانی با smoothmin تابع 5، می توانیم نقاطمان را بزرگتر نشان دهیم مایع، گویی که آنها دارند کشش سطحی:
این دو تغییر کوچک به دایرههای مجاور که به اندازه کافی نزدیک به هم هستند اجازه میدهد تا به زیبایی با هم ادغام شوند، گویی قطرههای جوهر هستند. همانطور که در نسخه ی نمایشی زیر نشان داده شده است، نیم تنی با ظاهری ارگانیک تر می دهد که وقتی روی یک صحنه سه بعدی متحرک پوشانده می شود، می درخشد.
نقاط جابجا شده
به عنوان آخرین گزینه نیمهتون، میخواستم وقت بگذارم و به روشهایی نگاه کنم که میتوانیم با اجازه دادن به نقاط متحرک و حرکت، جلوه را پویاتر/زندهتر کنیم. ما تقریباً در حال حاضر دستور العمل برای رسیدن به این هدف را از طریق دو مثال قبلی داریم، و تنها چیزی که اکنون به آن نیاز داریم یک خوب است یک ایده برای درخواست
به نوبه خود منبع اولیه الهام من برای این بخش این اثر هنری بود @adamfuhrer، یک هنرمند تجسمی که من از طرفداران شدید او هستم.
مونا #plottertwitter https://t.co/dFTdoUqNL8

-
از الگوی نیم تنه حلقه ای استفاده می کند که در قسمت اول این مقاله دیدیم.
-
ما برخی از حلقهها را دور از موقعیت اصلی خود قرار دادهایم، به این معنی که هنگام رندر کردن افکت خود به یک هسته نسبتاً بزرگ نیاز داریم.
-
آنجاست مسیر در سمت چپ یک حرکت نوسانی از طریق حلقه ها. این چیزی است که ما هنوز باید اجرا کنیم!
برای این آزمایش دوباره استفاده کردم MouseTrail مؤلفهای که من در اصل برای نشان دادن اثر Pixelated Mouse Trail در مقاله پس از پردازش خود ایجاد کردم. همانطور که برای این افکت انجام داد، این مؤلفه مستقل مسیر مکان نما کاربر را با استفاده از:
خارج از صفحه نمایش داده می شود و بافت حاصل از آن مستقیماً به صورت یکنواخت به جلوه نیمه تون ما منتقل می شود. پس از نمونه برداری، می توانیم روشنایی کانال های قرمز و سبز را که نشان دهنده حرکت مکان نما در امتداد محورهای x و y هستند، دریافت کنیم تا جهت و شدت تغییر را بدانیم.
افست از بافت قلم مو
1
vec2 brushUV = cellCenter / resolution;2
vec4 brush = texture2D(brushTexture, brushUV);3
vec2 brushVel = clamp(brush.rg, -0.45, 0.45);4
float brushIntensity = length(brushVel);6
vec2 forwardDir = brushIntensity > 0.001 ? brushVel / brushIntensity : vec2(0.0);7
vec2 perpDir = vec2(-forwardDir.y, forwardDir.x);8
float side = sign(random(cellCenter) - 0.5);10
float t = smoothstep(0.0, 0.5, brushIntensity);11
float easeIn = t * t * t;12
float easedIntensity = mix(easeIn, t, 0.5);14
vec2 srcUV = clamp(cellCenter / resolution, 0.0, 1.0);15
vec3 srcColor = texture2D(inputBuffer, srcUV).rgb;18
vec2 displacement = forwardDir * 0.75 + perpDir * side * 0.25;20
cellCenter += displacement * mouseStrength * easedIntensity;
سپس افست به مرکز سلولهای مجاور اعمال میشود تا جایی که نقاط/حلقهها به صورت بصری نمایش داده میشوند، جابجا شود. این توهم حرکت را ایجاد می کند که در این مورد به صورت زیر تعریف می شود:
-
ابتدا جهت حرکت را مشخص می کنیم:
vec2 forwardDir = brushIntensity > 0.001 ? brushVel / brushIntensity : vec2(0.0); -
بردار جهت عمود را بدست می آوریم:
vec2 perpDir = vec2(-forwardDir.y, forwardDir.x); -
هر طرفی را که حلقه عمود بر آن حرکت کند انتخاب کنید
-
حرکت را ترکیب و سبک کنید. در مورد ما، نسبت به حرکت رو به جلو (75%) نسبت به طرفین (25%) سنگینتر است و این تصور را ایجاد میکند که حلقهها به آرامی فشار داده میشوند و به آرامی به طرفین حرکت میکنند.
یک بار دیگر، این پیاده سازی بر اساس آنچه در قسمت اول دیدیم ساخته شده و فقط از چند ترفند تاکتیکی تشکیل شده است. من قویاً کاوش بیشتر در مورد آنچه می توان با چنین مدلی انجام داد را تشویق می کنم.
همانطور که می بینید، از یک شکل بسیار ساده مانند یک دایره، می توانیم به سرعت به مجموعه ای از افکت های متنوع برویم که هر یک از دیگری جالب تر و لذت بخش تر است. این نیز در کد نشان داده شده است، زیرا من توانستم سایه بان های خود را در طول آزمایش های خود مدولار نگه دارم و از همان توابع از افکت های بسیار ساده تا موارد پیچیده تر استفاده مجدد کنم.
من از نوشتن در مورد نیم تنه کوچکم بسیار لذت بردم جستجوی جانبی، از آنجایی که موضوع مدت زیادی در لیست من بوده است. امیدوارم این مقاله به شما کمک کند تا شما را با یک برنامه سایه زن مقرون به صرفه آشنا کرده یا به برخی از موارد دیگر توجه کنید. آزار دهنده مفاهیم این به احتمال زیاد به عنوان مبنایی برای مقاله دیگری در سال جاری خواهد بود که قصد دارم در مورد این موضوع بنویسم نقاشی های بیدرنگ مبتنی بر سایه زن از نقطههای سادهای که بهطور تصادفی روی صفحه کشیده شدهاند، میتوانیم به سایهزنی برسیم که میتواند انواع مختلفی از سبکهای طراحی مانند امپرسیونیسم، پوانتیلیسم و آبرنگ را تقلید کند. بلوک های سازنده این سایه زن بسیار شبیه به مواردی است که در اینجا ارائه شده است و بار دیگر تطبیق پذیری نیم تنه را نشان می دهد. با این حال، این برای زمان دیگری خواهد بود! در همین حال، من شما را با یک تیزر از آنچه که باید انتظار داشته باشید، می گذارم.
نقاشی آبرنگ در زمان واقعی https://t.co/N9lOWTv1Ym
-
فراکت – کتاب سایه داران
-
رسم دایره های ضد اسم مستعار در OpenGL
-
الگوی Moiré – ویکی پدیا
-
نحوه تنظیم ترکیب رنگ دیجیتال: مقدمه ای بر میکس باکس
-
عملیات SDF، صحنه های پیچیده و فراکتال ها





![SVGO مفید[ptimization] ابزار SVGO مفید[ptimization] ابزار](https://www.sarasoueidan.com/assets/images/svgomg.png)
