用 LixelStudio 網格為 3DGS 重打光
插件支持混合重打光:把 3DGS 與同比例的網格模型結合使用,讓 3DGS 獲得接近網格的光照響應,同時還能產生自陰影。
效果取決於 3DGS 下方那份網格的幾何精度。網格與 3DGS 對齊得越好,光照響應和陰影就越真實。
選哪種網格
LCC Studio 和 LixelStudio 都能生成網格,但用途不同。
| LCC Studio 網格 | LixelStudio 網格 | |
|---|---|---|
| 表面精度 | 較粗糙 | 更貼合真實形狀 |
| 文件體積 | 小 | 大 |
| 適合 | 碰撞檢測 | 重打光 |
用於碰撞時選 LCC Studio 網格就夠了,見碰撞。用於重打光要選 LixelStudio 網格。
LCC Studio 網格:


LixelStudio 網格:


步驟 1:把分塊模型集中到一個文件夾
LixelStudio 導出的網格是分塊的。場景大的時候會得到很多文件夾,每個裏面有一個 .obj 文件和貼圖。導入虛幻引擎前要先合併成一個網格,否則會得到許多獨立的 .obj。
下面用 Blender 完成,其他三維軟件同理。Blender 從官網下載。
Blender 不支持一次性把一批文件夾拖進去,得先把散在各個子文件夾裏的 .obj 提取到同一層。手動拖幾十個文件夾不現實,用一條 PowerShell 命令解決。
進入包含所有子文件夾的根目錄,在地址欄輸入 powershell 後按 Enter,終端會在當前目錄打開。

在文件管理器地址欄輸入 powershell
複製粘貼下面這條命令:
Get-ChildItem -Recurse -File | Move-Item -Destination .
注:命令會把所有子文件夾裏的文件提取到當前目錄,運行前先確認自己在正確的目錄下。比如目錄 A 下有 B 和 C,就要在 A 的地址欄打開 PowerShell,運行後 B 和 C 裏的文件都會被移動到 A。

運行前的目錄結構

粘貼命令後執行
粘貼後按 Enter 運行,需要幾秒。出現新的提示符表示執行完畢。
這時所有內容都被提取出來了,點開幾個子文件夾確認裏面已經清空。

所有 .obj 與貼圖已集中到同一層
步驟 2:在 Blender 中合併為一個文件
按 Ctrl + A 選中所有文件,拖進 Blender。

全選所有文件

拖入 Blender
點擊 Import Wavefront OBJ 導入。為保證朝向正確,把 Up Axis 設為 Z,Forward Axis 設為 X。

Up Axis 設為 Z,Forward Axis 設為 X
這時能看到所有貼片都已導入。

所有貼片已導入
按 A 選中所有貼片,按 Ctrl + J 合併成單個網格。場景大的時候要等一分鐘左右,等它跑完。

合併後得到單個網格
注:不需要整個場景參與重打光時,可以刪掉用不到的部分,能提升虛幻引擎中的性能。
步驟 3:減少渲染調用
這份網格導入虛幻引擎用於重打光時,材質全都用不上。3DGS 負責畫面呈現,代理網格只參與計算,材質留着既沒用又佔資源。
LixelStudio 網格的每張貼圖在虛幻引擎裏都是一次渲染調用。規模大的時候會產生大量渲染調用,直接拿去當代理網格會卡。
在 Collection 裏選中網格,用 Blender 的 Python 控制台查看渲染調用次數。

切換到 Python 控制台
粘貼下面的命令後按 Enter 執行:
obj = bpy.context.object
print("Material slots:", len(obj.data.materials))

輸出的數值就是渲染調用次數
圖中這份網格有 8859 次渲染調用。
要把渲染調用降下來,刪掉所有現有材質,替換為單一材質:
import bpy
# Get the currently selected object in Blender
obj = bpy.context.object
# Make sure a valid Mesh object is selected
if obj is None or obj.type != "MESH":
raise Exception("Please select a Mesh object first.")
# Create a new white clay material
mat = bpy.data.materials.new("M_White_Clay")
mat.use_nodes = True
# Configure the Principled BSDF shader settings
bsdf = mat.node_tree.nodes.get("Principled BSDF")
if bsdf:
bsdf.inputs["Base Color"].default_value = (1, 1, 1, 1) # White color
bsdf.inputs["Roughness"].default_value = 1.0 # Fully rough / matte surface
bsdf.inputs["Metallic"].default_value = 0.0 # Non-metallic material
bsdf.inputs["Alpha"].default_value = 1.0 # Fully opaque
# Remove all existing material slots from the mesh
obj.data.materials.clear()
# Add the single new white material
obj.data.materials.append(mat)
# Assign every face to material slot 0
for poly in obj.data.polygons:
poly.material_index = 0
# Print the result for verification
print("Done")
print("Material slots:", len(obj.data.materials))
print("Used material indices:", len(set(p.material_index for p in obj.data.polygons)))
print("Estimated draw calls:", len(set(p.material_index for p in obj.data.polygons)))
運行後確認渲染調用次數已經降到一次。

渲染調用已降為一次
步驟 4:導入虛幻引擎
把網格導出為 .obj 或 .fbx,導入虛幻引擎。

網格導入虛幻引擎後的效果
接着按代理網格的步驟放置 ProxyMesh Actor,並把法線模式設為 ProxyMesh。
效果不對時見代理網格故障排查。