所有文章
教學 · 8 min read

密集植被而不付幀率帳單:一份實用指南

如何用植被填滿場景並保持流暢——實例化、剔除距離、LOD 策略、陰影開銷、過繪製、密度擺放,以及那套用同一台固定相機證明每項最佳化真正見效的效能剖析循環。

Illustration of a row of trees next to a rising frame-rate graph

簡而言之: 密集植被很少單靠三角形數被殺死——它死於上千次 draw call、粗心 alpha 卡片的過繪製,以及沒人記得還開著 的陰影。把力氣按這個順序花:先實例化,次剔除距離,三陰影,四 LOD,五密度擺放——並用同一台固定相機、每次只動一個變數地 驗證每一步,否則你什麼都學不到。本指南逐段配上那個告訴你「這就是你的問題」的剖析器特徵。

密集森林樹冠倒映在靜靜的溪流中 真實的森林「免費」算繪,因為物理是大規模並行的。你的 GPU 能在 60 fps 偽造那份觀感——但前提是你別再打敗引擎為這活兒早就 自帶的機器。

心智模型:五個瓶頸,一個順序

植被效能不是一個問題,是五個,且它們以可預測的次序主導。draw call 先綁住 CPU;剔除距離決定你到底讓 GPU 畫多少;陰影 悄悄把每一個投射它們之物的開銷翻倍;LOD 與過繪製統治逐像素的帳單;密度擺放決定這一切你到底需要多少。亂序去攻,你就會最佳化 一個本不是瓶頸的東西。下面的順序,就是開銷真正咬人的順序。

先實例化,其餘一切在後

一棵樹畫 5000 次,比 5000 棵各自獨立的樹便宜得離譜——兩個引擎都把重複網格批處理為實例化繪製,你的頭一件事 就是別去打敗那台機器。

Unreal 透過 foliage 和層級實例化靜態網格批處理;Unity 透過 GPU 實例化和地形細節。悄悄打破批處理的:

  • 植被被放置為唯一的 actor/物件而非實例;
  • 逐實例的材質變體——用一個材質裡的逐實例資料(顏色、縮放),而非為每種觀感各寫一個材質;
  • 擺放在組織上分散,使引擎無法把簇作為單位剔除。

剖析器的破綻毫不含糊:draw call 隨植株數量而增。若一個森林視角顯示成千上萬次 draw call,先修這個再碰別的——這份清單裡 再往下的一切都救不了你,因為在 GPU 還沒起步之前你就已 CPU 受限。健康的實例化植被,對整個森林視角把 draw call 保持在 低三位數,無論裡面有幾千株植物。

剔除距離是白撿的錢

草不需要在 800 公尺外算繪——設逐類型的剔除距離(地被 30–60 公尺、灌木 100–200 公尺,只有樹木配得上遠距離), 配上淡出範圍以掩蓋彈出。

這是整條管線裡每分鐘價值最高的設定,卻因為預設在那兒又沒人注意,被例行地留在「無限」。理由是知覺性的:地被遠在 100 公尺前就 張不足一個像素——它對最終畫面字面上一無貢獻,卻仍每幀花費頂點、過繪製和陰影工作。遠處覆蓋屬於更便宜的系統:地形材質的 顏色、不透明的 impostor,或者乾脆是塗成正確綠色的地形層遠 LOD。

淡出範圍(抖動或 alpha)掩蓋彈出,讓玩家永遠看不見剔除距離本身。把淡出調到恰好長到隱形、不再更長——過長的淡出意味著在交叉 淡化期間你為同一株植物的兩個表示付了錢。

陰影:帳單裡沉默的那一半

為小地被關掉動態陰影投射,為樹木保留,為灌木按距離限制——草的陰影以近乎零的視覺收益把你的開銷翻倍。

陰影通道裡每一片草葉都從光源視角再畫一遍。在密集場景裡陰影通道常常與基礎通道一樣貴——這意味著草的陰影可能是整份植被 預算裡最大的單項,卻在視覺上與草叢根部一抹簡單的環境變暗無從區分。修復幾乎免費:地被關閉陰影投射,樹木開啟(它們的陰影 做真正的構圖工作),中間者按距離限制。然後在剖析器裡前後對照陰影通道——它通常是實例化之後最大的單項勝利,且只需幾分鐘。

LOD:給輪廓做預算,而非多邊形

好的植被 LOD 鏈保留外形、屠戮內部——用眼睛驗證過渡距離,並把 impostor 之前最後那個網格 LOD 最佳化得最狠,因為 那是每個大遠景裡都在螢幕上的那一個。

沿小徑的森林地面上的蕨類與下層植被 像這樣的地層植物,正是剔除距離與陰影設定回報最大之處——成千上萬個實例,每個在幾十公尺開外幾乎毫無貢獻,每個若投射動態陰影 便開銷翻倍。

英雄樹的一條實用鏈:完整網格 → 內部約 50% 削減(同一輪廓)→ 合併卡片約 15% → 不透明 impostor/billboard。兩條能省真痛的 註記:

  • 即便在帶虛擬化幾何的引擎裡,遠處的 impostor 仍然值得,因為無論三角形怎麼付費,過繪製與陰影都仍是真實開銷。虛擬化 幾何解決三角形數量,而非透明度開銷。
  • 透明是遠距離的敵人。密集的 alpha-tested 卡片恰好在 GPU 最弱之處——中段 LOD——堆起過繪製。近處偏愛網格葉片,遠處偏愛 不透明 impostor;重 alpha 的中段正是幀時間藏身之處。若某一個 LOD 神秘地貴,那幾乎總是透明的那個。

過繪製:你看不見的開銷

過繪製是 GPU 透過層疊的透明表面把同一像素著色多次——植被特有的詛咒,在最終畫面裡不可見,且往往是一個「輕」 場景之所以慢的原因。

多數引擎都有過繪製視覺化模式;打開它,看一片草地。若它發白光,你就是在把每個像素著色五到十次,隨著重疊的 alpha 卡片 層層堆積。緩解手段:更少更大的草葉,而非許多細的;輪廓允許處用不透明幾何;以及對貢獻最少的卡片做激進剔除。過繪製正是 「我的場景很慢但沒什麼看著貴」的經典元兇,因為三角形便宜,而像素被反覆付費。

密度是設計決定,不是滑桿位置

玩家走動與觀看處密,別處疏——沿小徑一條 20 公尺寬的豐富細節帶,以均勻成本的零頭讀作「處處茂盛」。

坡度與高度遮罩自動做了一部分(陡面與遠處台地根本不需要地被),成簇做了其餘——帶空隙的簇比均勻填充算繪更便宜看著更 自然,於是效能上的勝利與美感上的勝利指向同一方向。這裡擺放工具掙回自身價值:用遮罩與逐物種規則刷密度,再直接烘焙為引擎 原生實例,正是一個下午與一週之差。這是Numivo 的散佈所做的核心——而且因為它烘焙為普通 foliage 與實例化 網格,本文的每項技法都原封不動地適用於結果。你與標準最佳化之間沒有外掛執行時;烘焙好的場景就是引擎內容。

效能剖析循環

同一相機、同一視角、每次一個變數——每次改動後測量 GPU 幀時間、draw call、陰影通道與過繪製。

在你最密的遠景裡選一台固定的「預算相機」,在上面每一步前後對統計截圖。紀律之所以要緊,是因為植被最佳化會相互作用:一次 剔除距離改動會改變陰影通道看到多少實例;一次 LOD 改動會改變過繪製;一次密度改動一次性改變它們全部。隨機漫遊產出隨機數字, 以及關於某項改動是否有用的不可證偽的爭論。固定相機產出你能為之辯護的決定。把數字存進一張共享表,趨勢線會講出單次測量講 不出的故事。

值得偷師的現場數字

  • 地被剔除:30–60 公尺 · 灌木:100–200 公尺 · 樹木:視線
  • 一個健康的實例化森林視角的 draw call:低三位數
  • 密集場景裡陰影通道的占比:常達植被開銷的約一半——關掉草的陰影是現存最便宜的大勝利
  • 讀作「處處茂盛」的小徑帶陳設寬度:約 20 公尺
  • 一棵英雄樹的 LOD 數:3 個網格 LOD + 不透明 impostor
  • 草的過繪製目標:在過繪製視圖裡少於約 3×,而非層疊 alpha 卡片那種發白的 8–10×

迷你 FAQ

Nanite / 虛擬化幾何是否讓這一切過時? 它改變哪些條目主導,而非改變紀律。alpha 卡片的過繪製、陰影開銷、逐實例開銷 全都還在,遠處的 impostor 仍然值。請在你的目標硬體上測量,而非假定新技術解決了你那個具體瓶頸——它也許只是把它挪走了, 而非移除了。

為什麼我的場景連低密度也慢? 老嫌疑犯,按序:投射動態陰影的草、打敗批處理的逐變體唯一材質、無限的剔除距離,或者 堆過繪製的 alpha-tested LOD 鏈。每個都有獨特的剖析器特徵——改之前先查,否則你會修錯那個。

對玩法而言多密算「太密」? 戰鬥可讀性在效能之前先給密度封頂:若剪影沒入雜亂,玩家怪遊戲,而非怪陳設。遠景密、競技場 適中,正是同時熬過剖析器與試玩的那套模式。

該烘焙還是保持程序化? 出貨就烘焙——烘焙好的實例誠實地剖析,且不帶執行時依賴地出貨。把程序化設定(遮罩、規則、種子) 留在版本控制裡,好讓你在地形改動後重烘焙,而無需手工重做那份工。

看著密快並不矛盾——它多半是把五件事按正確順序做、並用同一台相機逐一證明的那份紀律。