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 标注

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

相关推荐
Urbano38 分钟前
校服精细化缝制难点、全流程自动化改造方案与核心贴袋设备选型实操科普
人工智能
IT_陈寒44 分钟前
SpringBoot自动配置失灵?你可能忘了这个关键注解
前端·人工智能·后端
零零信安1 小时前
AI智能体,攻守失衡的催化剂 | 零零信安
人工智能·网络安全·数据泄露·暗网·零零信安
IvorySQL1 小时前
PG 日报|社区讨论重构 pg_hba 配置文件格式
数据库·人工智能·postgresql·重构·ivorysql
白色机械键盘1 小时前
基于多智能体协作的预测性运维误报分级治理架构研究
人工智能
Web极客码1 小时前
突破并发瓶颈:云端高性能架构如何赋能海外 AI Agent 矩阵的高效产出
服务器·人工智能·架构
甲维斯1 小时前
P图自由!把字节SeeDream5pro接入Jimage!
人工智能
风华圆舞2 小时前
鸿蒙上跑通第一个 AI Agent:5 分钟接入智谱/DeepSeek
人工智能·华为·harmonyos·arkts·arkui·toolregistry
love530love2 小时前
将 ChatCut MCP 插件从 Codex 桌面应用移植到 WorkBuddy —— 完整适配实录
ide·人工智能·windows·视频剪辑·ai agent
Litluecat2 小时前
2026年7月13日科技热点新闻
人工智能·科技·新闻·每日·速览