فاز 4 · درس 22

آموزش 3D Gaussian Splatting از صفر تا پیاده‌سازی و خروجی

نوع
ساختنی
زمان
حدود 90 دقیقه
زبان‌ها
Python
نمایی شماتیک از ذرات بیضوی درخشان و رنگی معلق در فضا که با دقت بالا حجم یک شیء سه‌بعدی را شکل داده‌اند
فهرست مطالب
  1. اهداف یادگیری
  2. صورت مسئله
  3. مفاهیم پایه
  4. مشخصات هر گوسی
  5. رسترایزیشن به جای پرتوپیمایی
  6. مرحله‌ی تصویر کردن
  7. قاعده‌ی ترکیب آلفا
  8. چرا این فرایند مشتق‌پذیر است؟
  9. متراکم‌سازی و هرس کردن
  10. هارمونیک‌های کروی در یک پاراگراف
  11. استک عملیاتی در سال 2026
  12. مدل‌های چهاربعدی و زایشی
  13. ساخت گام‌به‌گام
  14. مرحله‌ی 1: تعریف یک گوسی دوبعدی
  15. مرحله‌ی 2: رسترایزر پاشش دوبعدی
  16. مرحله‌ی 3: ساخت یک صحنه‌ی پاشش دوبعدی آموزش‌پذیر
  17. مرحله‌ی 4: برازش گوسی‌های دوبعدی روی یک تصویر هدف
  18. مرحله‌ی 5: از دوبعدی به سه‌بعدی
  19. مرحله‌ی 6: محاسبه‌ی هارمونیک‌های کروی
  20. استفاده‌ی عملی
  21. تحویل پروژه
  22. تمرین‌ها
  23. اصطلاحات کلیدی
  24. برای مطالعه‌ی بیشتر

مدل‌های NeRF با وجود کیفیت بالا در بازسازی سه‌بعدی، به دلیل رندرینگ مبتنی بر پرتوپیمایی و پرس‌وجوهای سنگین از شبکه‌های عصبی، سرعت بسیار پایینی در آموزش و رندر بلادرنگ دارند. روش پاشش گوسی سه‌بعدی (3D Gaussian Splatting یا 3DGS) این گلوگاه را با جایگزینی یک نمایش صریح از میلیون‌ها بیضی‌گون گوسی و رسترایزیشن مستقیم روی کارت گرافیک حل کرده است؛ به طوری که می‌توان به رندر بلادرنگ با بیش از 100 فریم بر ثانیه دست یافت.

در این درس علاوه بر شناخت ساختار ریاضی گوسی‌ها، ماتریس‌های کوواریانس و هارمونیک‌های کروی (Spherical Harmonics)، یک رسترایزر مشتق‌پذیر را گام‌به‌گام پیاده‌سازی می‌کنید و نحوه‌ی استفاده از ابزارهای استانداردی مانند nerfstudio و gsplat را برای کار با صحنه‌های واقعی فرامی‌گیرید.

اگر برای پروژه‌های عملی به آموزش مدل‌های بزرگ با کارت‌های گرافیک قدرتمند ابری نیاز داشته باشید، به دلیل محدودیت‌های پرداخت ارزی یا دسترسی ناپایدار به برخی ارائه‌دهندگان خارجی، شبیه‌سازی‌های اولیه و اجرای کد دوبعدی این درس روی سیستم شخصی گزینه‌ی مناسبی است. همچنین برای نصب بسته‌های پایتون ممکن است به استفاده از آینه‌های داخلی نیاز پیدا کنید.

هر صحنه ابری از میلیون‌ها گوسی سه‌بعدی است. هر کدام موقعیت، جهت‌گیری، مقیاس، شفافیت و رنگی وابسته به زاویه‌ی دید دارند. آن‌ها را رسترایز کنید، پس‌انتشار را در فرایند رسترایزیشن اجرا کنید، و تمام.

اهداف یادگیری

  • توضیح این‌که چرا پاشش گوسی سه‌بعدی (3D Gaussian Splatting) در سال 2026 به عنوان گزینه‌ی پیش‌فرض عملیاتی برای بازسازی واقع‌گرایانه‌ی سه‌بعدی جایگزین NeRF شد
  • بیان شش پارامتر اختصاصی هر گوسی (موقعیت، کواترنیون دوران، مقیاس، شفافیت، رنگ بر پایه‌ی هارمونیک‌های کروی، ویژگی اختیاری) و سهم هر کدام از تعداد مقادیر اعشاری (float)
  • پیاده‌سازی یک رسترایزر پاشش گوسی دوبعدی از صفر با ترکیب آلفا (alpha compositing)، و سپس نمایش نحوه‌ی نگاشت حالت سه‌بعدی به همین حلقه
  • استفاده از nerfstudio، gsplat یا SuperSplat برای بازسازی یک صحنه از 20 تا 50 عکس و خروجی گرفتن در قالب افزونه‌ی KHR_gaussian_splatting برای glTF یا اسکیمای UsdVolParticleField3DGaussianSplat در OpenUSD 26.03

صورت مسئله

مدل NeRF صحنه را درون وزن‌های یک پرسپترون چندلایه (MLP) ذخیره می‌کند. رندر هر پیکسل نیازمند صدها بار پرس‌وجو از MLP در امتداد یک پرتو است. آموزش ساعت‌ها زمان می‌برد، رندر ثانیه‌ها طول می‌کشد و وزن‌ها قابل ویرایش نیستند؛ اگر بخواهید جای یک صندلی را درون صحنه تغییر دهید، باید مدل را از اول آموزش دهید.

تکنیک 3D Gaussian Splatting (کرِبل، کوپاناس، لایم‌کولر، درِتاکیس، SIGGRAPH 2023) همه‌ی این معادلات را تغییر داد. در این روش، صحنه مجموعه‌ای صریح از گوسی‌های سه‌بعدی است. رندر تصویر از طریق رسترایزیشن روی GPU با سرعت بیش از 100 فریم بر ثانیه انجام می‌شود. فرایند آموزش تنها چند دقیقه طول می‌کشد و ویرایش کاملاً مستقیم است: کافی است دسته‌ای از گوسی‌ها را جابه‌جا کنید تا صندلی حرکت کند. تا سال 2026، گروه Khronos یک افزونه‌ی glTF برای پاشش‌های گوسی تصویب کرده است، نسخه‌ی 26.03 اوپن‌یواس‌دی (OpenUSD) با یک اسکیمای پاشش گوسی عرضه می‌شود، وب‌سایت‌های Zillow و Apartments.com املاک را با این فرمت رندر می‌کنند و بیشتر مقالات پژوهشی جدیدِ حوزه‌ی بازسازی سه‌بعدی، انشعابی از ایده‌ی اصلی 3DGS هستند.

مدل ذهنی این روش ساده است، اما ریاضیات آن بخش‌های متحرک زیادی دارد؛ به طوری که بیشتر آموزش‌ها از رسترایزیشن شروع می‌کنند و از روی تصویر کردن (projection) و هارمونیک‌های کروی می‌گذرند. در این درس کل این ساختار را پیاده‌سازی می‌کنیم: اول یک نسخه‌ی دوبعدی، و سپس تعمیم آن به حالت سه‌بعدی.

مفاهیم پایه

مشخصات هر گوسی

یک گوسی سه‌بعدی لکه‌ای پارامتریک در فضاست که ویژگی‌های زیر را دارد:

position         mu         (3,)    centre in world coordinates
rotation         q          (4,)    unit quaternion encoding orientation
scale            s          (3,)    log-scales per axis (exponentiated at render time)
opacity          alpha      (1,)    post-sigmoid opacity [0, 1]
SH coefficients  c_lm       (3 * (L+1)^2,)   view-dependent colour

ترکیب دوران و مقیاس، یک کوواریانس 3×3 می‌سازد: Sigma = R S S^T R^T. این ماتریس شکل گوسی را در فضای سه‌بعدی تعیین می‌کند. هارمونیک‌های کروی (Spherical Harmonics یا به اختصار SH) این امکان را می‌دهند که رنگ با تغییر زاویه‌ی دید عوض شود — مثل بازتاب‌های براق، درخشش‌های ظریف و نورهای وابسته به زاویه‌ی دید — بدون این‌که نیاز باشد برای هر نما بافت جداگانه‌ای ذخیره کنید. با درجه‌ی هارمونیک کروی 3، برای هر کانال رنگی 16 ضریب و در مجموع 48 عدد اعشاری فقط برای رنگ هر گوسی خواهید داشت.

یک صحنه معمولاً بین 1 تا 5 میلیون گوسی دارد. هر گوسی تقریباً 60 عدد اعشاری ذخیره می‌کند (3 + 4 + 3 + 1 + 48 + متفرقه‌ها). این یعنی برای صحنه‌ای با پنج میلیون گوسی، حجم داده حدود 240 مگابایت خواهد بود؛ بسیار سبک‌تر از یک ابر نقطه‌ای معادل با بافت مجزا برای هر نقطه، و یک مرتبه بزرگی کوچک‌تر از وزن‌های MLP یک NeRF که با رزولوشن بالا دوباره رندر شود.

رسترایزیشن به جای پرتوپیمایی

میلیون‌ها گوسی 3بعدی(موقعیت، چرخش، مقیاس،شفافیت، رنگ SH)تصویر به 2بعدی(پارامترهای بیرونی و درونی دوربین)تخصیص به تایل‌ها(16x16 در فضای صفحه)مرتب‌سازی عمقدر هر تایلترکیب آلفااز جلو به عقبرنگ پیکسل

پنج مرحله که همگی برای پردازش روی GPU بهینه‌اند. نیازی به اجرای MLP به ازای هر پیکسل نیست. یک کارت گرافیک RTX 3080 Ti به تنهایی 6 میلیون پاشش را با نرخ 147 فریم بر ثانیه رندر می‌کند.

مرحله‌ی تصویر کردن

گوسی سه‌بعدی با موقعیت جهانی mu و کوواریانس سه‌بعدی Sigma، به یک گوسی دوبعدی با موقعیت صفحه‌ی نمایش mu' و کوواریانس دوبعدی Sigma' تصویر می‌شود:

μ′=project(μ)Σ′=JWΣWTJT(2×2)W=viewing transform (rotation + translation of camera)J=Jacobian of the perspective projection at μ′\begin{aligned} \mu' &= \mathop{\mathrm{project}}(\mu) \\ \Sigma' &= J W \Sigma W^T J^T \qquad (2 \times 2) \\[6pt] W &= \text{viewing transform (rotation + translation of camera)} \\ J &= \text{Jacobian of the perspective projection at } \mu' \end{aligned}

ردپای گوسی دوبعدی بیضه‌ای است که محورهای آن بردارهای ویژه‌ی Sigma' هستند. هر پیکسل درون این بیضه، سهمی از این گوسی دریافت می‌کند که با ضریب exp(-0.5 * (p - mu')^T Sigma'^-1 (p - mu')) وزن‌دهی می‌شود.

قاعده‌ی ترکیب آلفا

برای یک پیکسل، گوسی‌هایی که آن را می‌پوشانند از عقب به جلو مرتب می‌شوند (یا به طور معادل از جلو به عقب با فرمول معکوس). ترکیب رنگ با همان معادله‌ای انجام می‌شود که از دهه‌ی 1980 در تمام رسترایزرهای نیمه‌شفاف به کار رفته است:

Cpixel=∑iαiTiciTi=∏j<i(1−αj)transmittance up to iαi=opacityi⋅exp⁡(−0.5 dTΣ′−1d)local contributionci=eval_SH(SHi,view_direction)view-dependent colour\begin{aligned} C_{\text{pixel}} &= \sum_i \alpha_i T_i c_i \\[6pt] T_i &= \prod_{j < i} (1 - \alpha_j) && \text{transmittance up to } i \\ \alpha_i &= \text{opacity}_i \cdot \exp\left(-0.5 \, d^T \Sigma'^{-1} d\right) && \text{local contribution} \\ c_i &= \mathop{\mathrm{eval\_SH}}(\text{SH}_i, \text{view\_direction}) && \text{view-dependent colour} \end{aligned}

این فرمول دقیقاً همان معادله‌ی رندر حجمی NeRF است؛ فقط به جای نمونه‌برداری‌های متراکم در طول پرتو، روی مجموعه‌ای صریح و تنک از گوسی‌ها محاسبه می‌شود. همین تطابق ریاضی باعث شده کیفیت رندر با NeRF برابری کند، چرا که هر دو انتگرال یکسانی از میدان درخشندگی را حل می‌کنند.

چرا این فرایند مشتق‌پذیر است؟

تمام مراحل — تصویر کردن، تخصیص به تایل‌ها، ترکیب آلفا، محاسبه‌ی هارمونیک‌های کروی — نسبت به پارامترهای گوسی مشتق‌پذیرند. با داشتن یک تصویر مرجع (ground-truth)، تابع زیان (loss) پیکسل‌های رندرشده محاسبه می‌شود، پس‌انتشار از درون رسترایزر انجام می‌گیرد و تمام پارامترهای (mu, q, s, alpha, c_lm) با روش گرادیان کاهشی (gradient descent) به‌روزرسانی می‌شوند. پس از حدود 30,000 تکرار، گوسی‌ها به درستی در موقعیت، مقیاس و رنگ متناسب خود می‌نشینند.

متراکم‌سازی و هرس کردن

تعداد ثابتی از گوسی‌ها نمی‌تواند جزئیات یک صحنه‌ی پیچیده را پوشش دهد. فرایند آموزش شامل دو سازوکار تطبیقی است:

  • تکثیر (Clone): وقتی اندازه‌ی گرادیان یک گوسی بزرگ ولی مقیاس آن کوچک است، یک نسخه از آن در همان موقعیت ساخته می‌شود؛ زیرا بازسازی در این بخش به جزئیات بیشتری نیاز دارد.
  • شکستن (Split): وقتی گرادیان یک گوسیِ مقیاس‌بزرگ بالا باشد، به دو گوسی کوچک‌تر شکسته می‌شود؛ چرا که یک گوسی درشت بیش از حد نرم است و نمی‌تواند ناحیه را به خوبی برازش کند.
  • هرس کردن (Prune): گوسی‌هایی که شفافیت آن‌ها از یک آستانه (threshold) کمتر شود حذف می‌شوند؛ چون نقشی در خروجی ندارند.

متراکم‌سازی هر NN تکرار یک‌بار اجرا می‌شود. یک صحنه معمولاً از حدود 100 هزار گوسی اولیه (برگرفته از نقاط SfM) شروع می‌کند و در پایان آموزش به 1 تا 5 میلیون گوسی می‌رسد.

هارمونیک‌های کروی در یک پاراگراف

رنگ وابسته به نما تابعی به شکل c(direction) روی کره‌ی واحد است. هارمونیک‌های کروی در واقع همان پایه‌ی (basis) فوریه برای فضای کروی هستند. اگر بسط را در درجه‌ی L قطع کنید، (L+1)^2 تابع پایه برای هر کانال خواهید داشت. محاسبه‌ی رنگ برای یک نمای جدید، حاصل ضرب داخلی (dot product) بین ضرایب یادگرفته‌شده‌ی SH و توابع پایه‌ی محاسبه‌شده در جهت زاویه‌ی دید است. درجه‌ی 0 یعنی یک ضریب و در نتیجه رنگ ثابت؛ درجه‌ی 3 یعنی 16 ضریب، که برای نمایش سایه‌زنی لامبرتی، بازتاب‌های آینه‌ای و درخشش‌های ملایم کاملاً کافی است. مقالات پاشش گوسی سه‌بعدی به طور پیش‌فرض از درجه‌ی 3 استفاده می‌کنند.

استک عملیاتی در سال 2026

1. Capture         smartphone / DJI drone / handheld scanner
2. SfM / MVS       COLMAP or GLOMAP derives camera poses + sparse points
3. Train 3DGS      nerfstudio / gsplat / inria official / PostShot (~10-30 min on RTX 4090)
4. Edit            SuperSplat / SplatForge (clean floaters, segment)
5. Export          .ply -> glTF KHR_gaussian_splatting or .usd (OpenUSD 26.03)
6. View            Cesium / Unreal / Babylon.js / Three.js / Vision Pro

مدل‌های چهاربعدی و زایشی

  • پاشش گوسی چهاربعدی (4D Gaussian Splatting): گوسی‌ها توابعی از زمان هستند؛ کاربرد در ویدیوهای حجمی (فیلم Superman 2026، موزیک ویدیوی «Helicopter» از A$AP Rocky).
  • پاشش‌های زایشی (Generative splats): مدل‌های تبدیل متن به پاشش گوسی (مثل Marble محصول World Labs) که صحنه‌های کامل را از صفر بازتولید می‌کنند.
  • تبدیل بی‌پایه‌ی پاشش گوسی سه‌بعدی (3D Gaussian Unscented Transform): نسخه‌ای از NVIDIA NuRec برای شبیه‌سازی رانندگی خودران.
اسپلتینگ گوسی سه‌بعدی (3DGS)پروجکشن و ترکیب لکه‌ها، بدون ray marching
3D GAUSSIAN SPLATTINGA scene is millions of 3D Gaussians, each carrying a centre, a rotation+scale covariance, an opacity, and view-dependent colour. Rendering projects every blob to a 2D ellipse, sorts them by depth, and alpha-composites front to back, the same blend NeRF needed hundreds of MLP queries to approximate. That is why splats render at 100+ fps and train in minutes.ابری از گوسی‌های سه‌بعدی جهت‌دار، مرتب‌شده و ترکیب‌شده با آلفاهر اسپلت:mu, R, s,آلفا، SHرستریزاسیون،نه ray marchبدون پرس‌وجوی MLP برای هر پرتو؛ تصویر هر لکه به 2D و ترکیب با 100+ fps
یک صحنه متشکل از میلیون‌ها گوسی سه‌بعدی است که هر کدام دارای یک مرکز، کوواریانس چرخش+مقیاس، شفافیت و رنگ وابسته به زاویه دید هستند. در رندرینگ، هر لکه روی یک بیضی دوبعدی تصویر می‌شود، بر اساس عمق مرتب شده و از جلو به عقب ترکیب آلفا (alpha-composite) می‌گردد؛ دقیقاً همان ترکیبی که NeRF برای تقریب آن به صدها پرس‌وجوی MLP نیاز داشت. به همین دلیل اسپلت‌ها با سرعت 100+ فریم بر ثانیه رندر می‌شوند و آموزش آن‌ها تنها چند دقیقه زمان می‌برد.

ساخت گام‌به‌گام

مرحله‌ی 1: تعریف یک گوسی دوبعدی

ابتدا یک رسترایزر دوبعدی می‌سازیم. حالت سه‌بعدی پس از مرحله‌ی تصویر کردن، به همین ساختار تبدیل می‌شود.

import torch
import torch.nn as nn
import torch.nn.functional as F


def eval_2d_gaussian(means, covs, points):
    """
    means:  (G, 2)      centres
    covs:   (G, 2, 2)   covariance matrices
    points: (H, W, 2)   pixel coordinates
    returns: (G, H, W)  density at every pixel for every Gaussian
    """
    G = means.size(0)
    H, W, _ = points.shape
    flat = points.view(-1, 2)
    inv = torch.linalg.inv(covs)
    diff = flat[None, :, :] - means[:, None, :]
    d = torch.einsum("gpi,gij,gpj->gp", diff, inv, diff)
    density = torch.exp(-0.5 * d)
    return density.view(G, H, W)

عملگر einsum فرم مربعی diff^T Sigma^-1 diff را برای تک‌تک جفت‌های (گوسی، پیکسل) محاسبه می‌کند.

مرحله‌ی 2: رسترایزر پاشش دوبعدی

ترکیب آلفا به صورت جلو به عقب پیاده می‌شود. از آنجا که عمق در فضای دوبعدی معنایی ندارد، از یک اسکالر یادگرفتنی به ازای هر گوسی برای تعیین ترتیب استفاده می‌کنیم.

def rasterise_2d(means, covs, colours, opacities, depths, image_size):
    """
    means:     (G, 2)
    covs:      (G, 2, 2)
    colours:   (G, 3)
    opacities: (G,)     in [0, 1]
    depths:    (G,)     per-Gaussian scalar used for ordering
    image_size: (H, W)
    returns:   (H, W, 3) rendered image
    """
    H, W = image_size
    yy, xx = torch.meshgrid(
        torch.arange(H, dtype=torch.float32, device=means.device),
        torch.arange(W, dtype=torch.float32, device=means.device),
        indexing="ij",
    )
    points = torch.stack([xx, yy], dim=-1)

    densities = eval_2d_gaussian(means, covs, points)
    alphas = opacities[:, None, None] * densities
    alphas = alphas.clamp(0.0, 0.99)

    order = torch.argsort(depths)
    alphas = alphas[order]
    colours_sorted = colours[order]

    T = torch.ones(H, W, device=means.device)
    out = torch.zeros(H, W, 3, device=means.device)
    for i in range(means.size(0)):
        a = alphas[i]
        out += (T * a)[..., None] * colours_sorted[i][None, None, :]
        T = T * (1.0 - a)
    return out

این کد سریع نیست — پیاده‌سازی‌های واقعی از کرنل‌های (kernel) تایل‌محور CUDA بهره می‌برند — اما فرمول ریاضی آن کاملاً دقیق و فرایندش کاملاً مشتق‌پذیر است.

مرحله‌ی 3: ساخت یک صحنه‌ی پاشش دوبعدی آموزش‌پذیر

class Splats2D(nn.Module):
    def __init__(self, num_splats=128, image_size=64, seed=0):
        super().__init__()
        g = torch.Generator().manual_seed(seed)
        H, W = image_size, image_size
        self.means = nn.Parameter(torch.rand(num_splats, 2, generator=g) * torch.tensor([W, H]))
        self.log_scale = nn.Parameter(torch.ones(num_splats, 2) * math.log(2.0))
        self.rot = nn.Parameter(torch.zeros(num_splats))  # single angle in 2D
        self.colour_logits = nn.Parameter(torch.randn(num_splats, 3, generator=g) * 0.5)
        self.opacity_logit = nn.Parameter(torch.zeros(num_splats))
        self.depth = nn.Parameter(torch.rand(num_splats, generator=g))

    def covs(self):
        s = torch.exp(self.log_scale)
        c, si = torch.cos(self.rot), torch.sin(self.rot)
        R = torch.stack([
            torch.stack([c, -si], dim=-1),
            torch.stack([si, c], dim=-1),
        ], dim=-2)
        S = torch.diag_embed(s ** 2)
        return R @ S @ R.transpose(-1, -2)

    def forward(self, image_size):
        covs = self.covs()
        colours = torch.sigmoid(self.colour_logits)
        opacities = torch.sigmoid(self.opacity_logit)
        return rasterise_2d(self.means, covs, colours, opacities, self.depth, image_size)

پارامترهای log_scale، opacity_logit و colour_logits همگی بدون محدودیت تعریف می‌شوند و در زمان رندر از تبدیل مناسب عبور می‌کنند. این الگوی استاندارد در تمام پیاده‌سازی‌های 3DGS است.

مرحله‌ی 4: برازش گوسی‌های دوبعدی روی یک تصویر هدف

import math
import numpy as np

def make_target(size=64):
    yy, xx = np.meshgrid(np.arange(size), np.arange(size), indexing="ij")
    img = np.zeros((size, size, 3), dtype=np.float32)
    # دایره قرمز
    mask = (xx - 20) ** 2 + (yy - 20) ** 2 < 10 ** 2
    img[mask] = [1.0, 0.2, 0.2]
    # مربع آبی
    mask = (np.abs(xx - 45) < 8) & (np.abs(yy - 40) < 8)
    img[mask] = [0.2, 0.3, 1.0]
    return torch.from_numpy(img)


target = make_target(64)
model = Splats2D(num_splats=64, image_size=64)
opt = torch.optim.Adam(model.parameters(), lr=0.05)

for step in range(200):
    pred = model((64, 64))
    loss = F.mse_loss(pred, target)
    opt.zero_grad(); loss.backward(); opt.step()
    if step % 40 == 0:
        print(f"step {step:3d}  mse {loss.item():.4f}")

طی 200 گام، 64 گوسی شکل این دو شیء را به خود می‌گیرند. کل فلسفه‌ی کار در همین خلاصه می‌شود: گرادیان کاهشی روی المان‌های هندسی صریح.

مرحله‌ی 5: از دوبعدی به سه‌بعدی

تعمیم مدل به فضای سه‌بعدی از همان حلقه پیروی می‌کند؛ فقط موارد زیر اضافه می‌شوند:

  1. دوران هر گوسی به جای یک زاویه‌ی تک، با کواترنیون تعریف می‌شود.
  2. ماتریس کوواریانس به صورت R S S^T R^T ساخته می‌شود که در آن R از کواترنیون به دست می‌آید و S = diag(exp(log_scale)).
  3. فرایند تصویر کردن (mu, Sigma) -> (mu', Sigma') با استفاده از پارامترهای خارجی دوربین و ماتریس ژاکوبی تصویر پرسپکتیو در نقطه‌ی mu انجام می‌گیرد.
  4. رنگ به یک بسط هارمونیک‌های کروی تبدیل می‌شود؛ سپس مقدار آن در امتداد جهت دید محاسبه خواهد شد.
  5. مرتب‌سازی عمق به جای یک اسکالر یادگرفته‌شده، بر اساس z واقعی در فضای دوربین انجام می‌شود.

تمام پیاده‌سازی‌های عملیاتی (gsplat، inria/gaussian-splatting، nerfstudio) دقیقاً همین منطق را با کرنل‌های تایل‌محور CUDA روی GPU اجرا می‌کنند.

مرحله‌ی 6: محاسبه‌ی هارمونیک‌های کروی

پایه‌های SH تا درجه‌ی 3 دارای 16 جمله به ازای هر کانال هستند. نحوه‌ی محاسبه:

def eval_sh_degree_3(sh_coeffs, dirs):
    """
    sh_coeffs: (..., 16, 3)   last dim is RGB channels
    dirs:      (..., 3)       unit vectors
    returns:   (..., 3)
    """
    C0 = 0.282094791773878
    C1 = 0.488602511902920
    C2 = [1.092548430592079, 1.092548430592079,
          0.315391565252520, 1.092548430592079,
          0.546274215296039]
    x, y, z = dirs[..., 0], dirs[..., 1], dirs[..., 2]
    x2, y2, z2 = x * x, y * y, z * z
    xy, yz, xz = x * y, y * z, x * z

    result = C0 * sh_coeffs[..., 0, :]
    result = result - C1 * y[..., None] * sh_coeffs[..., 1, :]
    result = result + C1 * z[..., None] * sh_coeffs[..., 2, :]
    result = result - C1 * x[..., None] * sh_coeffs[..., 3, :]

    result = result + C2[0] * xy[..., None] * sh_coeffs[..., 4, :]
    result = result + C2[1] * yz[..., None] * sh_coeffs[..., 5, :]
    result = result + C2[2] * (2.0 * z2 - x2 - y2)[..., None] * sh_coeffs[..., 6, :]
    result = result + C2[3] * xz[..., None] * sh_coeffs[..., 7, :]
    result = result + C2[4] * (x2 - y2)[..., None] * sh_coeffs[..., 8, :]

    # degree 3 terms omitted here for brevity; full 16-coefficient version in the code file
    return result

ضرایب یادگرفته‌شده‌ی sh_coeffs، اطلاعات «رنگ در تمام جهات» را برای آن گوسی ذخیره می‌کنند. در زمان رندر، بر اساس جهت دید فعلی محاسبه انجام شده و یک بردار سه‌تایی RGB به دست می‌آید.

استفاده‌ی عملی

برای کارهای واقعی 3DGS، از gsplat (محصول Meta) یا nerfstudio استفاده کنید:

pip install nerfstudio gsplat
ns-download-data example
ns-train splatfacto --data path/to/data

روش splatfacto ابزار آموزش 3DGS در nerfstudio است. اجرای این فرایند برای یک صحنه‌ی معمولی روی یک پردازنده‌ی گرافیکی RTX 4090 حدود 10 تا 30 دقیقه طول می‌کشد.

فرمت‌های خروجی مهم در سال 2026:

  • فایل .ply — ابر گوسی خام (سازگار، بیشترین حجم فایل).
  • فایل .splat — فرمت کوانتیزه‌شده‌ی PlayCanvas / SuperSplat.
  • افزونه‌ی KHR_gaussian_splatting در glTF — استاندارد Khronos با قابلیت جابه‌جایی بین نرم‌افزارهای نمایش (نسخه‌ی ارائه‌شده در فوریه 2026).
  • اسکیمای UsdVolParticleField3DGaussianSplat در OpenUSD — فرمت بومی USD ویژه‌ی پایپ‌لاین‌های (pipeline) NVIDIA Omniverse و Vision Pro.

برای صحنه‌های چهاربعدی و متحرک، مدل‌های 4DGS و Deformable-3DGS همین ساختار را با میانگین‌ها و شفافیت‌های متغیر با زمان توسعه می‌دهند.

تحویل پروژه

این درس خروجی‌های زیر را تولید می‌کند:

  • outputs/prompt-3dgs-capture-planner.md — پرامپتی برای برنامه‌ریزی جلسه‌ی تصویربرداری (تعداد عکس‌ها، مسیر دوربین و نورپردازی) متناسب با نوع صحنه.
  • outputs/skill-3dgs-export-router.md — مهارتی برای انتخاب فرمت خروجی مناسب (.ply / .splat / glTF / USD) بر اساس موتور مقصد یا نرم‌افزار مشاهده‌گر.

تمرین‌ها

  1. (ساده) کد آموزش پاشش دوبعدی بالا را روی یک تصویر ساختگی دیگر اجرا کنید. مقدار num_splats را بین مقادیر [16, 64, 256] تغییر دهید و نمودار MSE را بر حسب گام رسم کنید. نقطه‌ای را که بازدهی دیگر رشد محسوسی ندارد شناسایی کنید.
  2. (متوسط) رسترایزر دوبعدی را طوری گسترش دهید که رنگ‌های RGB هر گوسی از طریق یک هارمونیک درجه‌ی 2 به یک متغیر اسکالر به عنوان «زاویه‌ی دید» وابسته باشند. مدل را روی یک جفت تصویر هدف آموزش دهید و مطمئن شوید که هر دو را بازسازی می‌کند.
  3. (سخت) مخزن nerfstudio را کلون کنید و splatfacto را با استفاده از 20 عکس از هر صحنه‌ای که دارید (میز کار، گیاه، چهره، اتاق) آموزش دهید. از خروجی با فرمت KHR_gaussian_splatting در glTF اکسپورت بگیرید و آن را در یک نمایش‌دهنده باز کنید (مثل GaussianSplats3D در Three.js، SuperSplat، یا Babylon.js نسخه‌ی V9). زمان آموزش، تعداد گوسی‌ها و نرخ فریم بر ثانیه‌ی رندر را گزارش دهید.

اصطلاحات کلیدی

اصطلاح در گفتگوها تعریف دقیق فنی
3DGS «پاشش‌های گوسی» بازنمایی صریح صحنه به شکل میلیون‌ها گوسی سه‌بعدی همراه با موقعیت، دوران، مقیاس، شفافیت و رنگ SH اختصاصی
کوواریانس «شکل گوسی» فرمول Sigma = R S S^T R^T؛ جهت‌گیری و مقیاس ناهمسانگرد یک گوسی
ترکیب آلفا «ترکیب عقب به جلو» همان معادله‌ی رندر حجمی NeRF، این بار روی مجموعه‌ای صریح و تنک
متراکم‌سازی «تکثیر و تقسیم» افزودن تطبیقی گوسی‌های جدید به بخش‌هایی که بازسازی در آن‌ها ضعیف است
هرس کردن «حذف شفافیت‌های پایین» پاک کردن گوسی‌هایی که شفافیت آن‌ها در طول آموزش به نزدیکی صفر رسیده است
هارمونیک‌های کروی «رنگ وابسته به زاویه‌ی دید» پایه‌ی فوریه روی کره؛ ذخیره‌سازی رنگ به عنوان تابعی از جهت دید
Splatfacto «3DGS در nerfstudio» ساده‌ترین مسیر برای آموزش 3DGS در سال 2026
KHR_gaussian_splatting «استاندارد glTF» افزونه‌ی سال 2026 گروه Khronos برای جابه‌جایی 3DGS بین نرم‌افزارهای نمایش و موتورها

برای مطالعه‌ی بیشتر

خودآزمایی

به سؤال‌ها جواب بدهید تا ببینید چقدر از درس در ذهنتان مانده است.

  1. پیش از درسچرا 3D Gaussian Splatting تا سال 2026 تا حد زیادی جایگزین NeRF به عنوان استاندارد پیش‌فرض بازسازی واقع‌گرایانه صحنه در محیط پروداکشن شد؟
  2. پیش از درسیک گوسی سه‌بعدی در صحنه حامل موقعیت، چرخش، مقیاس، شفافیت و چه بازنمایی اضافی دیگری برای مدیریت رنگ وابسته به زاویه دید (مانند بازتاب‌های براق یا specular) است؟
  3. پس از درسدر طول آموزش 3DGS، چگال‌سازی (densification) شامل عملیات‌های «clone» و «split» است. چه عاملی هر یک از این‌ها را فعال می‌کند؟
  4. پس از درسمعادله رنگ برای یک پیکسل در هر دو مدل NeRF و 3DGS به صورت `C = sum_i alpha_i * T_i * c_i` است که در آن `T_i = prod_{j<i}(1 - alpha_j)` می‌باشد. این معادله مشترک چه چیزی را درباره این دو روش نشان می‌دهد؟
  5. پس از درسشما می‌خواهید در سال 2026 یک صحنه 3DGS را در Unreal Engine، Vision Pro، Blender و یک نمایش‌دهنده تحت وب Three.js منتشر کنید. کدام فرمت خروجی مطمئن‌ترین انتخاب است؟

سؤالات متداول

تفاوت اصلی 3D Gaussian Splatting با NeRF چیست؟

مدل NeRF صحنه را در وزن‌های یک شبکه عصبی MLP ذخیره می‌کند و نیاز به پرتوپیمایی پرهزینه دارد؛ اما 3DGS صحنه را به صورت مجموعه‌ای صریح از گوسی‌های سه‌بعدی نگه می‌دارد و مستقیماً روی GPU با سرعت بالا رسترایز می‌شود.

یک گوسی سه‌بعدی چه مشخصاتی را ذخیره می‌کند؟

موقعیت مکانی سه‌بعدی، کواترنیون دوران، بردار مقیاس، مقدار شفافیت (opacity) و ضرایب هارمونیک‌های کروی (SH) برای ثبت رنگ وابسته به زاویه‌ی دید.

نقش فرایندهای متراکم‌سازی (densification) و هرس کردن (pruning) در 3DGS چیست؟

متراکم‌سازی گوسی‌های دارای گرادیان بالا را تکثیر یا تقسیم می‌کند تا جزئیات بهتری پوشش داده شوند؛ در حالی که هرس کردن، گوسی‌های دارای شفافیت بسیار کم را برای کاهش بار محاسباتی حذف می‌کند.

ما رو توی گوگل بیشتر ببین

با افزودن نکست ادمین به «منابع ترجیحی» گوگل، درس‌ها و مطالب ما را در بخش اخبار برتر جستجو بیشتر می‌بینید.