Download docs/presentation/figures/compose.py from kimjunhan/vkgs-sim: direct link, hf CLI and curl.
- Browser
- Download file 15.3 kB
-
https://huggingface.co/kimjunhan/vkgs-sim/resolve/main/docs/presentation/figures/compose.py
- Command line
-
hf download hf://kimjunhan/vkgs-sim/docs/presentation/figures/compose.py
-
curl -L -o compose.py https://huggingface.co/kimjunhan/vkgs-sim/resolve/main/docs/presentation/figures/compose.py
15.3 kB
| """๋ ผ๋ฌธ์ ์ํคํ ์ฒ ๋์ ๋ ์ฅ โ make_panels.py ์ ์ค์ ๋ฐ์ดํฐ ํจ๋์ ํฉ์น๋ค. | |
| fig_viewpoint_model.png : ๋ฉํฐ๋ทฐ ์์ ๋ณํ ๋ชจ๋ธ (๊ตฌ๊ฐ๋ณ 3DGS ํ์ต โ ๋ฆฌ๊ทธ ๋ณํ ๋ ๋) | |
| fig_engine_pipeline.png : Vulkan ์๋ฎฌ๋ ์ด์ ์์ง (CPU ์๋ฎฌ๋ ์ด์ ๋ฃจํ + GPU ๋ ๋ ๊ทธ๋ํ) | |
| ์ฐธ๊ณ ํ ๋์ ํ์: 3DGS (Kerbl 2023) ์ต์ ํ ํ์ดํ๋ผ์ธ, HUGSIM ยท OmniRe ๊ฐ์๋ โ ๋จ๊ณ๋ง๋ค ์ค์ ๋ฐ์ดํฐ ๊ทธ๋ฆผ, ๋ฐ์ดํฐ ํ๋ฆ ํ์ดํ, | |
| gradient ๋๋๋ฆผ ํ์ดํ. | |
| """ | |
| import json | |
| import os | |
| import sys | |
| from pathlib import Path | |
| import matplotlib | |
| matplotlib.use("Agg") | |
| import matplotlib.pyplot as plt # noqa: E402 | |
| from matplotlib.patches import Circle, FancyArrowPatch, FancyBboxPatch, Polygon, Rectangle # noqa: E402 | |
| from PIL import Image # noqa: E402 | |
| P = Path(sys.argv[1]) # ํจ๋ | |
| OUT = Path(sys.argv[2]) | |
| EXTRA = Path(sys.argv[3]) # sensors_sim.png, drive_6cam_still.jpg ๊ฐ ์๋ ๊ณณ | |
| ROOT = Path(__file__).resolve().parents[3] | |
| plt.rcParams["font.family"] = ["NanumBarunGothic", "DejaVu Sans"] # ์์ ๊ธฐํธ(ร, แต, ์๋์ฒจ์, โ)๋ DejaVu ๋ก | |
| plt.rcParams["axes.unicode_minus"] = False | |
| NAVY, BLUE, LIGHT, PALE, GRAY, ORANGE, GREEN = "#1F3B70", "#4472C4", "#DCE6F4", "#F4F7FB", "#404040", "#ED7D31", "#5B9B4C" | |
| class Canvas: | |
| def __init__(self, w, h): | |
| self.W, self.H = w, h | |
| self.fig = plt.figure(figsize=(w, h), facecolor="white") | |
| def ax(self, x, y, w, h): # ์์ชฝ ๊ธฐ์ค (y = ์์์ inch) | |
| a = self.fig.add_axes([x / self.W, 1 - (y + h) / self.H, w / self.W, h / self.H]) | |
| a.axis("off") | |
| return a | |
| def img(self, path, x, y, w, h, border=NAVY, lw=1.2, title=None, tsize=11, crop=None): | |
| im = Image.open(path).convert("RGB") | |
| if crop: | |
| im = im.crop(crop) | |
| a = self.ax(x, y, w, h) | |
| a.imshow(im, aspect="auto") | |
| a.set_xlim(0, im.width) | |
| a.set_ylim(im.height, 0) | |
| if border: | |
| self.rect(x, y, w, h, fc="none", ec=border, lw=lw, r=0.0) | |
| if title: | |
| self.text(x + w / 2, y - 0.12, title, size=tsize, bold=True, color=NAVY) | |
| return a | |
| def _fig_xy(self, x, y): | |
| return x / self.W, 1 - y / self.H | |
| def rect(self, x, y, w, h, fc=PALE, ec=LIGHT, lw=1.0, r=0.08, ls="-", z=0): | |
| bx = FancyBboxPatch(self._fig_xy(x, y + h), w / self.W, h / self.H, | |
| boxstyle=f"round,pad=0,rounding_size={r / self.W}" if r else "square,pad=0", | |
| transform=self.fig.transFigure, fc=fc, ec=ec, lw=lw, ls=ls, zorder=z) | |
| self.fig.add_artist(bx) | |
| return bx | |
| def text(self, x, y, s, size=11, bold=False, color=GRAY, ha="center", va="center", style="normal", z=8): | |
| self.fig.text(*self._fig_xy(x, y), s, fontsize=size, fontweight="bold" if bold else "normal", color=color, | |
| ha=ha, va=va, fontstyle=style, zorder=z) | |
| def arrow(self, x0, y0, x1, y1, color=BLUE, lw=2.2, ls="-", rad=0.0, head=14): | |
| a = FancyArrowPatch(self._fig_xy(x0, y0), self._fig_xy(x1, y1), transform=self.fig.transFigure, | |
| arrowstyle=f"-|>,head_length={head / 20},head_width={head / 34}", color=color, lw=lw, | |
| ls=ls, connectionstyle=f"arc3,rad={rad}", mutation_scale=10, zorder=5) | |
| self.fig.add_artist(a) | |
| def chip(self, x, y, s, fc=NAVY, color="white", size=10, w=None, h=0.3): | |
| w = w or (0.085 * len(s) * size / 10 + 0.22) | |
| self.rect(x - w / 2, y - h / 2, w, h, fc=fc, ec="none", r=0.12, z=6) | |
| self.text(x, y, s, size=size, bold=True, color=color) | |
| def save(self, path): | |
| self.fig.savefig(path, dpi=220, facecolor="white") | |
| plt.close(self.fig) | |
| def split(path, h_in, cut_in): | |
| """(a) ยท (b) ๋ ๋ฅผ ๋ฐ๋ก ์ ์ฅ โ ์ฌ๋ผ์ด๋์์ ํฌ๊ฒ ๋ณด์ด๊ฒ.""" | |
| im = Image.open(path) | |
| y = int(im.height * cut_in / h_in) | |
| im.crop((0, 0, im.width, y)).save(str(path).replace(".png", "_a.png")) | |
| im.crop((0, y, im.width, im.height)).save(str(path).replace(".png", "_b.png")) | |
| def stack(c, paths, x, y, w, h, dx=0.16, dy=0.16): | |
| """๊ฒน์น ์ฌ์ง ๋ฌถ์ (๋ฉํฐ๋ทฐ ์ ๋ ฅ).""" | |
| for i, p in enumerate(paths): | |
| c.img(p, x + i * dx, y + i * dy, w, h, border="white", lw=1.5) | |
| c.rect(x + i * dx, y + i * dy, w, h, fc="none", ec=NAVY, lw=0.8, r=0) | |
| # ================================================================== ๊ทธ๋ฆผ 1: ๋ฉํฐ๋ทฐ ์์ ๋ณํ ๋ชจ๋ธ | |
| c = Canvas(16, 8.6) | |
| c.text(0.25, 0.3, "(a) ๊ตฌ๊ฐ๋ณ 3DGS ์ฅ๋ฉด ํ์ต โ CUDA ยท gsplat", size=15, bold=True, color=NAVY, ha="left") | |
| c.rect(0.15, 0.5, 15.7, 4.55, fc="#FAFBFD", ec=LIGHT, lw=1.2, r=0.12) | |
| # ์ ๋ ฅ | |
| stack(c, [P / "gt_CAM_FRONT_LEFT.jpg", P / "gt_CAM_FRONT_RIGHT.jpg", P / "gt_CAM_FRONT.jpg"], 0.35, 0.95, 2.2, 1.24) | |
| c.text(1.5, 2.65, "๋ฉํฐ๋ทฐ ์ฌ์ง (6์บ , 800ร450)", size=11, bold=True, color=NAVY) | |
| c.img(P / "lidar_init.png", 0.35, 2.95, 2.55, 1.43) | |
| c.text(1.62, 4.55, "์ ์ ๋ผ์ด๋ค ๋์ (์ฝ 400 sweep)", size=11, bold=True, color=NAVY) | |
| c.text(1.62, 4.82, "์ฐจ๋ ยท ์ฌ๋ ๋ฐ์ค ์ ์ ์ ๊ฑฐ", size=9.5, color=GRAY) | |
| c.arrow(2.95, 3.65, 3.45, 2.7, color=GRAY, lw=1.6) | |
| c.chip(3.0, 3.1, "์ด๊ธฐํ", fc=GRAY, size=9) | |
| # 3D ๊ฐ์ฐ์์ | |
| c.img(P / "gaussians_3d.png", 3.5, 1.05, 3.0, 1.69, title="3D ๊ฐ์ฐ์์ ์ฅ๋ฉด G") | |
| c.text(5.0, 3.0, "G = { ฮผ, ฮฃ = RSSแตRแต, ฮฑ, SH (3์ฐจ) } ร โค 200๋ง", size=10, color=GRAY) | |
| c.text(5.0, 3.3, "MCMC: ๋ฎ์ ฮฑ ์ฌ๋ฐฐ์น + ์์น ์ก์", size=10, color=GRAY) | |
| c.arrow(6.55, 1.9, 7.25, 1.9) | |
| c.chip(6.9, 1.6, r"w2cยท$\Delta$, K", fc=BLUE, size=8.5, w=0.95) | |
| # ๋ฏธ๋ถ ๋์คํฐ๋ผ์ด์ | |
| c.img(P / "splats_tiles.png", 7.3, 1.05, 3.0, 1.69, title="๋ฏธ๋ถ ๋์คํฐ๋ผ์ด์ ") | |
| c.text(8.8, 3.0, "ํฌ์ ฮฃโฒ = J W ฮฃ Wแต Jแต", size=10, color=GRAY) | |
| c.text(8.8, 3.3, "16ร16 ํ์ผ ๊น์ด ์ ๋ ฌ โ ฮฑ ๋ธ๋ ๋ฉ", size=10, color=GRAY) | |
| c.text(8.8, 3.6, "C = ฮฃ cแตข ฮฑแตข ฮ (1 โ ฮฑโฑผ)", size=10, color=GRAY) | |
| c.arrow(10.35, 1.9, 10.85, 1.9) | |
| # ๋ ๋ ์ถ๋ ฅ | |
| c.img(P / "render_front.jpg", 10.9, 0.95, 2.1, 1.18, title="๋ ๋ ร + (1โฮฑ)ยทS(d)") | |
| c.img(P / "render_depth.png", 10.9, 2.45, 2.1, 1.18) | |
| c.text(11.95, 3.83, "๊ธฐ๋ ๊น์ด D", size=10.5, bold=True, color=NAVY) | |
| c.arrow(13.05, 1.55, 13.45, 1.55) | |
| c.arrow(13.05, 3.05, 13.45, 3.05) | |
| # ๊ฐ๋ ์ ํธ + ์์ค | |
| c.img(P / "masks.png", 13.5, 0.95, 2.1, 1.18, title="์ค์ ์ฌ์ง ยท ๊ฐ๋ฆผ ๋ง์คํฌ") | |
| c.img(P / "lidar_depth.png", 13.5, 2.45, 2.1, 1.18) | |
| c.text(14.55, 3.83, "๋ผ์ด๋ค ๊น์ด D_lidar", size=10.5, bold=True, color=NAVY) | |
| c.rect(9.0, 4.15, 6.65, 0.62, fc=NAVY, ec="none", r=0.1) | |
| c.text(12.32, 4.46, "L = 0.8ยทL1 + 0.2ยทD-SSIM + 0.1ยทL_depth + 0.05ยท(L_sky + L_surf) + 0.01ยท(แพฑ + sฬ)", size=10.5, bold=True, color="white") | |
| # gradient ๋๋๋ฆผ | |
| c.arrow(9.0, 4.46, 5.0, 3.55, color=ORANGE, lw=2.2, ls="--", rad=-0.08) | |
| c.text(6.7, 4.55, r"$\nabla$L (Adam) โ G ยท $\Delta$ (์นด๋ฉ๋ผ๋ณ SE3) ยท ์ ์ํ ยท ํ๋ ํ๋ธ๋งต", size=10.5, bold=True, color=ORANGE) | |
| c.text(14.55, 4.95, "๋นจ๊ฐ: ์ฐจ๋ยท์ฌ๋ (์์ค ์ ์ธ) ํ๋: ํ๋ (ฮฑ โ 0)", size=9, color=GRAY) | |
| # (b) ์์ ๋ณํ ๋ ๋ | |
| y0 = 5.35 | |
| c.text(0.25, y0, "(b) ๋ฉํฐ๋ทฐ ์์ ๋ณํ ๋ ๋ โ Vulkan ์คํ์คํฌ๋ฆฐ", size=15, bold=True, color=NAVY, ha="left") | |
| c.rect(0.15, y0 + 0.2, 15.7, 3.15, fc="#FFF9F4", ec="#F6D3B8", lw=1.2, r=0.12) | |
| c.img(P / "rig_transform.png", 0.45, y0 + 0.5, 2.25, 2.46, border=None) | |
| c.text(1.57, y0 + 3.08, "๋ฆฌ๊ทธ ๋ณํ T (6์บ ๊ณตํต)", size=11, bold=True, color=NAVY) | |
| c.text(3.75, y0 + 1.25, "Rโฒ = Rz(yaw)ยทRยทRx(โpitch)ยทRz(roll)", size=10, color=GRAY) | |
| c.text(3.75, y0 + 1.55, "tโฒ = t + shift (cam โ ego)", size=10, color=GRAY) | |
| c.text(3.75, y0 + 1.85, "์์ฐจ ๊ถค์ ยท ์๊ฐ์ ๊ทธ๋๋ก", size=10, color=GRAY) | |
| c.arrow(2.75, y0 + 2.2, 4.6, y0 + 2.2, color=ORANGE) | |
| c.img(P / "segments_bev.png", 4.7, y0 + 0.45, 2.3, 2.3, border=None) | |
| c.text(5.85, y0 + 3.0, "ํ๋ ์๋ง๋ค ๋ด๋น ๊ตฌ๊ฐ ๋ชจ๋ธ", size=11, bold=True, color=NAVY) | |
| c.arrow(7.05, y0 + 1.6, 7.55, y0 + 1.6, color=ORANGE) | |
| lay = [["CAM_FRONT_LEFT", "CAM_FRONT", "CAM_FRONT_RIGHT"], ["CAM_BACK_RIGHT", "CAM_BACK", "CAM_BACK_LEFT"]] | |
| for r, row in enumerate(lay): | |
| for k, cam in enumerate(row): | |
| c.img(P / f"render_{cam}.jpg", 7.6 + k * 1.22, y0 + 0.55 + r * 0.7, 1.18, 0.66, border="white", lw=0.5) | |
| c.text(9.4, y0 + 2.15, "6์บ ๋์ ๋ ๋ (์ ๋ณด์ ์์ = ํ๊ท ์นด๋ฉ๋ผ ์)", size=10.5, bold=True, color=NAVY) | |
| c.arrow(11.3, y0 + 1.25, 11.8, y0 + 1.25, color=ORANGE) | |
| # ๋ณํ 9์ข (๊ฐ์ ์ฌ ยท ์ ์นด๋ฉ๋ผ) | |
| var = ["left_1m", "left_0.5m", "right_0.5m", "right_1m", "high_0.4m", "low_0.3m", "pitch_down_3", "yaw_left_4", "yaw_right_4"] | |
| meta = json.load(open(ROOT / "outputs/aug/map/scene-0402/left_1m/meta.json")) | |
| fs = [s for s in meta["samples"] if s["cam"] == "CAM_FRONT"] | |
| smp = fs[len(fs) * 3 // 8] | |
| name = os.path.basename(smp["original_filename"]) | |
| for i, v in enumerate(var): | |
| r, k = divmod(i, 3) | |
| c.img(ROOT / f"outputs/aug/map/scene-0402/{v}/CAM_FRONT/{name}", 11.9 + k * 1.3, y0 + 0.42 + r * 0.8, 1.26, 0.71, border="white", lw=0.5) | |
| c.text(11.9 + k * 1.3 + 0.63, y0 + 0.42 + r * 0.8 + 0.62, v, size=7.5, bold=True, color="white") | |
| c.text(13.85, y0 + 2.92, "์ ์์ 6์บ ร 9์ข + meta.json (์ calibrated_sensor)", size=10.5, bold=True, color=NAVY) | |
| c.save(OUT / "fig_viewpoint_model.png") | |
| split(OUT / "fig_viewpoint_model.png", 8.6, 5.15) | |
| # ================================================================== ๊ทธ๋ฆผ 2: Vulkan ์๋ฎฌ๋ ์ด์ ์์ง | |
| c = Canvas(16, 8.45) | |
| c.text(0.25, 0.3, "(a) ์๋ฎฌ๋ ์ด์ ๋ฃจํ โ CPU, ๋งค ํ๋ ์ (closed-loop)", size=15, bold=True, color=NAVY, ha="left") | |
| c.rect(0.15, 0.5, 15.7, 3.25, fc="#FAFBFD", ec=LIGHT, lw=1.2, r=0.12) | |
| xs = [0.45, 3.0, 5.55, 8.1, 10.65, 13.2] | |
| yt, bw, bh = 0.95, 2.2, 1.6 | |
| titles = ["โ ์ ์ด ์ ๋ ฅ", "โก ์์ฐจ ๋์ญํ", "โข ์ถฉ๋ ํ์ ", "โฃ ๊ตฌ๊ฐ ์คํธ๋ฆฌ๋ฐ", "โค ์ผ์ ๋ ์ด์บ์คํธ", "โฅ ๊ธฐ๋ก ยท ๊ด์ธก"] | |
| subs = ["ํค๋ณด๋ ยท ์คํฌ๋ฆฝํธ (50 ms)\nVLA ๊ฐ ๋ค์ด์ฌ ์๋ฆฌ", "ํค๋ค๋งํฑ ์์ ๊ฑฐ ๋ชจ๋ธ\n10 ms ํ์ ์คํ ", "์ฅ์ ๋ฌผ ๊ฒฉ์ 0.2 m ยท ์ฐ์\n์ค์นจ 2์ ยท ํ์ถ ํ์ ", | |
| "๊ฐ๊น์ด ๋ด๋น ๊ถค์ ยท 3 m ํ์คํ ๋ฆฌ์์ค\n์ด์ 3๊ตฌ๊ฐ ๋น๋๊ธฐ ๋ก๋", "๋ ธ๋ฉด ์ ์ฐฉ โ ๋ผ์ด๋ค 32ch ยท ๋ ์ด๋ 5๋\n๋ณต์ ์๋ DDA (4 ms)", "drive_log.csv ยท 6์บ PNG\n๋ผ์ด๋ค .bin ยท ๋ ์ด๋ .txt"] | |
| for i, x in enumerate(xs): | |
| c.rect(x, yt, bw, bh, fc="white", ec=LIGHT, lw=1.0, r=0.08) | |
| c.text(x + bw / 2, yt + bh + 0.22, titles[i], size=11.5, bold=True, color=NAVY) | |
| c.text(x + bw / 2, yt + bh + 0.62, subs[i], size=9, color=GRAY) | |
| if i < 5: | |
| c.arrow(x + bw + 0.03, yt + bh / 2, xs[i + 1] - 0.03, yt + bh / 2, lw=2) | |
| # โ ์ด์ ๋ ์์ด์ฝ | |
| a = c.ax(xs[0], yt, bw, bh) | |
| a.set_xlim(-1.4, 1.4) | |
| a.set_ylim(-1.0, 1.0) | |
| a.set_aspect("equal") | |
| a.add_patch(Circle((0, 0), 0.75, fill=False, lw=6, color=NAVY)) | |
| a.add_patch(Circle((0, 0), 0.18, color=NAVY)) | |
| for ang in (90, 210, 330): | |
| import numpy as np | |
| a.plot([0, 0.72 * np.cos(np.radians(ang))], [0, 0.72 * np.sin(np.radians(ang))], color=NAVY, lw=5) | |
| a.text(0, -0.93, "throttle ยท brake ยท steer", ha="center", fontsize=8.5, color=GRAY) | |
| # โก ์์ ๊ฑฐ ๋ชจ๋ธ ๊ทธ๋ฆผ | |
| a = c.ax(xs[1], yt, bw, bh) | |
| a.set_xlim(-1.6, 1.6) | |
| a.set_ylim(-1.15, 1.15) | |
| a.set_aspect("equal") | |
| a.add_patch(Rectangle((-0.45, -0.95), 0.9, 1.9, fc=LIGHT, ec=NAVY, lw=1.5)) | |
| for wx, wy, rot in ((-0.45, -0.6, 0), (0.45, -0.6, 0), (-0.45, 0.6, 18), (0.45, 0.6, 18)): | |
| t = matplotlib.transforms.Affine2D().rotate_deg_around(wx, wy, rot) + a.transData | |
| a.add_patch(Rectangle((wx - 0.08, wy - 0.22), 0.16, 0.44, fc=NAVY, ec="none", transform=t)) | |
| a.plot([0, 0], [-0.6, 0.6], color=ORANGE, lw=2) | |
| a.annotate("", xy=(0.55, 1.05), xytext=(0, 0.6), arrowprops=dict(arrowstyle="->", color=ORANGE, lw=1.8)) | |
| a.text(0.75, 0.95, "ฮด", fontsize=13, color=ORANGE, fontweight="bold") | |
| a.text(0.12, 0.0, "L", fontsize=12, color=ORANGE, fontweight="bold") | |
| a.text(-1.5, -1.1, "แบaw = vยทtan ฮด / L", fontsize=9, color=GRAY) | |
| c.img(P / "obstacles_crop.png", xs[2] + 0.3, yt + 0.02, 1.6, 1.56, border=None) | |
| c.img(P / "segments_bev.png", xs[3] + 0.3, yt + 0.02, 1.6, 1.56, border=None) | |
| c.img(EXTRA / "sensors_sim.png", xs[4] + 0.05, yt + 0.03, 2.1, 1.54, border=None) | |
| c.img(P / "drive_log.png", xs[5] + 0.05, yt + 0.2, 2.1, 1.25, border=None) | |
| c.arrow(xs[5] + bw / 2, yt - 0.02, xs[0] + bw / 2, yt - 0.02, color=ORANGE, lw=2, ls="--", rad=0.06) | |
| c.text(7.6, 0.72, "๋ค์ ํ๋ ์์ ๊ด์ธก โ ๋ค์ โ (๋ชจ๋ธ์ ์ ์ด๊ฐ ๋ค์ ๊ด์ธก์ ๋ฐ๊พผ๋ค)", size=10, bold=True, color=ORANGE) | |
| # (b) GPU ๋ ๋ ๊ทธ๋ํ | |
| y0 = 4.05 | |
| c.text(0.25, y0, "(b) ๋ ๋ ๊ทธ๋ํ โ GPU, Vulkan (configs/render_graph.json, ๋ฐฐ๋ฆฌ์ด ์๋)", size=15, bold=True, color=NAVY, ha="left") | |
| c.rect(0.15, y0 + 0.2, 15.7, 3.95, fc="#F7F9FD", ec=LIGHT, lw=1.2, r=0.12) | |
| c.arrow(13.2, 3.8, 13.2, y0 + 0.62, color=GRAY, lw=1.8) | |
| c.text(13.05, y0 + 0.42, "CPU โ GPU: ์นด๋ฉ๋ผ UBO ยท ๋์ ์ (์ผ์ ์ ยท ์์ฐจ ๋ฐ์ค) ยท ๊ตฌ๊ฐ ๊ต์ฒด", size=9.5, color=GRAY, ha="right") | |
| bufs = [("gaussians", P / "gaussians_3d.png", "๊ฐ์ฐ์์ SSBO\n(๊ตฌ๊ฐ ๋ชจ๋ธ, โค 200๋ง)"), | |
| ("splats ยท keys", P / "splats.png", "ํ๋ฉด ํ์ ยท SH ์\n๋ณด์ด๋ ๊ฒ๋ง ์์ถ"), | |
| ("keys (์ ๋ ฌ)", P / "splats_sorted.png", "๊น์ด ์์\n(์ = ์ ๋ ฌ ์์)"), | |
| ("background", P / "sky_panorama.jpg", "ํ์ต ํ๋ ํ๋ธ๋งต\nยท IBL"), | |
| ("color ยท depth_acc", P / "render_front.jpg", "RGBA16F ์\n+ rg32f ๊ฑฐ๋ฆฌ ๋์ "), | |
| ("post โ ํ๋ฉด", EXTRA / "drive_6cam_still.jpg", "6์บ ยท 3์ธ์นญ ยท BEV\nPNG ์ฐ๊ธฐ ์ค๋ ๋")] | |
| passes = [("preprocess", "compute", "2.0 ms"), ("sort", "radix 8bitร4", "0.44 ms"), ("background", "raster", ""), | |
| ("scene", "raster (๊ฐ์ )", "4.4 ms"), ("weather ยท fxaa", "compute", "")] | |
| bx0, bw2, bh2, gap = 0.35, 1.8, 1.02, 0.92 | |
| for i, (nm, path, sub) in enumerate(bufs): | |
| x = bx0 + i * (bw2 + gap) | |
| c.img(path, x, y0 + 0.95, bw2, bh2, title=nm, tsize=10.5) | |
| c.text(x + bw2 / 2, y0 + 2.35, sub, size=9, color=GRAY) | |
| if i == 4: | |
| c.img(P / "render_depth.png", x, y0 + 2.75, bw2, bh2) | |
| c.text(x + bw2 / 2, y0 + 3.95, "depth_acc (rg32f ๊ฑฐ๋ฆฌ)", size=8.5, color=GRAY) | |
| if i < 5: | |
| pn, kind, tms = passes[i] | |
| cx = x + bw2 + gap / 2 | |
| c.arrow(x + bw2 + 0.04, y0 + 1.5, x + bw2 + gap - 0.04, y0 + 1.5, color=NAVY, lw=2) | |
| c.chip(cx, y0 + 1.2, pn, fc=NAVY, size=8, w=gap + 0.06, h=0.26) | |
| c.text(cx, y0 + 1.85, kind, size=8, bold=True, color=ORANGE) | |
| if tms: | |
| c.text(cx, y0 + 2.07, tms, size=8, color=GRAY) | |
| c.rect(0.4, y0 + 2.85, 9.9, 1.1, fc="white", ec=LIGHT, lw=1, r=0.08) | |
| c.text(0.6, y0 + 3.1, "bindless โ ์ ฐ์ด๋๊ฐ ์ฌ๋กฏ ๋ฒํธ๋ก SSBO ยท ์ด๋ฏธ์ง๋ฅผ ๊ณ ๋ฅธ๋ค (์ ํจ์ค์ ๋์คํฌ๋ฆฝํฐ ์ฝ๋ ๋ถํ์)", size=9.5, color=GRAY, ha="left") | |
| c.text(0.6, y0 + 3.4, "๋ ๋ ๊ทธ๋ํ โ ํจ์ค๋ง๋ค uses (์์ ยท ์ฉ๋) ์ ์ธ โ ๋ฐฐ๋ฆฌ์ด ยท ๋ ์ด์์ ์ ํ ์๋ ์ฝ์ ", size=9.5, color=GRAY, ha="left") | |
| c.text(0.6, y0 + 3.7, "์ ฐ์ด๋ ๊ทธ๋ํ โ ํ์ฒ๋ฆฌ ๋ ธ๋ (JSON) โ GLSL ์์ฑ ยท ๋ฆฌํ๋ ์ ยท Tracy ํจ์ค๋ณ GPU ์๊ฐ", size=9.5, color=GRAY, ha="left") | |
| c.save(OUT / "fig_engine_pipeline.png") | |
| split(OUT / "fig_engine_pipeline.png", 8.45, 3.79) | |
| print("saved", OUT) | |