آشنایی با Mipmap و فیلترینگ تکسچر در Three.js (WebGL)

هنگام ساخت تجربه‌های سه‌بعدی برای وب، تکسچرها همه جا هستند. یک آبجکت ساده می‌تواند تکسچر رنگ، Normal Map، Roughness Map، Metalness Map و تکسچرهای محیطی داشته باشد.

اما گاهی مشکلات عجیبی می‌بینید: تکسچرها تار به نظر می‌رسند، آبجکت‌های دور سوسو می‌زنند، الگوها پرنویز می‌شوند یا پرفورمنس افت می‌کند چون تکسچرها پرهزینه‌اند. خیلی از این مشکلات به دو مفهوم مهم مربوط‌اند: Mipmap و فیلترینگ تکسچر. بیایید ساده و کاربردی بررسی‌شان کنیم.

۱. WebGL تکسچر را چطور نمایش می‌دهد؟

تصویری ۱۰۲۴×۱۰۲۴ را روی یک مکعب سه‌بعدی تصور کنید. وقتی دوربین نزدیک است، مکعب حدود ۸۰۰×۸۰۰ پیکسل از صفحه را می‌گیرد و همه چیز خوب است. اما وقتی دوربین دور می‌شود، مکعب فقط ۵۰×۵۰ پیکسل می‌گیرد در حالی که تکسچر هنوز ۱۰۲۴×۱۰۲۴ است.

حالا WebGL با یک مسئله روبه‌روست: «چطور یک تصویر بزرگ را به تعداد خیلی کمی پیکسل تبدیل کنم؟» این فرایند نمونه‌برداری تکسچر (Texture Sampling) نام دارد.

۲. فیلترینگ تکسچر چیست؟

فیلترینگ روشی است که WebGL با آن تصمیم می‌گیرد برای هر پیکسل نهایی صفحه از کدام پیکسل‌های تکسچر استفاده کند. مثلاً ممکن است یک پیکسل صفحه بین چهار پیکسل تکسچر بیفتد و WebGL باید رنگ نهایی را حساب کند. روش‌های مختلف فیلترینگ نتایج متفاوتی می‌دهند.

۳. فیلتر Nearest

ساده‌ترین روش: WebGL نزدیک‌ترین پیکسل را انتخاب می‌کند.

texture.magFilter = THREE.NearestFilter;

خیلی سریع است و حالت پیکسل‌آرت می‌سازد، اما پله‌پله به نظر می‌رسد. کاربردهای رایج: بازی‌های پیکسلی، گرافیک رترو و تکسچرهای داده.

۴. فیلتر Linear

به جای انتخاب یک پیکسل، WebGL پیکسل‌های مجاور را ترکیب می‌کند — پیکسل قرمز کنار پیکسل آبی، بنفش می‌سازد.

texture.magFilter = THREE.LinearFilter;

نتیجه نرم‌تر است و معمولاً همان چیزی است که برای گرافیک سه‌بعدی واقع‌گرایانه می‌خواهیم.

۵. مشکل تکسچرهای دور

فیلترینگ یک مشکل را حل می‌کند، اما مشکل دیگری پیدا می‌شود. دیوار آجری را تصور کنید که فقط ۲۰ پیکسل از صفحه را می‌گیرد، در حالی که GPU هنوز از تکسچر اصلی ۲۰۴۸×۲۰۴۸ می‌خواند. نتیجه: سوسو زدن، آلیاسینگ و الگوهای پرنویز. اینجاست که Mipmap کمک می‌کند.

۶. Mipmap چیست؟

Mipmap مجموعه‌ای از نسخه‌های کوچک‌تر همان تکسچر است:

Level 0: 2048 × 2048
Level 1: 1024 × 1024
Level 2:  512 × 512
Level 3:  256 × 256
Level 4:  128 × 128
Level 5:   64 × 64

آن را مثل داشتن چند نسخه با کیفیت‌های مختلف از یک تصویر ببینید.

۷. WebGL از Mipmap چطور استفاده می‌کند؟

وقتی آبجکت نزدیک است، GPU از سطح ۲۰۴۸×۲۰۴۸ استفاده می‌کند. وقتی دور است، از چیزی مثل ۱۲۸×۱۲۸. GPU نسخه مناسب را خودکار انتخاب می‌کند.

مزایا: ✅ کیفیت بهتر، ✅ کار کمتر برای GPU، ✅ سوسوی کمتر، ✅ پرفورمنس بهتر.

۸. فیلترینگ Mipmap در Three.js

Three.js برای بیشتر تکسچرها Mipmap را خودکار فعال می‌کند:

const texture = textureLoader.load("/textures/wood.jpg");
// به صورت پیش‌فرض:
texture.generateMipmaps = true;

فیلتر کوچک‌نمایی پیش‌فرض THREE.LinearMipmapLinearFilter است، یعنی: از Mipmap استفاده کن، بین سطوح Mipmap ترکیب کن و انتقال نرم بساز.

۹. کنترل فیلترینگ در Three.js

یک تنظیم رایج:

const texture = loader.load("/textures/ground.jpg");

texture.wrapS = THREE.RepeatWrapping;
texture.wrapT = THREE.RepeatWrapping;

texture.minFilter = THREE.LinearMipmapLinearFilter;
texture.magFilter = THREE.LinearFilter;
  • minFilter وقتی استفاده می‌شود که تکسچر روی صفحه کوچک‌تر می‌شود (آبجکت بزرگ ← آبجکت کوچک).
  • magFilter وقتی استفاده می‌شود که تکسچر روی صفحه بزرگ‌تر می‌شود (تکسچر کوچک ← آبجکت زوم‌شده).

۱۰. کی Mipmap را غیرفعال کنیم؟

Mipmap عالی است اما نه همیشه. تکسچرهای پویا — Canvas Texture، Render Target، ترکیب‌کننده Decal و تکسچرهای رابط کاربری روی آبجکت‌های سه‌بعدی — ممکن است دچار نشت ناخواسته رنگ شوند. اگر لوگوی قرمز روی زمینه سفید بکشید، سطوح کوچک‌تر Mipmap پیکسل‌های قرمز و سفید را مخلوط می‌کنند و لبه‌های لوگو تار می‌شوند. در این حالت‌ها:

texture.generateMipmaps = false;
texture.minFilter = THREE.LinearFilter;

۱۱. مثال واقعی: Canvas Texture در Three.js

const canvas = document.createElement("canvas");
const texture = new THREE.CanvasTexture(canvas);

texture.generateMipmaps = false;
texture.minFilter = THREE.LinearFilter;
texture.magFilter = THREE.LinearFilter;

این برای برچسب‌ها، متن پویا، نقاشی‌های سفارشی و Decal کاربردی است.

۱۲. یک قانون ساده برای به خاطر سپردن

برای بیشتر مدل‌های سه‌بعدی:

texture.generateMipmaps = true;
texture.minFilter = THREE.LinearMipmapLinearFilter;
texture.magFilter = THREE.LinearFilter;

برای تکسچرهای پویا:

texture.generateMipmaps = false;
texture.minFilter = THREE.LinearFilter;

جمع‌بندی

Mipmap و فیلترینگ فقط تنظیمات پرفورمنس نیستند؛ مستقیماً روی کیفیت بصری، پرفورمنس GPU، وضوح تکسچر و تجربه کاربری اثر می‌گذارند. دفعه بعد که تکسچر سوسوزن، جزئیات تار یا لبه‌های عجیب دیدید، یادتان باشد: شاید مشکل از مدل شما نباشد؛ شاید از شیوه نمونه‌برداری WebGL از تکسچرها باشد.