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

前端 3D 人体肌肉解剖图:基于 Three.js + React Three Fiber

介绍如何使用 Three.js 和 React Three Fiber 在前端构建交互式 3D 人体肌肉解剖展示工具。核心流程包括从 Z-Anatomy 获取模型,使用 Blender 导出并 Draco 压缩至 Web 可用格式,通过 React Three Fiber 搭建场景,利用射线检测实现点击高亮交互,并结合 i18n 支持多语言肌肉名称映射。方案无需后端,适用于健身教育及医学教学等场景。

SparkGeek发布于 2026/4/6更新于 2026/10/26116 浏览

前端实现交互式 3D 人体肌肉解剖展示

本文将详细介绍如何在前端实现一个交互式的 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 in muscle_keywords):
            obj.select_set(True)

# 导出为 GLB,启用 Draco 压缩
bpy.ops.export_scene.gltf(
    filepath='muscle-anatomy.glb',
    export_format='GLB',
    use_selection=True,
    export_draco_mesh_compression_enable=True,
    export_draco_mesh_compression_level=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: '腓肠肌',
        // ... 150+ 肌肉翻译
    },
};

性能优化

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. 游戏开发:角色肌肉系统参考

总结

本文介绍了如何在前端使用 Three.js + React Three Fiber 实现交互式 3D 人体肌肉解剖展示。核心技术点包括:

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

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

目录

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

更多推荐文章

查看全部
  • Flutter 组件 spry 适配鸿蒙 HarmonyOS:轻量级 Web 框架
  • 微信 AI 群聊机器人本地搭建教程
  • Codex 与 Copilot 简介
  • Stable Diffusion 与 ComfyUI 整合包技术指南
  • 2026 年 3 月 GESP C++ 一级真题及解析:数字替换
  • AI 编程工具选型:Copilot、Cursor、Codex 核心差异
  • 基于 Spring Boot 的停车场管理系统设计与实现
  • 基于自适应卡尔曼滤波器的无人机追踪无人车 MATLAB 仿真
  • Llama-2-7b在昇腾NPU上的六大核心场景性能基准报告
  • Redis 主从复制架构详解
  • Qwen3-VL-Embedding 与 Reranker 模型:统一多模态表征与排序
  • Python 修改 pip 默认安装路径的几种方法
  • MiGPT GUI 部署小爱音箱接入 AI 及内网穿透配置
  • 3 款免费 AI 视频修复工具,有效提升视频画质
  • GitHub 2FA 丢失 Microsoft Authenticator 恢复与重置指南
  • 网文作者用什么AI工具?2026年AI写作工具实用榜单
  • 实战指南:Stable Diffusion 模型部署问题排查与性能调优
  • Open WebUI 下载的模型文件默认存放路径
  • 将 Zed 集成到 Bright Data Web MCP,让 AI 编辑器具备“超能力”
  • 无人机 GPS/北斗多源融合定位:标定、抗干扰与精度提升

相关免费在线工具

  • 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