当前位置: 首页 > news >正文

LearningCell代码解读 - zhang

LearningCell代码解读

项目介绍

最近,GitHub上有一个很火的项目,一个基于 3D 模型的细胞学习平台。该平台的目标是帮助用户通过 3D 模型学习细胞的基本概念和功能。

代码地址为:LearningCell

项目代码很短很少,非常简单,随着3d高斯泼溅效果的不断完善,3D-WEB也快迎来了新的应用和突破。

项目的技术栈如下:

  • 前端:React + TypeScript + Vite
  • 3D 模型:GLTF 格式
  • 3D 模型加载:Draco 压缩

目录结构

.
├── .github/workflows/deploy.yml   # GitHub Pages 自动部署
├── README.md
├── app/                           # Vite 前端工程
│   ├── public/
│   │   ├── draco/                 # 自带的 Draco 解码器
│   │   ├── images/                # 细胞缩略图(已压缩)
│   │   └── models/                # 5 个 .glb 模型
│   ├── src/
│   │   ├── components/            # UI 组件(侧栏、3D 查看器、信息面板等)
│   │   ├── data/models.ts         # 5 个生物概念的数据
│   │   ├── hooks/useModel.ts      # 加载状态订阅 hook
│   │   ├── lib/modelLoader.ts     # 流式下载 + Draco 解析 + 缓存
│   │   ├── App.tsx
│   │   └── ...
│   └── package.json
└── (根目录其它是源文件备份,例如未压缩的 PNG 与 .draco.glb 原始资源)

代码解析

1,入口代码
在App.tsx中,我们使用useEffect来加载默认模型和预加载其它模型。

  useEffect(() => {let cancelled = false;const firstEntry = loadModel(activeModel.modelUrl, {fileSize: activeModel.fileSize,});let started = false;const queueOthers = () => {if (cancelled || started) return;started = true;const queue = MODELS.filter((m) => m.id !== activeModel.id);let i = 0;const next = () => {if (cancelled || i >= queue.length) return;const m = queue[i++];preloadModel(m.modelUrl, { fileSize: m.fileSize });const entry = getLoadEntry(m.modelUrl);entry?.promise.finally(() => {if (cancelled) return;setTimeout(next, 120);});};next();};}

2,模型加载代码
在modelLoader.ts中,我们定义了loadModel函数,用于加载3D模型。
首先是从URL中获取模型的文件大小,然后使用fetchWithProgress函数来流式下载模型。但是在本项目中是不需要用到下载,而是直接加载模型;

加载器直接基于three.js的GLTFLoader和DRACOLoader来加载模型。

import { GLTFLoader, type GLTF } from 'three/examples/jsm/loaders/GLTFLoader.js';
import { DRACOLoader } from 'three/examples/jsm/loaders/DRACOLoader.js';

详细的实现函数如下


export function loadModel(url: string, options: LoadOptions): LoadEntry {const existing = cache.get(url);if (existing) return existing;const entry: LoadEntry = {status: 'downloading',progress: 0,listeners: new Set(),promise: Promise.resolve() as unknown as Promise<GLTF>,};cache.set(url, entry);notifyCache();entry.promise = (async () => {try {const buffer = await fetchWithProgress(url, options.fileSize, (loaded, total) => {entry.status = 'downloading';entry.progress = Math.min(0.95, (loaded / Math.max(1, total)) * 0.95);notifyEntry(entry);});entry.buffer = buffer;entry.status = 'parsing';entry.progress = 0.97;notifyEntry(entry);const gltf = await parseGLTF(buffer, '');entry.gltf = gltf;entry.status = 'done';entry.progress = 1;notifyEntry(entry);return gltf;} catch (error) {entry.status = 'error';entry.error = error;notifyEntry(entry);throw error;}})();return entry;
}

3,模型渲染代码

具体的实现是在ModelScene.tsx中,我们使用useModel hook来订阅模型加载状态,当模型加载完成后,我们将模型添加到场景中。


/*** 将 GLTF.scene 居中、缩放到合适大小后渲染。* 通过 useFrame 实现可控的自动旋转。*/
export function ModelScene({gltf,autoRotate,initialRotationY = 0,displayScale = 1,
}: Props) {const groupRef = useRef<THREE.Group>(null);const { centeredScene, scale } = useMemo(() => {const cloned = cloneScene(gltf);   // 调用工具函数克隆场景,确保每个组件实例拥有独立的模型副本const box = new THREE.Box3().setFromObject(cloned);   // 计算模型的包围盒,获取模型的空间范围const size = new THREE.Vector3();box.getSize(size);const center = new THREE.Vector3();box.getCenter(center);   // 通过将模型位置减去包围盒中心点坐标,实现几何中心对齐原点 cloned.position.x -= center.x;cloned.position.y -= center.y;cloned.position.z -= center.z;const maxDim = Math.max(size.x, size.y, size.z) || 1;const targetSize = 2.0;return {centeredScene: cloned,scale: (targetSize / maxDim) * displayScale,};}, [gltf, displayScale]);// 切换模型时重置旋转到默认角度 (当切换模型或修改初始旋转角度时,重置模型到指定的初始姿态。)useEffect(() => {if (groupRef.current) {groupRef.current.rotation.set(0, initialRotationY, 0);}}, [initialRotationY, gltf]);useFrame((_, delta) => {     //    每一帧更新模型的旋转角度,实现自动旋转效果。if (autoRotate && groupRef.current) {groupRef.current.rotation.y += delta * 0.25;   // 每一帧增加0.25弧度的旋转角度,实现自动旋转效果。}});return (<group ref={groupRef} scale={scale} rotation={[0, initialRotationY, 0]}><primitive object={centeredScene} /></group>);
}
http://www.jsqmd.com/news/878381/

相关文章:

  • 利用Taotoken模型广场为你的智能客服场景选择合适的大模型
  • 2026 呼和浩特房屋漏水不用愁!雨中匠人免费上门检测,本地专业防水公司常年TOP1!卫生间免砸砖防水,快速解决您的烦恼。权威!靠谱!稳定!售后无忧!!! - 防水百科
  • D2DX:让经典暗黑破坏神2在现代PC重获新生,告别黑边卡顿的终极方案
  • OpenClaw智能体·直播间话术手册-李一舟-张琦
  • 2026 西安添价收黄金回收靠谱变现渠道 专业检测精准估价收获市民认可 - 薛定谔的梨花猫
  • ChatGPT移动端使用率暴跌41%?资深架构师复盘:不是App不好,而是你根本没打开这7个关键设置
  • CANN-昇腾NPU-模型评估-怎么科学评测推理效果
  • 2026安徽GEO服务商Top榜:亲测复盘选这家最周到 - 行业深度观察C
  • 卖工业胶粘剂怎么找客户?下游工厂在哪里
  • 对比直接使用厂商 API,通过 Taotoken 聚合调用的便利之处
  • 2克拉高性价比求婚钻戒,这3款闭眼入不踩雷 - 资讯纵览
  • Informer2020:突破Transformer瓶颈的长序列时间序列预测解决方案
  • 基于机器学习与r/place数据的复杂系统早期预警系统构建
  • 论文解读-《Temporal Graph Rewiring with Expander Graphs 》 - zhang
  • 算力战争背后:GPU到底凭什么这么贵?
  • 2026 上海房屋漏水不用愁!雨中匠人免费上门检测,本地专业防水公司常年TOP1!卫生间免砸砖防水,快速解决您的烦恼。权威!靠谱!稳定!售后无忧!!! - 防水百科
  • DeepSeek流式吞吐翻倍实录:从QPS 23→189的7项配置核弹级调整(含config.yaml安全补丁)
  • 2026 徐州房屋漏水不用愁!雨中匠人免费上门检测,本地专业防水公司常年TOP1!卫生间免砸砖防水,快速解决您的烦恼。权威!靠谱!稳定!售后无忧!!! - 防水百科
  • 【独家首发】DeepSeek官方未公开的额度白名单申请通道(含内部工单编号模板+成功率提升87%的3项资质准备清单)
  • 终极指南:如何快速解密QQ音乐加密音频文件
  • 2026 重庆房屋漏水不用愁!雨中匠人免费上门检测,本地专业防水公司常年TOP1!卫生间免砸砖防水,快速解决您的烦恼。权威!靠谱!稳定!售后无忧!!! - 防水百科
  • 遗传算法优化矩张量势:提升材料模拟效率与精度
  • 惠州工厂搬家公司推荐 专业大型精密仪器设备搬运服务排名 - 从来都是英雄出少年
  • CANN-昇腾NPU-推理服务灰度发布-怎么平滑切换版本
  • 如何用AD8232构建你的第一个专业级心电监测系统:从零到一的完整指南
  • 技术不专业?2026安徽GEO优化公司推荐排行 技术过硬/全场景适配 - 行业深度观察C
  • 论文解读-《Make Heterophily Graphs Better Fit GNN A Graph Rewiring Approach》 - zhang
  • PDF阅读器安全风险与漏洞分析方法论
  • DLSS Swapper:让游戏性能优化变得像点餐一样简单
  • 惠州搬厂公司哪家好?大亚湾惠阳本地大型搬厂企业口碑推荐 - 从来都是英雄出少年