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

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

相关推荐
CodePlayer竟然被占用了1 小时前
当编排逻辑从上下文窗口搬到脚本:Claude Code Dynamic Workflows 深度拆解
人工智能
莫逸风1 小时前
【AgentScope】HarnessAgent 学习指南
大数据·人工智能
Zldaisy3d1 小时前
LPBF 3D打印迈入精准可控的技术深水区:扫描策略智能化与连续化正重构竞争壁垒
3d·重构
武子康1 小时前
调查研究-153 Cloudflare 能部署网站吗?2026 年完整对比 Vercel / Netlify / 自建服务器
大数据·运维·服务器·人工智能·部署·devops·opc
IvanCodes1 小时前
Agent开发入门:提示词工程
人工智能·agent
麦哲思科技任甲林1 小时前
白话Skills之七:编写AI Skill的原则
人工智能·prompt·agent·ai编程·skills
weixin_397574091 小时前
从“对接大模型“到“生成AI服务“:下一代企业AI应用开发框
人工智能
ConardLi1 小时前
啊?我刚开源的 Skills 已经 7K Star 了?!
前端·人工智能·后端
玩c#的小杜同学1 小时前
一周 AI 新鲜事|2026.05.25—2026.05.31
人工智能·程序人生·ai·c#·程序员创富