邊角點吸附開發指南
LCC Unity SDK 支持對 3DGS 表面進行邊緣、角點檢測和吸附預覽,可用於測量、標註、放置等需要精確定位的交互場景。下面介紹實現邊緣/角點檢測及吸附的完整步驟。
說明:
吸附功能(邊緣/角點檢測、吸附預覽、帶吸附的射線檢測)僅在 PC / Mac 平台支持,移動端 / VR 平台調用相關 API 無效並會輸出警告。
步驟 1:創建場景與遊戲對象
在 Unity 中創建一個全新的場景,Unity 默認會創建 Main Camera 和 Directional Light。
設置 Main Camera
在 Hierarchy 窗口中選擇 Main Camera,在 Inspector 窗口中按下圖設置其屬性。

設置 Main Camera 的屬性
創建 LCCManager
在 Hierarchy 窗口空白處單擊鼠標右鍵,在彈出的菜單中選擇 Create Empty,創建一個空遊戲對象,命名為 LCCManager,將其 Transform 歸一,並通過 Add Component 為其添加 LCCManager 腳本。

創建 LCCManager 遊戲對象並添加 LCCManager 腳本
創建 LCCRenderer
在 Hierarchy 窗口空白處單擊鼠標右鍵,選擇 Create Empty,創建一個空遊戲對象,命名為 LCCRenderer,將其 Transform 設置為 Rotation.x = -90、Scale.x = -1。

創建 LCCRenderer 並設置 Transform(Rotation.x = -90、Scale.x = -1)
注意:
LCCRenderer 遊戲對象的 Transform 設置(Rotation.x = -90、Scale.x = -1)是與 LCC 數據座標系的對齊。關於座標系對齊的詳細說明,參見 Unity SDK 簡介 中的「LCC 數據座標系」。
步驟 2:添加 Render Feature
- 在 Unity 菜單欄中選擇 File → Project Settings,在左側選擇 Graphics,確認當前使用的 Default Render Pipeline Asset。本示例為 URP(Universal Render Pipeline Asset)。

在 Graphics 設置中確認 Default Render Pipeline Asset
點擊該 Asset,在 Project 窗口中定位到對應的資源文件,找到與之關聯的 Renderer(本示例為
URP_Renderer.asset)。選中該 Renderer 資源文件,在 Inspector 窗口中點擊 Add Renderer Feature,添加 Snap Frame Capture Feature。

在 URP Renderer 中添加 Snap Frame Capture Feature
步驟 3:編寫腳本開啟吸附功能
新建一個 C# 腳本,命名為 Snap.cs,代碼如下:
using LCCCore;
using UnityEngine;
public class Snap : MonoBehaviour
{
public LCCManager m_manager;
public string m_FilePath;
private LCCCore.Renderer m_renderer;
private bool m_loaded = false;
private Camera m_camera;
void Start()
{
m_camera = Camera.main;
m_manager.SetPlatformType(PlatformType.PC);
Debug.Log("Started ");
m_renderer = m_manager.GetRender(this.transform);
m_renderer.Load(m_FilePath, onProgress, onComplete);
}
private void onProgress(float _progress)
{
Debug.Log($"[LCCRenderer] file load progress: {_progress:P1}");
}
private void onComplete()
{
Debug.Log($"[LCCRenderer] file loaded");
m_loaded = true;
// 開啟邊緣/角點檢測與吸附預覽
m_manager.SetSnapEnabled(true);
m_manager.SetSnapPreviewEnabled(true);
}
private void Update()
{
if (!m_loaded) return;
// 根據當前鼠標位置實時更新吸附預覽
m_manager.UpdateSnapPreview(Input.mousePosition, m_camera);
if (Input.GetMouseButtonDown(1))
{
m_manager.RaycastWithSnap(Input.mousePosition, m_camera, out HitResult result);
if (result.isHit)
{
GameObject sphere = GameObject.CreatePrimitive(PrimitiveType.Sphere);
sphere.transform.position = result.hitPos;
sphere.GetComponent<UnityEngine.Renderer>().material.color = Color.red;
sphere.transform.localScale = new Vector3(0.1f, 0.1f, 0.1f);
}
}
}
}
注意:
邊緣/角點檢測(
SetSnapEnabled)與吸附預覽(SetSnapPreviewEnabled)需要在 LCC 場景加載完成後開啟,因此二者都在onComplete回調中調用。吸附預覽還需要在Update中通過UpdateSnapPreview持續更新。
上述示例演示了以下要點:
- 開啟邊緣、角點檢測:
m_manager.SetSnapEnabled(true) - 開啟吸附預覽:
m_manager.SetSnapPreviewEnabled(true) - 實時更新吸附預覽:
m_manager.UpdateSnapPreview(Input.mousePosition, m_camera) - 在吸附點進行射線檢測並創建碰撞點小球:
m_manager.RaycastWithSnap(...),命中後在result.hitPos處創建紅色小球
步驟 4:掛載腳本並設置數據路徑
- 將
Snap.cs腳本掛載到 Hierarchy 窗口中的 LCCRenderer 遊戲對象上。 - 在 Inspector 窗口中,將 LCCManager 遊戲對象拖動到腳本的 Manager 屬性上。
- 在腳本的 File Path 屬性中填寫 LCC 文件的路徑地址。
步驟 5:運行
在 Game 窗口中點擊 Play 按鈕,即可看到實時檢測到的邊緣、角點以及吸附目標的預覽圖標。移動鼠標時預覽圖標會實時跟隨最近的吸附目標;單擊鼠標右鍵會在吸附點處進行射線檢測並創建一個紅色小球。

運行後實時檢測到的邊緣、角點及吸附預覽圖標
常見問題:關閉兼容模式
如果 Unity Console 窗口報錯且沒有出現吸附預覽圖標,請關閉兼容模式:通過 Edit → Project Settings → Graphics 打開設置面板,選擇 URP 選項卡,不要勾選 Render Graph → Compatibility Mode (Render Graph Disabled) 後的多選框。

不要勾選 Render Graph 兼容模式(Render Graph Disabled)
關鍵步驟
實現邊緣/角點檢測及吸附的關鍵步驟:
- 確保在 URP Renderer 中添加了 Snap Frame Capture Feature 渲染特性。
- 確保在 LCC 場景加載完成後通過代碼開啟了邊緣/角點檢測功能(
SetSnapEnabled(true))和吸附預覽功能(SetSnapPreviewEnabled(true))。 - 確保在
Update中實時調用UpdateSnapPreview更新預覽圖標。
吸附相關 API
LCC Unity SDK 通過 LCCManager 提供了以下吸附相關 API。它們僅在 PC / Mac 平台支持,移動端 / VR 平台調用無效並輸出警告;且都需要在 LCC 場景加載完成後調用。
SetSnapEnabled
// 返回值:void
public void SetSnapEnabled(bool enable)
開關吸附功能。啟用後 RaycastWithSnap 會自動搜索附近的邊緣/角點進行吸附。
| 參數 | 類型 | 說明 |
|---|---|---|
enable | bool | 是否啟用吸附 |
調用示例:
m_manager.SetSnapEnabled(true);
說明:
- 默認關閉。
- 僅 PC / Mac 平台支持,移動端 / VR 調用無效並輸出警告。
- 啟用後會分配 GPU 資源(EdgeDetect / CornerDetect / SnapSearch )。
SetSnapRadius
// 返回值:void
public void SetSnapRadius(float pixels)
設置吸附搜索半徑。在此像素範圍內搜索最近的邊緣/角點。
| 參數 | 類型 | 說明 |
|---|---|---|
pixels | float | 吸附搜索半徑(像素) |
調用示例:
m_manager.SetSnapRadius(30f);
說明:
- 默認 20 像素。
- 值越大搜索範圍越廣,但可能吸附到非預期目標。
- 僅 PC / Mac 平台支持。
SetEdgeThreshold
// 返回值:void
public void SetEdgeThreshold(float threshold)
設置 Sobel 邊緣檢測的閾值。值越小檢測到的邊緣越多。
| 參數 | 類型 | 說明 |
|---|---|---|
threshold | float | 邊緣檢測閾值 |
調用示例:
m_manager.SetEdgeThreshold(0.2f);
說明:
- 默認 0.3。
- 建議取值範圍
[0.1, 0.8]。 - 值過小會產生大量噪聲邊緣。
- 僅 PC / Mac 平台支持。
SetSnapPreviewEnabled
// 返回值:void
public void SetSnapPreviewEnabled(bool enable)
開關吸附預覽功能。啟用後鼠標移動時實時顯示最近的吸附目標指示器。
| 參數 | 類型 | 說明 |
|---|---|---|
enable | bool | 是否啟用吸附預覽 |
調用示例:
m_manager.SetSnapPreviewEnabled(true);
說明:
- 需先調用
SetSnapEnabled(true)。 - 預覽會持續消耗 GPU 資源(每幀檢測)。
- 僅 PC / Mac 平台支持。
UpdateSnapPreview
// 返回值:void
public void UpdateSnapPreview(Vector2 mousePos, Camera cam)
更新吸附預覽狀態。在鼠標移動時調用,更新預覽指示器位置。
| 參數 | 類型 | 說明 |
|---|---|---|
mousePos | Vector2 | 當前鼠標屏幕座標 |
cam | Camera | 相機 |
調用示例:
void Update()
{
m_manager.UpdateSnapPreview(Input.mousePosition, Camera.main);
}
說明:
- 需先調用
SetSnapPreviewEnabled(true)。 - 建議在
Update中持續調用。 - 僅 PC / Mac 平台支持。
GetSnapPreviewState
// 返回值:SnapPreviewState(screenPos 為屏幕座標)
public SnapPreviewState GetSnapPreviewState()
獲取當前吸附預覽狀態,包括是否有吸附目標、目標類型、目標屏幕位置和到鼠標的像素距離。
調用示例:
var state = m_manager.GetSnapPreviewState();
if (state.hasTarget)
{
// state.snapType: Corner / Edge
// state.screenPos: 吸附目標屏幕座標
// state.distanceToMouse: 像素距離
}
說明:
- 需先調用
SetSnapPreviewEnabled(true)和UpdateSnapPreview。 - 無目標時返回
default(SnapPreviewState)。 screenPos是屏幕座標,不是世界座標;需要世界座標時請用RaycastWithSnap取HitResult.hitPos。- 僅 PC / Mac 平台支持。
RaycastWithSnap
// 返回值:bool(true = 命中)
public bool RaycastWithSnap(Vector2 screenPos, Camera cam, out HitResult result)
帶吸附功能的射線檢測。先進行普通 Raycast,再在命中點附近搜索邊緣/角點進行吸附。
| 參數 | 類型 | 說明 |
|---|---|---|
screenPos | Vector2 | 屏幕座標 |
cam | Camera | 相機 |
result | out HitResult | 命中結果(含吸附信息) |
調用示例:
if (m_manager.RaycastWithSnap(Input.mousePosition, m_camera, out HitResult hit))
{
// hit.snapType: Corner / Edge / None
// hit.hitPos: 吸附後的世界座標
// hit.originalHitPos: 吸附前的原始命中點
}
說明:
- 需先調用
SetSnapEnabled(true)。 - 吸附優先級:Corner > Edge > None。
- 本入口同步阻塞主線程(等待 GPU 回讀結果),建議僅在交互事件(如點擊)時調用,不要每幀調用。
- 預覽模式(
SetSnapPreviewEnabled(true))下若已有吸附目標,則直接複用預覽緩存,不再重新計算;否則走正常吸附流程。 - 僅 PC / Mac 平台支持。
相關數據結構
SnapType
public enum SnapType { None, Edge, Corner }
吸附目標類型:無 / 邊緣 / 角點。
SnapPreviewState
public struct SnapPreviewState {
public bool hasTarget; // 是否有吸附目標
public SnapType snapType; // None / Edge / Corner
public Vector2 screenPos; // 吸附目標屏幕座標(非世界座標)
public float distanceToMouse; // 到鼠標位置的像素距離
}
⚠️
screenPos是屏幕像素座標,不是世界座標。需要世界座標時請用RaycastWithSnap取HitResult.hitPos。
HitResult
public struct HitResult {
public bool isHit; // 是否命中
public float distance; // 距離
public Vector3 hitPos; // 命中點世界座標(字段名為 hitPos,非 position)
public Vector3 normal; // 命中法線
public float hitAlpha; // 被擊中橢球的 Alpha
public float dist2Origin; // 到射線源的距離
public float scale; // 橢球 scale
public SnapType snapType; // 吸附類型(None / Edge / Corner)
public Vector3 originalHitPos; // 吸附前原始命中點
}
⚠️ 字段命名差異:命中點世界座標的字段是
hitPos(而非position),調用方代碼請按實際字段名訪問。