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

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

相关推荐
fai厅的秃头姐!13 分钟前
OpenCV实战篇
人工智能·opencv·计算机视觉
TMT星球1 小时前
虎鲸文娱春苗编剧计划全面升级,已孵化20个剧本进入前期开发
大数据·人工智能
奔跑中的小象7 小时前
统信UOS + 天数AI卡部署SGLang服务手册
人工智能·uos·sglang·天数智芯
DevSecOps选型指南7 小时前
中国版Mythos,为何是悬镜安全灵脉CodeAI?
人工智能·安全
Shockang8 小时前
LangGraph 状态机实战
人工智能
刹那芳华19928 小时前
循环神经网络的从零开始实现(RNN)
人工智能·rnn·深度学习
阿童木写作8 小时前
跨境图片翻译工具多合一,批量图片视频字幕翻译加智能抠图
人工智能·python·音视频·语音识别
科技之门8 小时前
AI3D从建模到贴图、绑骨和动画的完整流程怎么做?V2Fun完整工作流指南
人工智能·3d·贴图
宇宙第一小趴菜8 小时前
二、机器学习的应用领域和发展史
人工智能·机器学习
前端开发江鸟8 小时前
我写过 MCP Server,却一直以为 MCP 只有 Tool
人工智能