C3DynamicBone重力效果预览工具
目标是在 3ds Max 中用 MaxScript 实现Unity C3 DynamicBone 动态骨骼计算效果,可把继续结果烘焙为普通关键帧;同时提供不写关键帧的视口实时预览。重点是阻尼、弹性、刚性、惯性、碰撞摩擦与粒子半径的沿链分布曲线,以及 Gravity、Force、风和质量等整体参数。用于观察Unity中的模拟效果,特别是添加重力,外力的效果。
[!NOTE] 受3dsmax单线程影响,当有视口操作时(移动选择物体等),UI插件等都会暂停更新,导致实时预览效果也会暂停计算。所有做不到类似Unity中移动物体就有动态效果,只能移动结束后出现动态效果。
# 使用
# 修改3dsMax 浮点数显示精度
如下图设置,增加到显示 小数点后 5 位数。否则导入 unity 配置时,数值不对。
# 添加 骨骼链 的第一节骨骼 :如下图
# 模拟
添加第一节骨骼后,可直接点击 【烘焙模拟】或者【实时预览】即可创建参考的Box骨骼链 。
【清理】是删除掉参考的 Box骨骼链。
# 导入unity 的配置
🔔
可直接把Unity中配置好的 动态骨骼参数导入。先在 unity 中保存 配置(注意配置只能保存在unity项目路径下),然后在3dsMax 导入。
# 1.1 获取插件
使用天晴盒子安装器下载 - C3_Export_Script , NDBoxList 两个资源包。如下图。
插件本体路径:\scripts\NDTools\C3S3\C3DynamicBone_OfflineBake.ms
# 项目源码调研结论
C3DynamicBone 源码不在 /MYResources/Release/JTMY_Editor (opens new window) 项目中,需要请联系:王熠中(806098)
# 1.1 已确认的 C3 算法实现
用户提供的源码目录包含 C3DynamicBone.cs 及 partial 扩展文件,因此现在可直接确认 C3 的核心粒子更新,而不只限于 Inspector 参数:
- 粒子树逐骨骼建立,记录当前/上一位置、父粒子、累计骨长、原始动画局部位置及动态矩阵;排除节点可由虚拟末端封闭分支。
- 分布曲线用
累计 BoneLength / BoneTotalLength采样;Additive Elasticity、Damping、Elasticity、Stiffness、Inert、Friction、Radius 都是基础值乘曲线倍率,参数随后钳制到 0–1,Radius 最小为 0。[C3DynamicBone.cs]( Prepare()采样对象位移、粒子动画姿势、风和碰撞体;角度限位绑定/同步在准备末尾进行。- 局部风算法可见:3 个 Cosine 脉冲混合;风力与 speed²、pulse、drag 相乘;粒子外力位移再乘
0.5 / mass × timeVar²。 - 角度限制提供 Swing1/Swing2 的 Free/Limited/Locked 模式,并把粒子方向约束在 pivot 坐标空间的近似锥体/轴角范围内。
- S3 与 C3 的积分主干和约束顺序高度相似,可作为交叉核对;实现差别包括 C3 的 Additive Elasticity、风、全局重力及角度限位。
# 1.2 仍需明确的复刻边界
算法公式已能从指定源码目录确认,但 MaxScript 复刻仍不是完全无歧义的数值移植:Unity 的单位换算、C3 坐标轴约定、Max 的场景帧率/动画控制器求值、负缩放和矩阵语义需单独映射。
# 数据模型
# 2.1 骨骼树与粒子
每个参与模拟的骨骼节点建立一个粒子,另为叶节点可选建立虚拟末端粒子。节点记录:
node:目标骨骼节点;parentIndex:父粒子索引。pos、prevPos:当前及前一子步的世界空间位置。sourceTM:当前采样时刻原始动画骨骼的世界变换;不能被模拟结果覆盖。restLocalPos /restLocalTM:骨骼在父节点空间中的局部偏移/姿势。restLength:C3 在每次约束更新时从当前动画父子世界位置计算;虚拟末端由当前动画矩阵变换 EndOffset 得出。为严格对齐应逐步重算,固定初始长度是 Max 插件可选的稳定化改动,会改变动画缩放时的结果。distanceFromRoot、u:累计链长及归一化位置,用于参数分布。- 参数实例:各基础值乘分布曲线后的粒子值。
- 可选
isVirtualEnd:末端虚拟粒子不直接写回节点,只用于决定末段骨骼朝向。
采用“原始骨架只读采样 → 代理 Helper 链求解 → 独立输出骨架烘焙”的结构。原始动画骨架只提供每个模拟子步的动画姿势、局部偏移和变换矩阵,禁止被求解结果覆盖;每个参与模拟的骨骼对应一个代理 Helper(如 Point/Dummy),用于承载粒子位置及求解状态(pos、prevPos、父子索引等),也可为末端创建虚拟 Helper。Helper 的父子层级便于检查链结构,但求解器仍应显式维护粒子状态、动画目标和骨长约束,不能仅依赖 Max 的层级变换传播。
每个子步先采样原始骨架,再驱动代理链完成弹性、惯性、重力、碰撞和骨长约束;求解结束后由粒子位置还原骨骼姿势并烘焙到重复骨架或专用输出控制器。
不要让代理 Helper 反向驱动原始输入骨架,否则会形成反馈或污染后续动画采样。
# C3 参数语义和分布曲线
构建 u_i = clamp(BoneLength_i / BoneTotalLength, 0, 1),其中 BoneLength 是根到粒子的累计长度,BoneTotalLength 是该 ParticleTree 的最长累计长度。曲线纵轴是倍率,不是最终参数值;同树分支共享归一化分母,多 Root 各自建立树并独立归一化,u=0 在根部、u=1 在最长末端。
MaxScript 中以曲线关键点数组表示分布:[(u0, value0), ...],按 u 排序,段内采用线性插值起步。若用户需要平滑形状,再支持每个关键点入/出切线的三次 Hermite 插值;不要依赖当前场景里的动画 Curve 控制器作为隐式输入,保证参数可序列化、可复算。无曲线或空曲线时倍率为 1。曲线采样值可超出 0–1,但最终参数仍按参数类型钳制;Radius 最小为 0。
参数 | C3 实际作用 | 取值/备注 |
|---|---|---|
Damping | 衰减 Verlet 历史位移(速度);值越大越快停止 | 0–1 |
Elasticity | 将粒子向由父粒子动态位置与当前动画局部偏移构成的 restPos回拉;每步乘Elasticity_i × timeVar | 参数曲线结果 clamp 0–1 |
Stiffness | 通过限制粒子离 restPos的最大偏移实现;maxOffset = restLength × (1 - effectiveStiffness) × 2 | 参数曲线结果 clamp 0–1; effectiveStiffness = lerp(1, Stiffness_i, BlendWeight) |
Inert | 仅首个模拟 loop 将角色位移乘以惯性系数加到预测位移,并同步偏移 prevPos | 参数曲线结果 clamp 0–1 |
Friction | 粒子上一约束阶段发生碰撞后,在下一次预测中加到 Damping,再将总阻尼封顶为 1 | 参数曲线结果 clamp 0–1 |
Radius | 粒子碰撞球半径;碰撞时乘对象缩放 | 参数曲线结果 clamp 到非负 |
Gravity | 局部重力先扣除沿静止重力方向的投影分量,再与 Force相加,乘objectScale × timeVar;它不是直接套用标准g × dt² | 向量;需按 C3 坐标与缩放语义映射 |
Force | 与有效 Gravity相加后按objectScale × timeVar加到粒子位置 | 向量;源码按该位置增量实现 |
Additive Elasticity | 仅首个模拟 loop 中,向父粒子的上一动态矩阵变换当前骨骼局部偏移所得目标回拉 | 参数曲线结果 clamp 0–1;乘 timeVar |
Blend Weight | 通过 lerp(1, Stiffness_i, BlendWeight)调制刚性;不是所有输出变换的通用混合权重 | 0–1 |
Local Wind | 全局风恒参与;开启局部风时将局部方向转换到世界空间后相加;粒子外力位移为 windForce × 0.5 / mass × timeVar² | 风场向量由脉冲模型计算 |
Mass | 仅用于缩放风的外力位移,除数形式 | > 0 |
Drag | 在风力公式中直接作为乘数系数,不是相对风速阻力项 | 非负 |
参数值和曲线由 C3DynamicBoneMaterial 覆盖时优先读取材质;例如阻尼、附加弹性、弹性、刚性、惯性、摩擦、半径及其曲线可以来自材质,Gravity、BlendWeight、质量、Drag 和风不走这些粒子材质 getter。
