پخشکردن مایع روی صفحه با three.js و شبیهسازی سیال
خلاصهٔ کاملتر
نویسنده که تو Vue Fes Japan 2026 دربارهی این افکت حرف زده، توی این پست توضیح میده چطوری افکت پخششدن کرمپودر رو برای یه پروژهی تبلیغاتی سال ۲۰۲۱ ساخته. خودش میگه اولش نمیدونست از کجا شروع کنه و یه ماه با کرمپودر ور رفت تا بفهمه چی باعث میشه شبیه مایع رفتار کنه. آخرش به این رسید که وقتی انگشت رو توی مایع میکشی، طرف مقابل برآمده میشه و اطرافش هم کشیده میشه؛ پس سراغ شبیهسازی سیال رفت.
پایهی کار همون شبیهسازی Stable Fluids مقالهی قبلی نویسندهست که یه velocity map میسازه، یعنی تصویری که جهت و سرعت حرکت رو برای هر نقطهی صفحه نگه میداره. هندسه هیچ تغییری نمیکنه و همهچیز توی fragment shader رندر میشه. ضخامت مایع توی یه FBO جدا (یعنی یه تصویر که GPU روش رندر میکنه و بعد ازش میخونه) به اسم height map ذخیره میشه. مقدار اولیه یه نیمکرهست که توی کانال R ریخته میشه.
برای جابهجا کردن ضخامت، هر پیکسل اول بر اساس سرعتش یه مقدار removed از ضخامت خودش کم میکنه. بعد با advection، یعنی دنبال کردن سرعت به عقب، میفهمه این مایع از کجا اومده و یه مقدار added از اونجا برمیداره:
vec2 sourceUv = backtraceUv(vUv, flow, fboSize, dt);
float sourceHeight = texture2D(heightMap, sourceUv).r;ضخامت جدید میشه max(0.0, previousHeight - removed + added). با smoothstep() جاهایی که سرعت کمه تقریباً تکون نمیخورن، و هر فریم بین دو FBO جابهجا میشه. چون fragment shader پیکسلها رو موازی پردازش میکنه و یه پیکسل نمیتونه مستقیم روی پیکسل دیگه بنویسه، چند پیکسل ممکنه از یه جا نمونه بگیرن. یعنی حجم کل مایع ثابت نمیمونه: با حرکت صاف تقریباً پایداره، ولی با کشیدن دایره مایع مدام زیاد میشه.
height map فقط برآمدگی رو نشون میده و رد نازک مایع رو نگه نمیداره. برای همین یه alpha map جدا هست که بیشترین مقدار ضخامت تا حالا رو تو کانال R نگه میداره و تو کانال G میانگین اون با مقدار فعلی رو. رندر نهایی از G میخونه، پس وقتی مایع رد میشه رنگ یهو صفر نمیشه و انگار به سطح چسبیده. برای نور، normal سطح از ضرب خارجی دو بردار بین هر پیکسل و همسایههاش در جهت X و Y ساخته میشه و بعد با یه Matcap (یعنی تصویری که رنگ و نور رو بر اساس جهت سطح میده) رنگ میگیره.
دو تا بونوس هم هست. اول، دقت texture: با texture هشتبیتی فقط ۲۵۶ سطح ارتفاع داریم و توی سایهها پلهپله دیده میشه، ولی با texture اعشاری ۳۲ بیتی سطح صافتره. دوم، سه مایع رنگی که velocity map مشترک ولی height map و alpha جدا دارن و رنگهاشون با یه مدل سادهشدهی Kubelka–Munk مخلوط میشه. نویسنده آخر میگه این روش رو الان نوشته چون هوش مصنوعی داره تو فهم فضا و مختصات خیلی بهتر میشه و میخواست ردی از فکر خودش بمونه.
نکات کلیدی:
- افکت برای سایت تبلیغاتی کرمپودر یه برند آرایشی ژاپنی تو سال ۲۰۲۱ ساخته شده.
- ضخامت مایع تو کانال R یه height map نگه داشته میشه و با velocity map شبیهسازی Stable Fluids جابهجا میشه.
- هر فریم بین دو FBO جابهجا میشه و هندسه اصلاً تغییر نمیکنه.
- alpha map با نگه داشتن بیشترین مقدار ضخامت، رد مایع رو روی سطح حفظ میکنه.
- روش حجم مایع رو حفظ نمیکنه و با حرکت دایرهای مایع زیاد میشه.
- texture هشتبیتی فقط ۲۵۶ سطح داره و توی سایهها پله میندازه؛ texture اعشاری ۳۲ بیتی صافتره.




