跳到主要内容
极客日志极客日志面向AI+效率的开发者社区
首页博客我的书AI学习GitHub 精选镜像AI工具UI配色美学关于
搜索内容 / 工具 / 仓库 / 镜像...⌘K搜索
注册
博客列表
TypeScriptNode.js大前端

基于 Three.js + React Three Fiber 实现交互式3D人体肌肉解剖图

基于 Three.js 和 React Three Fiber 构建浏览器端交互式 3D 人体肌肉解剖展示工具。通过 Draco 压缩模型至 6.8MB,利用射线检测实现点击高亮与中英文名称映射。支持旋转缩放交互,无需后端服务,适用于健身教育、医学教学及康复指导场景。

乱七八糟发布于 2026/4/7更新于 2026/10/24127 浏览

前端实现交互式 3D 人体肌肉解剖图:基于 Three.js + React Three Fiber 方案

为什么要做这个?

传统的肌肉解剖学习通常依赖静态图片或昂贵的 3D 软件。为提供免费的在线工具,基于开源 Z-Anatomy 项目,在浏览器中实现一个交互式的 3D 肌肉解剖图。

技术架构概览

┌─────────────────────────────────────────────────────────────┐
│ 用户浏览器                                                  │
├─────────────────────────────────────────────────────────────┤
│ ┌─────────────┐ ┌─────────────┐ ┌─────────────────┐        │
│ │ GLB 模型    │ -> │ Three.js  │ -> │ React Three   │        │
│ │ (Draco)     │    │ 场景渲染  │    │ Fiber 组件    │        │
│ └─────────────┘ └─────────────┘ └─────────────────┘        │
│                                                             │
│ ┌──────────────────┼──────────────────┐                    │
│ v                  v                  v                    │
│ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐            │
│ │ 射线检测    │ │ 肌肉高亮    │ │ i18n 翻译   │            │
│ │ Raycaster   │ │ 材质切换    │ │ 中英文名称  │            │
│ └─────────────┘ └─────────────┘ └─────────────┘            │
└─────────────────────────────────────────────────────────────┘

模型来源与处理

Z-Anatomy 开源项目

Z-Anatomy 是一个开源的人体解剖学 Blender 项目,包含完整的人体肌肉、骨骼、器官等结构。原始文件约 300MB,包含 1000+ 个独立的 mesh 对象。

模型导出与压缩

为了在 Web 端使用,需要将 Blender 文件导出为 GLB 格式,并使用 Draco 压缩:

# export_cli.py - Blender 命令行导出脚本
import bpy

# 选择所有肌肉相关的对象
muscle_keywords = ['muscle', 'deltoid', 'bicep', 'tricep', 'pectoralis', ...]

for obj in bpy.data.objects:
    if obj.type == 'MESH':
        name_lower = obj.name.lower()
        if any(keyword in name_lower for keyword  muscle_keywords):
            obj.select_set()


bpy.ops.export_scene.gltf(
    filepath=,
    export_format=,
    use_selection=,
    export_draco_mesh_compression_enable=,
    export_draco_mesh_compression_level=,
)
in
True
# 导出为 GLB,启用 Draco 压缩
'muscle-anatomy.glb'
'GLB'
True
True
6

导出后的模型从 300MB 压缩到约 6.8MB,非常适合 Web 加载。

核心实现

1. 场景搭建 (React Three Fiber)

// muscle-scene.tsx
import { Canvas } from '@react-three/fiber';
import { OrbitControls, Environment } from '@react-three/drei';

export function MuscleScene({ onMuscleClick, onMuscleHover, hoveredMuscle, selectedMuscle }) {
  return (
    <Canvas camera={{ position: [1.5, 0.3, 2], fov: 50 }}>
      {/* 环境光照 */}
      <ambientLight intensity={0.6} />
      <directionalLight position={[5, 5, 5]} intensity={0.8} />
      {/* 3D 模型 */}
      <Suspense fallback={null}>
        <MuscleModel 
          onMuscleClick={onMuscleClick} 
          onMuscleHover={onMuscleHover} 
          hoveredMuscle={hoveredMuscle} 
          selectedMuscle={selectedMuscle} 
        />
      </Suspense>
      {/* 轨道控制器 */}
      <OrbitControls enablePan={false} minDistance={1} maxDistance={5} target={[0, 0.5, 0]} />
      {/* 环境贴图 */}
      <Environment preset="studio" />
    </Canvas>
  );
}

2. 模型加载与肌肉识别

// muscle-model.tsx
import { useGLTF } from '@react-three/drei';
import * as THREE from 'three';

// 肌肉识别关键词
const muscleKeywords = [
  'muscle', 'deltoid', 'bicep', 'tricep', 'pectoralis',
  'latissimus', 'trapezius', 'rectus', 'oblique', 'gluteus',
  'quadricep', 'vastus', 'hamstring', 'gastrocnemius', 'soleus',
];

// 需要隐藏的非肌肉对象
const HIDDEN_KEYWORDS = [
  'region', 'fascia', 'bursa', 'ligament', 'membrane', '.j', '.t',
];

function isMuscle(name: string): boolean {
  const lowerName = name.toLowerCase();
  return muscleKeywords.some(keyword => lowerName.includes(keyword)) &&
         !HIDDEN_KEYWORDS.some(keyword => lowerName.includes(keyword));
}

export function MuscleModel({ onMuscleClick, onMuscleHover, hoveredMuscle, selectedMuscle }) {
  const { scene } = useGLTF('/models/muscle-anatomy.glb');

  // 克隆场景并处理材质
  const clonedScene = useMemo(() => {
    const clone = scene.clone(true);
    clone.traverse((child) => {
      if (child instanceof THREE.Mesh) {
        if (shouldHide(child.name)) {
          child.parent?.remove(child);
          return;
        }
        if (isMuscle(child.name)) {
          // 为肌肉设置红色系材质
          child.material = child.material.clone();
          child.material.color = new THREE.Color(0xc44d4d);
          child.material.roughness = 0.7;
          child.material.metalness = 0.1;
        }
      }
    });
    return clone;
  }, [scene]);

  return (
    <primitive object={clonedScene} position={[0, -0.84, 0]}
      onPointerOver={handlePointerOver}
      onPointerOut={handlePointerOut}
      onClick={handleClick} />
  );
}

3. 交互高亮效果

// 高亮颜色配置
const HIGHLIGHT_COLOR = new THREE.Color(0x5ac57a); // 薄荷绿 - 悬停
const SELECTED_COLOR = new THREE.Color(0x4caf50);  // 深绿 - 选中

// 更新高亮效果
useEffect(() => {
  clonedScene.traverse((child) => {
    if (child instanceof THREE.Mesh && isMuscle(child.name)) {
      const material = child.material as THREE.MeshStandardMaterial;
      const muscleId = getMuscleIdFromModelName(child.name);
      const isHovered = muscleId === hoveredMuscle;
      const isSelected = muscleId === selectedMuscle;

      if (isSelected) {
        material.emissive = SELECTED_COLOR;
        material.emissiveIntensity = 0.5;
      } else if (isHovered) {
        material.emissive = HIGHLIGHT_COLOR;
        material.emissiveIntensity = 0.3;
      } else {
        material.emissive = new THREE.Color(0x000000);
        material.emissiveIntensity = 0;
      }
    }
  });
}, [hoveredMuscle, selectedMuscle, clonedScene]);

4. 肌肉名称映射与多语言

Z-Anatomy 的命名格式是 Muscle name.l(左侧)/ Muscle name.r(右侧),需要将其映射到标准的肌肉 ID:

// muscles.ts
const muscleAliases: Record<string,string[]> = {
  'pectoralis_major': [
    'pectoralis major',
    'sternocostal head of pectoralis major',
    'clavicular head of pectoralis major'
  ],
  'biceps_brachii': [
    'biceps brachii',
    'long head of biceps brachii',
    'short head of biceps brachii'
  ],
};

export function getMuscleIdFromModelName(modelName: string): string | undefined {
  const cleanName = modelName
    .replace(/\.(l|r|el|er)$/i, '')
    .toLowerCase()
    .trim();

  for (const [muscleId, aliases] of Object.entries(muscleAliases)) {
    if (aliases.some(alias => cleanName.includes(alias))) {
      return muscleId;
    }
  }
  return undefined;
}

多语言翻译存储在 i18n 模块中:

// locales/zh/muscle-anatomy.ts
export const muscleAnatomy = {
  muscles: {
    pectoralis_major: '胸大肌',
    biceps_brachii: '肱二头肌',
    triceps_brachii: '肱三头肌',
    latissimus_dorsi: '背阔肌',
    rectus_abdominis: '腹直肌',
    gluteus_maximus: '臀大肌',
    quadriceps_femoris: '股四头肌',
    gastrocnemius: '腓肠肌',
  },
};

性能优化

1. 模型压缩

  • 使用 Draco 压缩,模型从 300MB 压缩到 6.8MB
  • 在 Blender 中使用 Decimate Modifier 降低面数

2. 动态加载

// 使用 Next.js 动态导入,禁用 SSR
const MuscleScene = dynamic(
  () => import('./muscle-scene').then((mod) => mod.MuscleScene),
  { ssr: false }
);

3. 材质优化

  • 克隆材质避免全局修改
  • 使用 emissive 属性实现高亮,避免重新创建材质

应用场景

这套技术方案可以应用于多种场景:

  1. 健身教育:帮助健身爱好者了解肌肉位置和名称
  2. 医学教学:辅助医学生学习人体解剖
  3. 康复指导:展示特定肌肉群的位置
  4. 游戏开发:角色肌肉系统参考

总结

核心技术点包括:

  1. 模型处理:从 Z-Anatomy 导出并压缩 GLB 模型
  2. 场景搭建:使用 React Three Fiber 构建 3D 场景
  3. 交互实现:射线检测 + 材质高亮
  4. 多语言支持:肌肉名称中英文翻译

这套方案完全在浏览器端运行,无需后端服务,非常适合构建教育类的 3D 可视化应用。

相关链接

  • Z-Anatomy 开源项目
  • React Three Fiber 文档

目录

  1. 前端实现交互式 3D 人体肌肉解剖图:基于 Three.js + React Three Fiber 方案
  2. 为什么要做这个?
  3. 技术架构概览
  4. 模型来源与处理
  5. Z-Anatomy 开源项目
  6. 模型导出与压缩
  7. export_cli.py - Blender 命令行导出脚本
  8. 选择所有肌肉相关的对象
  9. 导出为 GLB,启用 Draco 压缩
  10. 核心实现
  11. 1. 场景搭建 (React Three Fiber)
  12. 2. 模型加载与肌肉识别
  13. 3. 交互高亮效果
  14. 4. 肌肉名称映射与多语言
  15. 性能优化
  16. 1. 模型压缩
  17. 2. 动态加载
  18. 3. 材质优化
  19. 应用场景
  20. 总结
  21. 相关链接

更多推荐文章

查看全部
  • 大模型量化详解:基于 llama.cpp 的 GGUF 转换与量化
  • JS 生成 UUID 的常见方案与生产环境避坑指南
  • 具身智能落地瓶颈:RoboBrain 2.5 的空间与时间协同方案
  • MyBatisPlus 与 Thymeleaf 全栈分页实战方案
  • Capacitor 跨平台 Web 原生应用开发及鸿蒙适配指南
  • GitHub Copilot 编辑器集成与实战技巧
  • 链表常见操作:移除元素、合并、反转及回文判断
  • 数据结构核心:链表(单链表、双链表及循环链表)
  • AI 大模型入门与实战指南:从基础原理到应用部署
  • Whisper-large-v3 长文本语音转写与智能分段实战
  • Python Literal 类型注解详解
  • Python 连接 MySQL 的 5 种主流方案
  • RabbitMQ/Spring-AMQP 高级特性:事务机制与消息限流
  • 数据结构:相交链表、随机链表复制及链表回文问题解析
  • 基于 Simulink 的协作机器人末端执行器抓取控制仿真
  • Whisper-large-v3 语音转文字部署与使用教程
  • 圣女司幼幽 - 造相 Z-Turbo 镜像评测:对比 Stable Diffusion 本地部署优势
  • OpenClaw 多飞书机器人配置与绑定指南
  • Python UV 搭配 Miniconda:下一代包管理体验
  • DREAM 数据库:睡眠脑电与梦境报告配对研究及意识神经关联分析

相关免费在线工具

  • Base64 字符串编码/解码

    将字符串编码和解码为其 Base64 格式表示形式即可。 在线工具,Base64 字符串编码/解码在线工具,online

  • Base64 文件转换器

    将字符串、文件或图像转换为其 Base64 表示形式。 在线工具,Base64 文件转换器在线工具,online

  • Markdown转HTML

    将 Markdown(GFM)转为 HTML 片段,浏览器内 marked 解析;与 HTML转Markdown 互为补充。 在线工具,Markdown转HTML在线工具,online

  • HTML转Markdown

    将 HTML 片段转为 GitHub Flavored Markdown,支持标题、列表、链接、代码块与表格等;浏览器内处理,可链接预填。 在线工具,HTML转Markdown在线工具,online

  • JSON 压缩

    通过删除不必要的空白来缩小和压缩JSON。 在线工具,JSON 压缩在线工具,online

  • JSON美化和格式化

    将JSON字符串修饰为友好的可读格式。 在线工具,JSON美化和格式化在线工具,online