Add light shape wireframe display in viewport

Draw a type-appropriate wireframe gizmo for every UsdLux light in the stage,
mirroring the existing camera-wireframe overlay (dedicated VAO/VBO reusing the
bbox shader, drawn on top with depth-test off).

Shapes, built in the light's local space and pushed through its local-to-world
transform:
  - SphereLight   3 orthogonal circles (radius); axis-cross when treatAsPoint
  - RectLight     width x height rectangle + emission direction line
  - DiskLight     circle + direction line
  - CylinderLight two end-cap circles + connectors (radius/length)
  - DistantLight  sun disc + parallel rays
  - DomeLight     3 large display-scaled circles

Selected lights draw accent orange, others warm yellow.

Verified by creating a SphereLight (3-circle sphere) and a RectLight
(rectangle) in-app: distinct shapes, correct selected/deselected colours,
gizmos visible over geometry.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
2026-06-22 07:56:47 +08:00
parent a24eff04bd
commit 2649fe814c
3 changed files with 247 additions and 0 deletions
+24
View File
@@ -108,6 +108,16 @@ public:
const pxr::GfMatrix4d& viewProjMatrix,
double viewportCameraDist);
/// Draw wireframe gizmos for all UsdLux light prims in the stage.
/// The shape reflects each light's type (sphere/rect/disk/distant/dome/
/// cylinder); selected lights get an accent colour. viewportCameraDist
/// scales direction lines and point/distant/dome markers.
void DrawLightWireframes(
pxr::UsdStageRefPtr stage,
const pxr::SdfPathVector& selectedPaths,
const pxr::GfMatrix4d& viewProjMatrix,
double viewportCameraDist);
/// Test a screen-space mouse position against all camera wireframe segments.
/// Returns true and sets *outCameraPath if a camera wireframe is within
/// kCameraPickRadius (10 px) of mousePos. Prioritises the closest hit.
@@ -217,6 +227,8 @@ private:
void DestroyBBoxResources();
void InitCamWireResources();
void DestroyCamWireResources();
void InitLightWireResources();
void DestroyLightWireResources();
/// Draw a single axis-aligned box from a GfRange3d.
void DrawBox(const pxr::GfRange3d& range, const pxr::GfMatrix4f& mvp);
@@ -227,6 +239,14 @@ private:
double scale,
std::vector<float>& outVerts);
/// Build light-gizmo line segments (GL_LINES vertex pairs) in world space for
/// a single light prim. localToWorld is the light's transform at m_currentTime;
/// scale is the display-size factor (for direction lines / point markers).
void BuildLightWireframeLines(const pxr::UsdPrim& lightPrim,
const pxr::GfMatrix4d& localToWorld,
double scale,
std::vector<float>& outVerts);
/// Project a world-space point to absolute screen coordinates (x=imagePosX+pixelX, etc.).
/// Returns false when the point is behind the camera.
static bool WorldToScreen(const pxr::GfVec3d& world,
@@ -307,6 +327,10 @@ private:
GLuint m_camWireVAO = 0;
GLuint m_camWireVBO = 0; ///< dynamic VBO; reallocated per frame as needed
// --- Light wireframe GL resources (mirrors camera wireframe) ---
GLuint m_lightWireVAO = 0;
GLuint m_lightWireVBO = 0; ///< dynamic VBO; reallocated per frame as needed
// --- Camera wireframe cache ---
pxr::SdfPathVector m_cachedCameraPaths;
bool m_cameraCacheDirty = true;