news 2026/10/27 1:36:11

63只昆虫共用的建模地基:insect-world放样(loft)工具箱深度解析

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
63只昆虫共用的建模地基:insect-world放样(loft)工具箱深度解析

【免费下载链接】insect-world

Interactive 3D insect field guide: 63 species across 14 orders, every body procedurally generated in the browser with TypeScript + Three.js — no model or texture files in the repo. Eight species step through a full life cycle; the hoverers beat their wings.

项目地址:https://gitcode.com/gh_mirrors/in/insect-world
点击查看免费下载

insect-world 是一个零模型文件的交互式 3D 昆虫图鉴:63 种昆虫、14 个目,全部由 TypeScript + Three.js 在浏览器里实时程序化生成。而所有虫体的几何,几乎都架在一套自研的放样(loft)建模工具箱之上——一个 1400 来行、住在 src/three/builders/kit.ts 里的文件。本文带你读懂这套地基是如何"以点建面、以面成虫"的。

为什么是放样?3D 程序化建模的最优解

先说结论:仓库里没有一个.glb模型文件,也没有一张贴图文件。每一只虫都是从"一串截面参数"现场算出来的网格(BufferGeometry)。

这带来两个好处:

  • 体积归零:63 种虫 + 18 个生活史阶段(卵/幼虫/蛹/若虫),全部几何都来自代码,仓库几乎不含二进制资产;
  • 参数可复用:画成虫的同一套代码,换个参数就能画出卵、幼虫和蛹。

实现路径很直白:昆虫身体(躯干、鞘翅、角、腿节、触角节)本质上都是**"沿一条路径,截面从粗变细再闭合"的管状体**——这正是放样(lofting)的经典定义。项目把这套算法做成了loft()一个函数,再在它上面搭了spindle()、segmentedAbdomen()、leg()、antenna()等十几个"高级积木"。63 只虫,都是积木的排列组合。

放样核心:loft()的四个关键设计

核心函数在 src/three/builders/kit.ts。输入是一组截面(Section),输出是一个封闭的网格:

export interface Section { at: THREE.Vector3 | [number, number, number] // 截面中心 ry: number // 上下半径(Y 方向) rz: number // 左右半径(Z 方向) roll?: number // 绕路径切线的扭转(弧度),默认 0 }

截面:把虫体抽象成"一串椭圆环"

每个截面就是"路径上某一点的一个椭圆"。把 20 个截面串起来,就是一段身体;ry/rz不等就得到扁截面——独角仙那片"外侧高、内侧低"的半个穹顶鞘翅,就是这么压出来的(见 src/three/builders/rhinoceros-beetle.ts)。

平行传输:防止截面沿路径"打转"

最容易翻车的地方:相邻截面如果各自随意定向,细长的身体会像麻花一样扭起来。loft()的解法是切线定向 + 平行传输——先求每个截面处沿路径的切线tangent,再用上一段的参考向量推当前截面的横向标架(kit.ts#L392-L406)。这个设计还有一个隐性红利:它只依赖差值向量,所以整条腿平移到哪儿,放样结果都不变——这正是后来"腿部骨架化"(62 只虫同时学会走路)能成立的前提。

法线与封口:细节决定"像不像"

  • 椭圆法线按半径倒数加权:扁截面的法线若按圆算,侧光下会发暗失真(kit.ts#L418-L422);
  • 极点封口:首尾截面收到一个极点(半径 0 的截面自动退化成尖),一头一尾各补一个顶点就封好了(kit.ts#L436-L450)。

地基之上:63 只虫共享的"放样积木"

loft()本身是毛坯,真正的生产力来自包在它外面的参数化部件——物种文件只需给"尺寸 + 颜色 + 姿态":

函数一句话职责位置
loft()核心:一串椭圆截面 → 封闭网格kit.ts#L379
spindle()纺锤体:两端收尖的椭球,昆虫的头、胸、腹节几乎都是它kit.ts#L470
segmentedAbdomen()分节腹部:带环沟起伏的体节,蜂/蚁/蜻蜓腹部的辨识点kit.ts#L559
leg()/legPair()四段嵌套关节的昆虫足,62/63 个物种共用kit.ts#L718
antenna()六种触角类型:丝状、棒状、膝状、鳃叶状、栉齿状、刚毛状kit.ts#L882
wingVeins()扇形放射的翅脉细管——鉴定"目"级别的关键特征kit.ts#L1057
chitin()/elytra()/membrane()几丁质、鞘翅釉质、膜翅三档材质kit.ts#L244
finalize()收尾:居中、开阴影、算取景半径、收集可动骨架kit.ts#L1293

以独角仙为例,它的构建只有四步:spindle()画腹部和前胸 → 22 个截面loft()出两片隆起鞘翅 →antennaPair()加鳃叶状触角 →finalize()收尾(src/three/builders/rhinoceros-beetle.ts)。把同样的四步换个参数,就换了一只虫——这就是"地基"的威力:改loft()一处,63 只虫同时受益;加一只新虫,只写参数。

健壮性保证:让放样工具永不出 NaN

放样工具箱的地基测试(src/three/builders/tests/kit.test.ts)专门钉死了几类最容易炸的退化输入:

  • 路径首尾重合:切线方向退化 → 强制兜底轴,不产生NaN;
  • 竖直路径:参考向量与切线平行时自动换轴;
  • 零半径截面:尖端退化不炸;
  • 扁截面法线:逐顶点断言仍是单位向量;
  • 输入不足 2 个截面:直接抛错,而不是静默产出坏几何。

这种"退化输入逐个钉死"的思路,加上全项目 4000 多个测试,构成了"所有物种都建在 loft 之上,这里出问题就是全线崩"的防线。

贴图也是"放样"出来的?零文件表面细节

顺带一提,表面微观层同样零文件:src/three/builders/surface.ts 用 Canvas 2D 在运行时现画刻点(甲虫头部的随机圆坑)与纵沟纹(鞘翅上的平行沟槽)法线图,种子化 PRNG 保证任何机器上生成同一张图。几何放样负责"形状",程序贴图负责"质感",两者合起来才是这只虫。

总结:一个 loft 函数,撑起一座昆虫馆

insect-world 的放样工具箱给"3D 程序化建模"提供了三个可直接抄作业的启示:

  1. 先做地基,再做生态:把loft()的边角情况全部钉死后,上层 63 个物种文件几乎不再写几何算法;
  2. 参数即物种:形态差异全部收敛为参数(半径曲线、扁度、姿态角),代码结构完全同构;
  3. 测试即门禁:退化输入、镜像对称、姿态不变性都有测试守着,"悄悄改坏"无处遁形。

想自己动手?按这个顺序读源码最省力:src/three/builders/kit.ts 的loft()→spindle()→leg(),再挑 src/three/builders/ladybird.ts 或 src/three/builders/rhinoceros-beetle.ts 看一只虫的完整装配,最后翻翻 docs/roadmap.md 了解这座昆虫馆是怎么一路扩建到 63 种的。

【免费下载链接】insect-world

Interactive 3D insect field guide: 63 species across 14 orders, every body procedurally generated in the browser with TypeScript + Three.js — no model or texture files in the repo. Eight species step through a full life cycle; the hoverers beat their wings.

项目地址:https://gitcode.com/gh_mirrors/in/insect-world
点击查看免费下载

相关推荐

上一篇:Mac用户必备:3步解密QQ音乐加密格式,让音乐自由播放
下一篇:芋道源码企业级框架终极实战指南:5个高效开发技巧构建完整Spring Boot应用

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/10/27 1:33:57

【机械制图与CAD实战(二十九)】弹簧的表示方法

弹簧是用途极广的零件,可以用于机械的运动控制、减震、夹紧、测力和储能等。 l弹簧的种类繁多,有螺旋弹簧、蝶形弹簧、平面蜗簧、板弹簧等。螺旋弹簧螺旋弹簧又有压缩螺旋弹簧、拉伸螺旋弹簧、扭转螺旋弹簧。1、圆柱螺旋压缩弹簧的各部分名称及尺寸关系…

作者头像 李华
网站建设 2026/10/27 1:30:37

AdGuardHome 端口冲突快速搞定:53 与 3000 默认端口一次改对

AdGuardHome 端口冲突快速搞定:53 与 3000 默认端口一次改对 【免费下载链接】AdGuardHome Network-wide ads & trackers blocking DNS server 项目地址: https://gitcode.com/gh_mirrors/ad/AdGuardHome 刚部署 AdGuardHome 时最常见的报错就是 address…

作者头像 李华
网站建设 2026/10/27 1:28:40

Java SE基础语法>>数据类型与变量

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/10/27 1:28:33

OpenWorkBuddy拆解:Agent Harness如何让LLM输出可验收

1. 为什么"调通API"和"交付一份产物"之间隔着一条河过去大半年,我一直在折腾各种LLM落地项目,最深的感受是:让模型吐出一段话很容易,但让它稳定地产出一份"能直接交给上级、发给客户、归档入系统"的…

作者头像 李华
网站建设 2026/10/27 1:28:04

基于Springboot培训机构业务管理系统【附源码+文档】

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华