You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何将弹簧质点系统布料的粒子投影到立方体表面?

立方体布料粒子碰撞投影实现方案

好问题!球体的碰撞投影确实省心,因为球面到中心的距离处处相等,但立方体的面是平面,每个轴方向的边界是固定范围,咱们得换个思路来处理。

首先假设你的立方体是轴对齐的(这是最常见的情况,毕竟你只给出了中心和边长),下面是具体的实现思路和代码:

核心思路

  1. 先计算立方体的边界范围:
    • 半边长 = 边长 / 2.0f,这是立方体中心到每个面的垂直距离
    • 最小边界:中心坐标在三个轴上分别减去半边长
    • 最大边界:中心坐标在三个轴上分别加上半边长
  2. 对每个粒子,先判断它是否在立方体内(x、y、z坐标都落在最小/最大边界之间)
  3. 如果粒子在内部,计算它到立方体6个面的距离,找到最近的那个面
  4. 将粒子沿着垂直于该面的方向移动,直到贴合到表面上

代码实现

和你之前的球体碰撞函数风格保持一致,代码如下:

void cubeCollision(const Vec3 center, const float sideLength) {
    float halfSize = sideLength / 2.0f;
    Vec3 minBounds = center - Vec3(halfSize, halfSize, halfSize);
    Vec3 maxBounds = center + Vec3(halfSize, halfSize, halfSize);

    for (auto& particle : particles) { // 用范围for更简洁,也可以保留你的迭代器写法
        Vec3 pos = particle.getPos();
        // 判断粒子是否在立方体内
        if (pos.x >= minBounds.x && pos.x <= maxBounds.x &&
            pos.y >= minBounds.y && pos.y <= maxBounds.y &&
            pos.z >= minBounds.z && pos.z <= maxBounds.z) {
            
            // 计算粒子到每个面的距离
            float distLeft = pos.x - minBounds.x;
            float distRight = maxBounds.x - pos.x;
            float distBottom = pos.y - minBounds.y;
            float distTop = maxBounds.y - pos.y;
            float distBack = pos.z - minBounds.z;
            float distFront = maxBounds.z - pos.z;

            // 找到最近的面(最小的距离)
            float minDist = std::min({distLeft, distRight, distBottom, distTop, distBack, distFront});

            // 将粒子偏移到最近的表面
            if (minDist == distLeft) {
                particle.offsetPos(Vec3(-distLeft, 0.0f, 0.0f));
            } else if (minDist == distRight) {
                particle.offsetPos(Vec3(distRight, 0.0f, 0.0f));
            } else if (minDist == distBottom) {
                particle.offsetPos(Vec3(0.0f, -distBottom, 0.0f));
            } else if (minDist == distTop) {
                particle.offsetPos(Vec3(0.0f, distTop, 0.0f));
            } else if (minDist == distBack) {
                particle.offsetPos(Vec3(0.0f, 0.0f, -distBack));
            } else if (minDist == distFront) {
                particle.offsetPos(Vec3(0.0f, 0.0f, distFront));
            }
        }
    }
}

注意事项

  • 这个代码默认立方体是轴对齐的,如果你的立方体是旋转过的(OBB),那需要用更复杂的碰撞检测方法(比如计算粒子到立方体每个面的距离,找到最近的面并投影),但这种情况需要额外提供立方体的旋转信息。
  • 如果你想优化性能,可以提前计算好minBounds和maxBounds,不用每次循环都重新计算(不过函数调用一次计算一次也没问题)。
  • 范围for循环for (auto& particle : particles)比迭代器写法更简洁,如果你习惯用迭代器,替换成原来的写法也完全可以。

内容的提问来源于stack exchange,提问作者Odai Mohammed

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.27 09:22:13