3d-rendering

GitHub

提供基于THREE.js的3D渲染技能,涵盖WebGL管线、动态缓冲区管理(无几何倍增)、点云渲染优化及TF树变换解析。适用于构建高性能3D可视化面板,处理场景优化与数据流更新。

.github/skills/3d-rendering/SKILL.md lichtblick-suite/lichtblick

Trigger Scenarios

需要实现或优化基于THREE.js的3D可视化功能 处理WebGL渲染性能问题 管理动态几何体缓冲区或点云数据

Install

npx skills add lichtblick-suite/lichtblick --skill 3d-rendering -g -y
More Options

Non-standard path

npx skills add https://github.com/lichtblick-suite/lichtblick/tree/develop/.github/skills/3d-rendering -g -y

Use without installing

npx skills use lichtblick-suite/lichtblick@3d-rendering

指定 Agent (Claude Code)

npx skills add lichtblick-suite/lichtblick --skill 3d-rendering -a claude-code -g -y

安装 repo 全部 skill

npx skills add lichtblick-suite/lichtblick --all -g -y

预览 repo 内 skill

npx skills add lichtblick-suite/lichtblick --list

SKILL.md

Frontmatter
{
    "name": "3d-rendering",
    "description": "Deep THREE.js rendering knowledge for the 3D panel: WebGL pipeline, buffer management, instanced rendering, shader considerations, and scene optimization techniques."
}

3D Rendering Skill

THREE.js Integration

Renderer Setup

const renderer = new THREE.WebGLRenderer({
  canvas,
  antialias: true,
  alpha: true,
});
renderer.setPixelRatio(window.devicePixelRatio);
renderer.outputColorSpace = THREE.SRGBColorSpace;

Render Loop

  • Driven by requestAnimationFrame
  • Each frame: update transforms → update extensions → render scene
  • No double-buffering needed (WebGL handles swap)

DynamicBufferGeometry Details

packages/suite-base/src/panels/ThreeDeeRender/DynamicBufferGeometry.ts:

class DynamicBufferGeometry extends THREE.BufferGeometry {
  // Grows to EXACTLY itemCount when capacity is exceeded — no geometric doubling.
  resize(itemCount: number): void {
    this.setDrawRange(0, itemCount);
    if (itemCount <= this.#itemCapacity) {
      return; // capacity sufficient — only the draw range changed
    }
    // For each attribute, allocate a NEW typed array of exactly itemCount * itemSize
    // (old data is NOT copied; callers refill the buffer after resize)
    this.#itemCapacity = itemCount;
  }
}

Growth Behavior (Important)

  • resize(itemCount) always calls setDrawRange(0, itemCount) first
  • If itemCount <= itemCapacity, it returns early — buffers are reused, only the draw range moves
  • If itemCount > itemCapacity, each attribute is reallocated to exactly itemCount * itemSize (no * 2 over-allocation, no copy of existing data)
  • Capacity only ever grows; it is never shrunk below a previous high-water mark

⚠️ Do not assume geometric/amortized doubling here. Repeatedly increasing the count by small increments reallocates every time, so callers that know a target size should resize to it once.

Point Cloud Rendering

Data Flow

Raw message (PointCloud2)
    │
    ▼
Decode fields (x, y, z, rgb, intensity)
    │
    ▼
Fill position buffer (Float32Array)
Fill color buffer (Uint8Array)
    │
    ▼
Upload to GPU (BufferAttribute.needsUpdate = true)
    │
    ▼
Render with THREE.Points or InstancedMesh

Decay History

  • Configurable decayTime in seconds
  • Old points are culled by sliding the drawRange start forward
  • Ring-buffer approach: write position wraps around, draw range skips old data
  • Avoids array shifting (O(1) per frame instead of O(n))

Point Budget

  • Too many points → GPU bottleneck
  • filterQueue: processes messages in batches per frame
  • Downsampling: skip points when exceeding budget

Transform Resolution

TF Tree Structure

world (root)
├── base_link
│   ├── lidar_link
│   ├── camera_link
│   └── imu_link
└── map
    └── odom
        └── base_link (loop via static transform)

Time-based Lookup

// TransformTree.apply has an 8-argument signature:
const pose = transformTree.apply(
  output,       // Pose written in place (returned, or undefined on failure)
  input,        // Readonly<Pose> source pose
  frameId,      // destination/target frame
  rootFrameId,  // optional explicit root frame (defaults to frame.root())
  srcFrameId,   // source frame
  dstTime,      // Time to evaluate the destination frame at
  srcTime,      // Time to evaluate the source frame at
  maxDelta,     // optional Duration cap on extrapolation
);
  • Defined in packages/suite-base/src/panels/ThreeDeeRender/transforms/TransformTree.ts
  • Writes into the provided output Pose and returns it (or undefined if a frame is missing)
  • Interpolates between stored transforms at query time; maxDelta caps extrapolation from stale data

Instanced Rendering

For many identical objects (markers, arrows):

const mesh = new THREE.InstancedMesh(geometry, material, maxCount);
// Update per-instance transform
mesh.setMatrixAt(index, matrix);
mesh.instanceMatrix.needsUpdate = true;
  • Single draw call for all instances
  • Massively reduces draw call overhead (100→1 for 100 markers)
  • maxCount determines GPU buffer allocation — avoid over-allocation

Shader Considerations

  • Custom materials extend THREE.ShaderMaterial or THREE.RawShaderMaterial
  • Point size attenuation: points shrink with distance (sizeAttenuation: true)
  • Color mapping: intensity → color lookup via uniform texture
  • Vertex colors: per-point coloring via vertexColors: true on material

Performance Optimization Checklist

  1. ✅ Use DynamicBufferGeometry — never new BufferGeometry() per frame
  2. ✅ Set needsUpdate = true only on changed attributes
  3. ✅ Use InstancedMesh for repeated geometries (>10 instances)
  4. ✅ Dispose materials/geometries on removal (prevents GPU memory leak)
  5. ✅ Frustum culling enabled (default in THREE.js)
  6. ✅ Reuse temporary Vector3/Matrix4 instances (object pool pattern)
  7. ✅ Limit point count with decay + budget
  8. ❌ Never create new THREE.Material per frame
  9. ❌ Never call renderer.render() if scene hasn't changed
  10. ❌ Never use traverse() in hot path — cache node references

Version History

  • cab9317 Current 2026-07-24 12:16

Same Skill Collection

.github/skills/caching-internals/SKILL.md
.github/skills/deserialization/SKILL.md
.github/skills/e2e-playwright-mcp/SKILL.md
.github/skills/electron-internals/SKILL.md
.github/skills/extensions-internals/SKILL.md
.github/skills/layouts-internals/SKILL.md
.github/skills/mcap-format/SKILL.md
.github/skills/message-path/SKILL.md
.github/skills/message-pipeline/SKILL.md
.github/skills/panel-extension-api/SKILL.md
.github/skills/panel-image/SKILL.md
.github/skills/panel-log/SKILL.md
.github/skills/panel-map/SKILL.md
.github/skills/panel-raw-messages/SKILL.md
.github/skills/panel-state-transitions/SKILL.md
.github/skills/panel-user-scripts/SKILL.md
.github/skills/performance/SKILL.md
.github/skills/player-internals/SKILL.md
.github/skills/plot-internals/SKILL.md
.github/skills/remote-caching/SKILL.md
.github/skills/test-conventions/SKILL.md
.github/skills/theme/SKILL.md
.github/skills/unit-testing/SKILL.md
.github/skills/web-workers/SKILL.md
.github/skills/websocket-connection/SKILL.md

Metadata

Files
0
Version
cab9317
Hash
267ec6ae
Indexed
2026-07-24 12:16

Accueil - Wiki
Copyright © 2011-2026 iteam. Current version is 2.155.2. UTC+08:00, 2026-08-07 09:13
浙ICP备14020137号-1 $Carte des visiteurs$