3d 标注工具

目录

three-bvh-csg

点选功能:

连接件

挖空

加载glb

three-gltf-viewer

[2. 如果是给 Mesh 做分割标注](#2. 如果是给 Mesh 做分割标注)

[Label Studio 官方网站](#Label Studio 官方网站)

[3. 如果是 Web 端编辑 GLB](#3. 如果是 Web 端编辑 GLB)

Spline

[4. 如果是 AI 资产生产线](#4. 如果是 AI 资产生产线)

[Three.js + 自定义标注](#Three.js + 自定义标注)

[5. 如果要类似 LabelMe 的 3D 标注](#5. 如果要类似 LabelMe 的 3D 标注)

Supervisely

[6. 如果你的目标是训练"动物部件识别"](#6. 如果你的目标是训练“动物部件识别”)


three-bvh-csg

点选功能:

http://localhost:5173/simple.html

连接件

复制代码
http://localhost:5173/coplanar.html

挖空

bash 复制代码
http://localhost:5173/geometry.html

加载glb

simple.js

javascript 复制代码
import * as THREE from 'three';
import { GLTFLoader } from 'three/examples/jsm/loaders/GLTFLoader.js';
import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls.js';
import { TransformControls } from 'three/examples/jsm/controls/TransformControls.js';
import { Brush, Evaluator, ADDITION } from 'three-bvh-csg';

// renderer / scene / camera
const scene = new THREE.Scene();
scene.background = new THREE.Color(0x111111);

const camera = new THREE.PerspectiveCamera(60, window.innerWidth / window.innerHeight, 0.1, 1000);
camera.position.set(3, 3, 3);

const renderer = new THREE.WebGLRenderer({ antialias: true });
renderer.setSize(window.innerWidth, window.innerHeight);
renderer.shadowMap.enabled = true;
document.body.appendChild(renderer.domElement);

// ========== 关键:添加控制器 ==========
// 1. OrbitControls - 控制相机(旋转/缩放/平移场景)
const controls = new OrbitControls(camera, renderer.domElement);
controls.enableDamping = true;      // 惯性效果
controls.dampingFactor = 0.05;
controls.zoomSpeed = 1.2;
controls.rotateSpeed = 1.0;
controls.enableZoom = true;
controls.enablePan = true;

// 2. TransformControls - 控制物体(移动/旋转/缩放模型)
const transformControls = new TransformControls(camera, renderer.domElement);
transformControls.addEventListener('dragging-changed', (event) => {
    // 拖动物体时禁用相机控制器
    controls.enabled = !event.value;
});
scene.add(transformControls.getHelper());

// 辅助工具
const axesHelper = new THREE.AxesHelper(2);
scene.add(axesHelper);
const gridHelper = new THREE.GridHelper(10, 20, 0x888888, 0x444444);
scene.add(gridHelper);

// 灯光
scene.add(new THREE.AmbientLight(0xffffff, 0.6));
const dirLight = new THREE.DirectionalLight(0xffffff, 1);
dirLight.position.set(5, 5, 5);
dirLight.castShadow = true;
scene.add(dirLight);
scene.add(dirLight.target);

const backLight = new THREE.DirectionalLight(0xffffff, 0.5);
backLight.position.set(-2, 1, -3);
scene.add(backLight);

// 键盘快捷键:W=移动,E=旋转,R=缩放
window.addEventListener('keydown', (e) => {
    switch (e.code) {
        case 'KeyW': transformControls.setMode('translate'); break;
        case 'KeyE': transformControls.setMode('rotate'); break;
        case 'KeyR': transformControls.setMode('scale'); break;
    }
});

const evaluator = new Evaluator();
const loader = new GLTFLoader();

let resultMesh = null;

// 加载 GLB
loader.load(
    './niu.glb',
    (gltf) => {
        const model = gltf.scene;
        
        // 开启阴影
        model.traverse((child) => {
            if (child.isMesh) {
                child.castShadow = true;
                child.receiveShadow = true;
            }
        });
        
        scene.add(model);
        
        // 将 TransformControls 绑定到模型上
        transformControls.attach(model);
        
        // 调整相机位置以适应模型
        const box = new THREE.Box3().setFromObject(model);
        const center = box.getCenter(new THREE.Vector3());
        const size = box.getSize(new THREE.Vector3());
        const maxDim = Math.max(size.x, size.y, size.z);
        camera.position.set(center.x + maxDim, center.y + maxDim * 0.8, center.z + maxDim * 1.5);
        camera.lookAt(center);
        controls.target.copy(center);
        
        console.log("模型加载成功");
    },
    (xhr) => {
        console.log(Math.round(xhr.loaded / xhr.total * 100) + '%');
    },
    (error) => {
        console.error('加载失败:', error);
    }
);

// 动画循环
function animate() {
    requestAnimationFrame(animate);
    
    // 更新控制器(支持惯性效果)
    controls.update();
    
    renderer.render(scene, camera);
}
animate();

three-gltf-viewer

bash 复制代码
npm install
npm run dev
bash 复制代码
https://github.com/donmccurdy/three-gltf-viewer

2. 如果是给 Mesh 做分割标注

例如:

复制代码
狗模型
↓
点击耳朵
↓
标记为 Ear

比较成熟的是:

Label Studio 官方网站

支持自定义前端。

很多团队会:

复制代码
复制代码
Three.js
+
Label Studio

自己做 Mesh 面选取。

3. 如果是 Web 端编辑 GLB

最成熟的是:

Spline

支持:

  • 导入 GLB
  • 编辑材质
  • 添加灯光
  • 标注热点(Hotspot)

例如:

复制代码
点击耳朵
显示:
Lion Ear

非常适合产品展示。


4. 如果是 AI 资产生产线

你这种场景:

复制代码
AIGC
↓
TRELLIS
↓
GLB
↓
人工审核

其实最常见的是:

Three.js + 自定义标注

实现:

复制代码
复制代码
点击 Mesh
↓
记录 Face ID
↓
记录 Label
↓
保存 JSON

例如:

复制代码
复制代码
{
  "tail": [123,124,125],
  "ear": [456,457,458]
}

很多 3D 数据集都是这么做出来的。


5. 如果要类似 LabelMe 的 3D 标注

推荐看看:

Supervisely

支持:

  • 点云
  • Mesh
  • 3D Cuboid
  • 团队协作

属于目前工业界比较成熟的方案之一。


6. 如果你的目标是训练"动物部件识别"

例如:

复制代码
复制代码
狮子
↓
头部
鬃毛
尾巴
四肢

我会建议直接基于:

  • Three.js
  • React Three Fiber
  • GLTFLoader

开发一个轻量标注系统。

功能只需要:

复制代码
复制代码
上传GLB
↓
点击区域
↓
输入标签
↓
保存JSON

两三周就能做出来,而且比 CVAT、Supervisely 更贴合你的动物手办场景。

所以我想确认一下,你说的 3D标注 是:

  1. 给整个模型分类(狮子、老虎、小狗)?
  2. 给模型部件打标签(耳朵、尾巴、腿)?
  3. 给 Mesh 面片做语义分割标注
  4. 给 3D 检测框/Cuboid 标注

这几种工具路线差别很大。

相关推荐
ting94520003 小时前
Humalike X Hermes 深度技术剖析:单指令注入群聊社交智能的底层架构、算法与跨 IM 平台实现
人工智能·算法·架构
涤生大数据3 小时前
一次“没有运行日志”的DolphinScheduler任务失败排查
大数据·数据库·人工智能·状态模式
东风破_3 小时前
Vibe Coding 上头之后,我开始用 SDD 给 AI 编程加一张“施工图”
人工智能·程序员
weixin_403810134 小时前
AI智能体写安卓自动化脚本教程:Cursor/Trae+CLI 实战,自然语言生成代码
android·人工智能·自动化·跨境电商·安卓自动化脚本·多账户运营
深圳雨林凯AI4 小时前
雨林凯AI四方连图介质适配原理:像素密度、纱线纹理与颜色管理怎么协调
人工智能
玖玥拾4 小时前
Unity3D RPG 入门项目(十一)主角完整战斗、怪物自动刷新、四大类型技能系统
游戏·3d·unity·游戏引擎
ZGIAI4 小时前
ZGI 混合检索:汇集候选并统一重排
人工智能·架构
ZGIAI4 小时前
ZGI 运行日志:还原任务与节点状态
人工智能·架构
Scott9999HH4 小时前
2026 中小企业如何破局 AI 搜索?轻量化 GEO 优化系统架构设计与 Python 实战落地
人工智能
甲维斯5 小时前
opencode的“恶果”来了,吃掉100G空间!
人工智能