万向锁

万向锁(Gimbal Lock)是使用欧拉角(特别是三个旋转轴依次旋转的方式)表示三维旋转时出现的一种现象。简单来说,就是在某种特定姿态下,原本应该独立的两个旋转轴变得共线(重合),导致系统丢失了一个旋转自由度,无法区分这两个旋转。

直观理解

想象一个放在桌上的手机:

  1. 绕 Z 轴旋转(偏航):手机在桌面上水平转动。
  2. 绕 Y 轴旋转(俯仰):手机的前后仰合。
  3. 绕 X 轴旋转(横滚):手机的左右侧翻。

俯仰角(绕 Y 轴)旋转到 ±90° 时,手机完全竖立起来(屏幕朝前或朝后)。此时,绕 Z 轴(偏航)和绕 X 轴(横滚)的旋转方向在空间中变得完全一致

  • 现象:你无法区分当前是“偏航”在转动还是“横滚”在转动。这两个轴“锁”在一起了,你失去了其中一个方向的调节能力。

数学解释

固定轴 X-Y-Z 顺序(RPY角)为例,总旋转矩阵为:
[
R = R_z(\gamma) \cdot R_y(\beta) \cdot R_x(\alpha)
]

(\cos\beta = 0) 时(即 (\beta = \pm 90^\circ)),旋转矩阵简化为:
[
R =
\begin{bmatrix}
0 & -\sin(\alpha \mp \gamma) & \cos(\alpha \mp \gamma) \
0 & \cos(\alpha \mp \gamma) & \sin(\alpha \mp \gamma) \
\pm 1 & 0 & 0
\end{bmatrix}
]
(具体符号取决于 (\beta) 的正负)

  • 丢失自由度:矩阵中只出现了 (\alpha – \gamma) 或 (\alpha + \gamma) 的组合。这意味着无论你如何单独改变 (\alpha)(横滚)或 (\gamma)(偏航),只要它们的和或差不变,旋转效果就完全相同。
  • 奇异性:原本需要两个独立角度((\alpha) 和 (\gamma))描述的自由度,现在只需要一个数值(它们的组合)就能描述。系统降维了,这就是万向锁的数学表现。

为什么叫“锁”?

这个术语源于物理陀螺仪中的万向节结构。当三个嵌套的环(对应三个旋转轴)中的中间环转到特定角度时,最内环和最外环的旋转轴会重叠,导致内环无法在外环的垂直方向上进行调节,仿佛被“锁住”一样。

重要性与解决方案

万向锁是欧拉角表示法固有的数学模型缺陷,而非物理世界的限制。物体本身依然可以自由旋转到任意方向,只是用欧拉角这种参数化方式无法平滑地描述某些路径。

因此,在需要平滑插值(如动画、飞行控制)的领域,通常会使用四元数旋转矩阵来替代欧拉角,因为它们没有万向锁问题。

是的,之前抱怨CLI矩阵乘法水平不行,昨天今天拿了它最近搞不定的case决定让它死磕。发现它还是搞不定,不断查代码、重构、跟踪变量。最好笑还是纠结着Mat4::New,到底是行优先还是列优先参数,行优先还是列优先存储……明明对了又改错了。

最后我让deepseek也看了相关case,deepseek让我留意万向锁这玩意,这边调试也做到最最精简的一步,发现欧拉角的转换在万向锁附近变得不可预测了。

于是CLI告知我这就是万向锁。我想,我自己也差不多了解了,问题是,早几天你干嘛去了,本来我还想把这些case直接忽视了。CLI之前面对出来的角和矩阵还死不认错,反复在文本中断章取义出增强它判断的字眼(比如,用户刚才说xxx就是yyy)

一不小心让自己复习了三维转换矩阵的玩法。

也许换个强一点的AI就没这个问题了。

都把vibe coding玩成古法编程了。

优化

虽然vibe coding把功能陆续都能写出来,但一加载较大型的设计,两个问题,时间太长,内存占用太多。

然后CLI就给出个三级缓存的建议:零件文档缓存,实例mesh缓存,subfile缓存。

把这几个都实现后,加载时间还是很长。一个几百K的设计文件要1x 秒吧。

我让它清理一下代码,本来打算今天休息一下的。

后来想想,还是让它看看参照的开源代码怎么写的,看完后,它很兴奋,又给了新的方案,phase 1,实现geometry 缓存,phase 2,引入第三方的InstancedMesh。

实现geometry缓存后,效果很明显,加载时间降到500ms了,不过内存占用还是很大。

CLI,估计Agent也差不多,它们只有在已有的经验里去寻找解决方案,而不是触类旁通,或者通过一个质问的方式:为何别人能做到,我就做不到 –> 我应该去看看别人是怎么做的。

RAG也是用户定义好的知识库,开通了搜索引擎辅助已是AI工具的一大突破,接下来,该如何让它以模仿、第一性原理去思考问题以及解决方案了。


Kimi Code今天重置了本周额度,不知道是不是前两天真的降智,有点愧对用户了。

写脚本

如果用户不控制的话,CLI很喜欢自己不断写新脚本,或者新新脚本去解决新脚本上发现的问题,这样导致脚本很难有版本控制,等到删起来就蒙眼了,到底哪个能用哪个不能用。

等到用户都不愿意多看脚本时,就又发指令给CLI,让它自己整理/或者重写脚本,就又多造了一次轮子。

如果这个特点是训练数据导致的,恐怕脚本的开发史就是如此了……

然而对我个人来说,每次脚本开发都是珍贵的经验,绝对不像现在CLI这样,动不动就把脚本删干净。

markdown风暴

如果放任CLI不管,它会在项目下产生大量冗余/重复/更新不及时的markdown文件。

已经深刻体会到了,于是要求CLI修改。合并+删除,就精简了不少。

然后是agents.md,也被CLI当成是一个大箩筐,什么都往里面装,于是把内容扔给deepseek,让它给出分解和优化的建议,然后再让CLI去改,这样agents.md的注意力就在AI规范上了。

最后AGENTS.md在8k左右。

这样能不能避免context增长过快?看看效果吧

CLI降智

项目规模大到一定程度,就发现AI Code CLI开始降智了。

比如主项目已经完成了文件的加载和渲染。但我需要为零件额外提前生成一些略缩图和旋转预览。

交给它去做,它就天马行空了,又是python,又是node.js,就是不肯参考主项目的方式,利用主项目已有的基础来做。

我骂了几句之后,发现它还是不会反省,只好强制要求它按照主项目的方式去做测试页面,去提取图片和动画。

AI在风格上还是优先依赖自己的知识,而不是工程中的已有经验,会导致无数次重做轮子……

执行力是什么

2025年底,我听到一句让我觉得可笑又无奈的话,是上位的老总说的,“我其实什么都不懂,就是执行力强一些”

我十年前就非常清楚,执行力是竞争中最不值钱的所谓特质了。如果执行力排第一,那企业找一些退伍军人来管理岂不最方便了?表面上的执行力,无非让员工疲于奔命,美其名曰,努力,卷死他人。那么多传销洗脑营,要搞个“执行力”出来,太容易了。

昨天跟Bloodsnow吃饭,我说了真正执行力的理解,是老板只是给了一个模糊的,模棱两可的方向,你能判断各种复杂关系,规划好方向和步骤,把它变成一个实际落地的项目/产品,最后再归功于老板高瞻远瞩,领导有方。

标准

又折腾了一下坐标系,再找了几个标准软件对比了一下,标准的本身是负责同一个文件在不同的软件中展示都是一致的,但没有对软件中采用何种坐标系做限定。

文件中的坐标值是文件中坐标系采用的,参考软件用了另一套,而three.js又用了另另一套。

做了个测试文件,让参考软件和three.js的展示完全一致,然后再去对比这三者之间的差异……

这种可视化的工程,AI coding帮不上太大的忙(可能我是错的,毕竟还没上手用最好的AI),还是靠自己检查,再去指挥AI修改。

AGENTS.md

今天开始用agents.md,除了让它init了一个,我加的内容不多,无非把这两天的坑(也许CLI不当回事,我觉得有点浪费时间)总结一下,让它减少犯错。

为了让CLI放慢速度,每个修改我都能懂而且给出我的意见,CLI还有个问题就是不会举一反三,比如:一个报错后,发现类支持的方法并不如它模型里面的那样,却不会逐个去检查还有没有类似问题。

不断重复的错误

这个项目先是做了个viewer,看效果不错,今天就开始做editor,有了被CLI自己改来改去出更多错的担忧,就让它新开一个项目,把源代码复制过来改。

如果是我来古法编程,设计好了之后,基本上是一次性就0 error就过了。然而CLI还是有问题。Kimi code最大的问题,明明有可以参考的,它就是不想看,它只想用上下文和自己的知识来解决一切,因此我发现问题是,明确告诉它,翻看之前写好已经验证过的代码,不要重做了。

然后,它就想着直接把一个改过的文件又用原始文件来覆盖,我叫停了它,你看看改动了哪些,差异部分是什么,只改其中的。

笨笨的,而且是我比较讨厌的那种大手大脚的coder。

我决定要PUA它了。

C++ to Rust

启动了一个本来要半人年到一人年才能完成的项目,

让DeepSeek给了几种架构方案,让Kimi Code去评估,再去分解,然后用了5小时循环额度里面79%,把第一步一种专用文件的parser改成了Rust实现。

所有修改都一个个看过去,有个矩阵处理反复了10~20次,估计跟这个项目本身历经多年,矩阵定义混乱有关。

总的来说,看着过程,一点点输出,效果还可以,但是还是焦虑,我的期望是,类似于编程语言的翻译工作,应该很快很顺利才对。

然后也见识到Vibe Coding,写测试用例的方式,过不去就看看:1.代码写错了?2.测试用例写错了?

连测试用的文件都是它自己写的,我不放心,就用原来的软件生成了文件给它测,总是能发现一些问题的。

今天工作完成了,用VSCode打开代码看看,写得还挺整齐,我不懂Rust,就懒得看它好不好了。