XGRIDSDocs
  • 简体中文
  • English
  • 繁體中文
  • 日本語
  • Deutsch
  • Español
  • Italiano
  • Français
  • Русский
  • Polski
  • Nederlands
  • 简体中文
  • English
  • 繁體中文
  • 日本語
  • Deutsch
  • Español
  • Italiano
  • Français
  • Русский
  • Polski
  • Nederlands
  • Lixel PortalCam Series

    • PortalCam P1

      • Product Overview
      • Basic Operation
      • Using the LCC Scan App
      • Maintenance and Care
      • FAQ
  • Lixel K Series

    • Lixel K1

      • Product Overview
      • Basic Operation
      • Device Activation and Connection
      • Scanning Workflow
      • Acquire Point Cloud Data with Absolute Coordinate
      • Map Fusion
      • Route Planning Suggestions for Typical Scenes
      • Precautions
      • FAQ
    • Lixel K2

      • Product Overview
      • Basic Operation
      • Device Activation and Connection
      • Scanning Workflow
      • Acquire Point Cloud Data with Absolute Coordinate
      • Map Fusion
      • Route Planning Suggestions for Typical Scenes
      • Precautions
      • FAQ
  • Lixel L Series

    • Lixel L2 Pro

      • Product Overview
      • Basic Operation
      • Device Activation and Connection
      • Scanning Workflow
      • Acquire Point Cloud Data with Absolute Coordinate
      • Measure Point
      • Appendix
      • FAQ
    • Lixel L3

      • Product Overview
      • Basic Device Functions
      • Device Activation and Connection
      • Data Capture
      • Capturing Absolute Coordinates
      • Appendix
  • Accessories

    • Stick Light

      • Installation Guide
      • Basic Operation
      • FAQ
  • Lixel Studio

    • Version and Copyright
    • Installation and Activation
    • Software Interface
    • File Operations
    • Project Processing
    • Tools
    • 2D Drawing
    • Applications
    • Settings
    • Device Connection
    • FAQ
  • Lixel CyberColor

    • LCC Studio

      • Getting Started
      • Version and Updates
      • Download and Installation
      • Interface Overview and Navigation
      • Before Reconstruction
      • Model Reconstruction
      • Single Model Reconstruction
      • Map Fusion
      • Aerial-Ground Fusion
      • Aerial Reconstruction
      • My Models
      • Other Features
      • Settings and Account
      • Converter
      • Video Reconstruction
      • FAQ
    • LCC Scene Editor

      • Version & Updates
      • Account & Login
      • Product Overview & Home
      • Editor Interface
      • Scene Navigation Modes
      • File
      • Settings
      • Edit Operations
      • Window
      • Global Toolbar
      • Assets & Properties
      • Left Toolbar
      • Viewpoints
      • Portal
      • Skybox
      • Annotations
      • Measurement
      • Flythrough
      • Scene Report
      • 3D Layout
      • Mini-Map
      • Preview Mode (Viewer)
      • Help
      • FAQ
      • Spawn Point
    • LCC Model Editor

      • Version and Updates
      • User Guide
      • Overview and Interface
      • File Operations
      • Selectors
      • Editing Models
      • Measurement
      • Color Grading
      • Asset Management
      • Settings and Help
      • FAQ
    • Capture Guide

      • Overview
      • Capture Devices Overview
      • General Capture Principles
      • Indoor Scene Capture
      • Outdoor Scene Capture
      • Large-Scale Capture (Map Fusion)
      • Aerial-Ground Map Fusion Capture
      • Object Capture
      • People Capture
      • Video Reconstruction Capture
      • HD Enhancement
      • Control Points (Lixel P1)
      • FAQ and Troubleshooting
    • LCC Studio Linux

      • Product Overview
      • Architecture Guide
      • Installation and Deployment Guide
      • Container Startup Parameters Guide
      • CodeMeter Offline Licensing Deployment Guide
      • API Reference
      • Appendix - Developer Data Guide
      • Appendix - Error Code List
      • Single-Machine Multi-GPU Cluster Deployment QuickStart
    • Best Practices

      • Merging Multiple Large 3DGS Models
    • Version History
  • Plugin & SDK

    • Unreal

      • Introduction
      • Quick Start - Windows
      • Quick Start - Linux
      • Quick Start - Quest3
      • Editions and Licensing
      • Rendering
      • Tiled Rasterization (Experimental)
      • Visual Settings
      • Normals and Lighting
      • Scene Editing
      • Performance Parameters
      • Performance Guide
      • Third-party and Engine Plugin Integration
      • Proxy Mesh
      • Loading Animation
      • Collision
      • Navigation System Support
      • Single Layer Water Support
      • Localization
      • FAQ
      • Troubleshooting
      • Logging and Diagnostics
      • Contact Us
      • Best Practices

        • Relighting 3DGS with a LixelStudio Mesh
      • API Reference

        • ALCCActorBase
        • ULCCComponentBase
        • ULCCComponent
        • ULCC2Component
        • SOG / SPZ / PLY Actors
        • ALCC2ProxyMesh
        • ALCCClippingVolume
        • ALCCSectionPlane
        • ALCCLoadVolume
        • ULCCUtilLibrary
        • Enums
        • Structs
      • Changelog

        • v3.4.0
        • v3.3.1
        • v3.0.0
        • v2.2.1
        • v1.0.0
        • v0.9.0
        • v0.8.0
        • v0.7.1
        • v0.6.1
        • v0.5.2
        • v0.4.1
        • v0.4.0
        • v0.3.0
        • v0.0.5
        • v0.0.4
        • v0.0.3
        • v0.0.2
        • v0.0.1
    • Unity

      • Unity SDK Introduction
      • Technical Features
      • Development Environment Requirements
      • PC Quick Start Guide
      • Project Settings Optimization Guide
      • Pico 4 Ultra Development Guide
      • Pico 4 Ultra PC Streaming Guide
      • Quest 3 Development Guide
      • Quest 3 PC Streaming Guide
      • OpenXR Development Guide
      • Pico 4 Ultra Business Streaming Guide
      • Glossary
      • FAQ
      • Contact Us
      • Feature Development Guide

        • Multi-Scene Mixed Rendering Development Guide
        • Shadow Receiving Development Guide
        • Real-Time Lighting Development Guide
        • Multi-Camera Rendering Development Guide
        • High-Resolution Image Rendering Development Guide
        • LCC and LCC2 Data Format Compatibility Development Guide
        • Loading Effect Development Guide
        • Mip Rendering Mode Switching Development Guide
        • Edge and Corner Snapping Development Guide
        • Projected Decal Development Guide
        • Video Projected Decal Development Guide
        • Highlight Development Guide
        • Real-Time Clipping Development Guide
        • Color Adjustment Development Guide
        • Getting Scene Mesh Data Development Guide
        • Editor Mode Development Guide
        • Render Performance Parameter Configuration Guide
        • Application and Data Co-packaging Development Guide
        • Collision System Development Guide
        • macOS Development Permission Issue Guide
        • iOS Device Compilation and Packaging Development Guide
      • API Reference

        • LCCManager
        • Renderer
        • Data Types
      • Changelog

        • v2.3.0
        • v2.2.10
        • v2.2.0
        • v2.1.19
        • v2.0.14
    • Web

      • Introduction
      • Rendering Performance Optimization Guide
      • Graphics Configuration
      • FAQ
      • API Reference

        • LCCRender::clearIndexDB
        • LCCRender::dispose
        • LCCRender::load
        • LCCRender::setCamera
        • LCCRender::unload
        • LCCRender::update
        • LCCObject::checkRenderNextFrame
        • LCCObject::clearRenderNextFrame
        • LCCObject::ecef2Prj
        • LCCObject::getBounds
        • LCCObject::getEnvInstancedMesh
        • LCCObject::getInstancedMesh
        • LCCObject::getLodInfos
        • LCCObject::getOriginPosition
        • LCCObject::getProjectionCoordinateSystemInfos
        • LCCObject::hasCollision
        • LCCObject::hasEnvironment
        • LCCObject::hasShcoef
        • LCCObject::intersectsCapsule
        • LCCObject::intersectsRayExt
        • LCCObject::intersectsRayFromOriginExt
        • LCCObject::intersectsSphere
        • LCCObject::lowerToBottom
        • LCCObject::prj2Ecef
        • LCCObject::raiseToTop
        • LCCObject::raycast
        • LCCObject::raycastFromOrigin
        • LCCObject::setAlpha
        • LCCObject::setClipBox
        • LCCObject::setClipPlane
        • LCCObject::setEndLod
        • LCCObject::setLodAutoLevelUp
        • LCCObject::setMaxDistance
        • LCCObject::setMaxNodeSplats
        • LCCObject::setMaxSplats
        • LCCObject::setOriginPosition
        • LCCObject::setPointsColor
        • LCCObject::setRenderState
        • LCCObject::setRotation
        • LCCObject::setScale
        • LCCObject::setSemantic
        • LCCObject::setSemanticColor
        • LCCObject::setSmooth
        • LCCObject::setStartLod
        • LCCObject::setTranslation
        • LCCObject::setVisible
        • LCCObject::togglePointsDisplayMode
        • LCCObject::useEnvironment
        • LCCObject::useShcoef
      • Changelog

        • v0.6.3
        • v0.6.2
        • v0.6.1
        • v0.6.0
        • v0.5.5
        • v0.5.4
        • v0.5.3
        • v0.5.2
        • v0.5.1
        • v0.5.0
        • v0.4.1
        • v0.4.0
        • v0.3.1
        • v0.3.0
        • v0.2.0
    • Lixel OpenAPI

      • Overview
      • Connection & Authentication
      • Message Model & Codec
      • Interface Catalog
      • Real-time Data
      • Project File Access
      • Error Codes
      • Python

        • Quick Start
        • Client Wrapper & Tools
        • FAQ
      • C++

        • Quick Start
        • Client & Examples
        • FAQ

Edge and Corner Snapping Development Guide

The LCC Unity SDK supports edge and corner detection and snap preview on 3DGS surfaces, which can be used in interaction scenarios requiring precise positioning such as measurement, annotation, and placement. The following describes the complete steps for implementing edge/corner detection and snapping.

Note:

The snapping feature (edge/corner detection, snap preview, and raycasting with snapping) is only supported on PC / Mac platforms. Calling the related APIs on mobile / VR platforms has no effect and outputs a warning.

Step 1: Create the scene and GameObjects

Create a brand-new scene in Unity. Unity creates Main Camera and Directional Light by default.

Set up Main Camera

Select Main Camera in the Hierarchy window, and set its properties in the Inspector window as shown below.

Set the Main Camera properties

Set the Main Camera properties

Create LCCManager

Right-click an empty area in the Hierarchy window, select Create Empty from the pop-up menu to create an empty GameObject, name it LCCManager, normalize its Transform, and add the LCCManager script to it via Add Component.

Create the LCCManager GameObject and add the LCCManager script

Create the LCCManager GameObject and add the LCCManager script

Create LCCRenderer

Right-click an empty area in the Hierarchy window, select Create Empty to create an empty GameObject, name it LCCRenderer, and set its Transform to Rotation.x = -90 and Scale.x = -1.

Create LCCRenderer and set its Transform

Create LCCRenderer and set its Transform (Rotation.x = -90, Scale.x = -1)

Note:

The Transform settings of the LCCRenderer GameObject (Rotation.x = -90, Scale.x = -1) align it with the LCC data coordinate system. For details on coordinate system alignment, see "LCC Data Coordinate System" in Unity SDK Introduction.

Step 2: Add a Render Feature

  1. In the Unity menu bar, select File → Project Settings, choose Graphics on the left, and confirm the current Default Render Pipeline Asset. This example uses URP (Universal Render Pipeline Asset).
Confirm the Default Render Pipeline Asset in Graphics settings

Confirm the Default Render Pipeline Asset in Graphics settings

  1. Click that Asset, locate the corresponding asset file in the Project window, and find its associated Renderer (URP_Renderer.asset in this example).

  2. Select that Renderer asset file, click Add Renderer Feature in the Inspector window, and add the Snap Frame Capture Feature.

Add the Snap Frame Capture Feature to the URP Renderer

Add the Snap Frame Capture Feature to the URP Renderer

Step 3: Write a script to enable snapping

Create a new C# script named Snap.cs with the following code:

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;
        // Enable edge/corner detection and snap preview
        m_manager.SetSnapEnabled(true);
        m_manager.SetSnapPreviewEnabled(true);
    }

    private void Update()
    {
        if (!m_loaded) return;
        // Update the snap preview in real time based on the current mouse position
        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);
            }
        }
    }
}

Note:

Edge/corner detection (SetSnapEnabled) and snap preview (SetSnapPreviewEnabled) must be enabled after the LCC scene finishes loading, so both are called in the onComplete callback. Snap preview also needs to be continuously updated via UpdateSnapPreview in Update.

The example above demonstrates the following points:

  • Enable edge and corner detection: m_manager.SetSnapEnabled(true)
  • Enable snap preview: m_manager.SetSnapPreviewEnabled(true)
  • Update snap preview in real time: m_manager.UpdateSnapPreview(Input.mousePosition, m_camera)
  • Raycast at the snap point and create a sphere at the hit point: m_manager.RaycastWithSnap(...); on hit, a red sphere is created at result.hitPos

Step 4: Attach the script and set the data path

  1. Attach the Snap.cs script to the LCCRenderer GameObject in the Hierarchy window.
  2. In the Inspector window, drag the LCCManager GameObject onto the script's Manager property.
  3. Fill in the LCC file path in the script's File Path property.

Step 5: Run

Click the Play button in the Game window to see the edges and corners detected in real time and the preview icon of the snap target. As you move the mouse, the preview icon follows the nearest snap target in real time; right-clicking performs a raycast at the snap point and creates a red sphere.

Edges, corners, and the snap preview icon detected in real time after running

Edges, corners, and the snap preview icon detected in real time after running

FAQ: Disable compatibility mode

If the Unity Console window reports errors and no snap preview icon appears, disable compatibility mode: open the settings panel via Edit → Project Settings → Graphics, select the URP tab, and do not check the checkbox after Render Graph → Compatibility Mode (Render Graph Disabled).

Do not check Render Graph compatibility mode

Do not check Render Graph compatibility mode (Render Graph Disabled)

Key Steps

The key steps for implementing edge/corner detection and snapping:

  1. Make sure the Snap Frame Capture Feature has been added to the URP Renderer.
  2. Make sure edge/corner detection (SetSnapEnabled(true)) and snap preview (SetSnapPreviewEnabled(true)) are enabled in code after the LCC scene finishes loading.
  3. Make sure UpdateSnapPreview is called in real time in Update to update the preview icon.

Snap-related APIs

The LCC Unity SDK provides the following snap-related APIs through LCCManager. They are only supported on PC / Mac platforms — calling them on mobile / VR platforms has no effect and outputs a warning — and they all must be called after the LCC scene finishes loading.

SetSnapEnabled

// Return value: void
public void SetSnapEnabled(bool enable)

Toggles the snapping feature. When enabled, RaycastWithSnap automatically searches for nearby edges/corners to snap to.

ParameterTypeDescription
enableboolWhether to enable snapping

Usage example:

m_manager.SetSnapEnabled(true);

Notes:

  • Disabled by default.
  • Only supported on PC / Mac; calling it on mobile / VR has no effect and outputs a warning.
  • When enabled, GPU resources are allocated (EdgeDetect / CornerDetect / SnapSearch).

SetSnapRadius

// Return value: void
public void SetSnapRadius(float pixels)

Sets the snap search radius. The nearest edge/corner is searched within this pixel range.

ParameterTypeDescription
pixelsfloatSnap search radius (pixels)

Usage example:

m_manager.SetSnapRadius(30f);

Notes:

  • Default is 20 pixels.
  • The larger the value, the wider the search range, but it may snap to unintended targets.
  • Only supported on PC / Mac.

SetEdgeThreshold

// Return value: void
public void SetEdgeThreshold(float threshold)

Sets the Sobel edge detection threshold. The smaller the value, the more edges are detected.

ParameterTypeDescription
thresholdfloatEdge detection threshold

Usage example:

m_manager.SetEdgeThreshold(0.2f);

Notes:

  • Default is 0.3.
  • Recommended range [0.1, 0.8].
  • Too small a value produces a lot of noisy edges.
  • Only supported on PC / Mac.

SetSnapPreviewEnabled

// Return value: void
public void SetSnapPreviewEnabled(bool enable)

Toggles the snap preview feature. When enabled, the nearest snap target indicator is displayed in real time as the mouse moves.

ParameterTypeDescription
enableboolWhether to enable snap preview

Usage example:

m_manager.SetSnapPreviewEnabled(true);

Notes:

  • Requires SetSnapEnabled(true) to be called first.
  • Preview continuously consumes GPU resources (detection every frame).
  • Only supported on PC / Mac.

UpdateSnapPreview

// Return value: void
public void UpdateSnapPreview(Vector2 mousePos, Camera cam)

Updates the snap preview state. Call it as the mouse moves to update the preview indicator position.

ParameterTypeDescription
mousePosVector2Current mouse screen coordinate
camCameraCamera

Usage example:

void Update()
{
    m_manager.UpdateSnapPreview(Input.mousePosition, Camera.main);
}

Notes:

  • Requires SetSnapPreviewEnabled(true) to be called first.
  • It is recommended to call it continuously in Update.
  • Only supported on PC / Mac.

GetSnapPreviewState

// Return value: SnapPreviewState (screenPos is in screen coordinates)
public SnapPreviewState GetSnapPreviewState()

Gets the current snap preview state, including whether there is a snap target, the target type, the target screen position, and the pixel distance to the mouse.

Usage example:

var state = m_manager.GetSnapPreviewState();
if (state.hasTarget)
{
    // state.snapType: Corner / Edge
    // state.screenPos: snap target screen position
    // state.distanceToMouse: pixel distance
}

Notes:

  • Requires SetSnapPreviewEnabled(true) and UpdateSnapPreview to be called first.
  • Returns default(SnapPreviewState) when there is no target.
  • screenPos is a screen coordinate, not a world coordinate; if you need the world coordinate, use RaycastWithSnap to get HitResult.hitPos.
  • Only supported on PC / Mac.

RaycastWithSnap

// Return value: bool (true = hit)
public bool RaycastWithSnap(Vector2 screenPos, Camera cam, out HitResult result)

Raycasting with snapping. It first performs a normal Raycast, then searches for edges/corners near the hit point to snap to.

ParameterTypeDescription
screenPosVector2Screen coordinate
camCameraCamera
resultout HitResultHit result (including snapping information)

Usage example:

if (m_manager.RaycastWithSnap(Input.mousePosition, m_camera, out HitResult hit))
{
    // hit.snapType: Corner / Edge / None
    // hit.hitPos: world position after snapping
    // hit.originalHitPos: original hit point before snapping
}

Notes:

  • Requires SetSnapEnabled(true) to be called first.
  • Snap priority: Corner > Edge > None.
  • This entry point synchronously blocks the main thread (waiting for the GPU readback result); it is recommended to call it only on interaction events (such as clicks), not every frame.
  • In preview mode (SetSnapPreviewEnabled(true)), if a snap target already exists, the preview cache is reused directly without recomputation; otherwise the normal snap flow is used.
  • Only supported on PC / Mac.

Related data structures

SnapType

public enum SnapType { None, Edge, Corner }

Snap target type: none / edge / corner.

SnapPreviewState

public struct SnapPreviewState {
    public bool hasTarget;          // whether there is a snap target
    public SnapType snapType;       // None / Edge / Corner
    public Vector2 screenPos;       // snap target screen position (not world position)
    public float distanceToMouse;   // pixel distance to the mouse position
}

⚠️ screenPos is a screen pixel coordinate, not a world coordinate. If you need the world coordinate, use RaycastWithSnap to get HitResult.hitPos.

HitResult

public struct HitResult {
    public bool isHit;             // whether hit
    public float distance;         // distance
    public Vector3 hitPos;         // hit point world position (field name is hitPos, not position)
    public Vector3 normal;         // hit normal
    public float hitAlpha;         // alpha of the hit ellipsoid
    public float dist2Origin;      // distance to the ray origin
    public float scale;            // ellipsoid scale
    public SnapType snapType;      // snap type (None / Edge / Corner)
    public Vector3 originalHitPos; // original hit point before snapping
}

⚠️ Field naming difference: the field for the hit point world position is hitPos (not position); callers should access it using the actual field name.