gpt4 book ai didi

c++ - C++ 软体引擎

转载 作者:塔克拉玛干 更新时间:2023-11-03 02:09:29 24 4
gpt4 key购买 nike

我正在尝试使用 SDL2 在 C++ 中制作一个基本的软体引擎。它的工作原理是考虑软体的所有顶点都由相同长度和刚度的 Spring 互连(具有相同的 Spring 常数 k 和长度 natural_length)。为了让它更真实,我还引入了一个阻尼常数c
但是,我遇到了一个令人沮丧的问题。在过去的 6-7 个小时里,我一直在尝试调试它,但无济于事。软体遇到很多不明白的奇葩bug

  • 首先,“软体”一点也不“软”。每次都变成一团皱巴巴的点。我试过只计算相邻点的力,但它仍然变得一团糟。
  • 即使我没有施加任何外力,软体每次都会飞到顶角(原点)。

这两个错误都在此图像中可见 - bug

以下两个函数(它们与所有变量都在同一个类中,因此不需要接受任何参数)是代码的实际模拟部分。 (我省略了其余的代码,因为它是不必要的。)
我使用 SDL_Pointsvector 来存储每个点,并使用 Vectorvector 来存储它们的速度。如果您想知道 Vector 是什么,它只是我创建的一个 struct,它只有 2 个 float 成员 xy
acceleratePoints() 函数为每个点分配速度和位置,checkCollision() 嗯...检查与宽度为 的窗口壁的碰撞scr_w 和高度 scr_h

    void acceleratePoints()
{
vector<SDL_Point> soft_body_copy=soft_body;
vector<Vector> velocity_copy=velocity;
for(int i=0;i<soft_body.size();++i)
{
for(int j=0;j<soft_body.size();++j)
{
if(i!=j)
{
Vector d={(soft_body[j].x-soft_body[i].x)/100.0,(soft_body[j].y-soft_body[i].y)/100.0};
float t=atan2(d.y,d.x);
float disp=fabs(magnitude(d))-natural_length/100.0;
velocity_copy[i].x+=(k*disp*cos(t))/10000.0;
velocity_copy[i].y+=(k*disp*sin(t))/10000.0;
velocity_copy[i].x-=c*velocity_copy[i].x/100.0;
velocity_copy[i].y-=c*velocity_copy[i].y/100.0;
soft_body_copy[i].x+=velocity_copy[i].x;
soft_body_copy[i].y+=velocity_copy[i].y;
}
}
soft_body=soft_body_copy;
velocity=velocity_copy;
}
}
void checkCollision()
{
for(int k=0;k<soft_body.size();++k)
{
if(soft_body[k].x>=scr_w||soft_body[k].x<=0)
{
velocity[k].x*=e;
soft_body[k].x=soft_body[k].x>scr_w/2?scr_w-1:1;
}
if(soft_body[k].y>=scr_h||soft_body[k].y<=0)
{
velocity[k].y*=e;
soft_body[k].y=soft_body[k].y>scr_h/2?scr_h-1:1;
}
}
}

magnitude() 函数返回一个Vector 的大小。
我用于图像的恢复系数 e、阻尼常数 c 和 Spring 常数 k 的值分别为 0.5、10 和 100 .感谢您抽出时间来阅读!将不胜感激。

编辑

Here是完整的代码,如果有人想测试的话。您将需要 SDL 和文件夹“img”,其中包含“img/point.bmp”中的“.bmp”文件。

最佳答案

基于 Spring 的软体模拟需要一个“静止配置”,其中没有重力或其他外力, body 将保持内部静止。

模拟中的每个 Spring 都需要自己的长度。共享的 natural_length 会导致 Spring 在 body 内施加力,连接点之间的输入间隔不同,这似乎是导致您描述的问题的原因。

从一组点生成软体(或“点 blob”)的典型方法如下所示:

  • 生成点集的 Delaunay 三角剖分(或 3D 中的四面体化)。
  • 在三角剖分的每条边上创建 Spring ,使用边的长度作为 Spring 的静止长度。
  • 模拟“重力”和其他外力!

为简单起见,您可以只连接所有点对,而不是生成三角剖分。

模拟本身可以分三个步骤执行:

  • 清除顶点力蓄能器
  • 将 Spring 力添加到它们连接的顶点
  • 更新每个顶点的速度和位置

按照您发布的代码的精神,Spring 可能如下所示:

struct Spring
{
int point_index[2];
float rest_length;
};

放在一边

在您的代码中,您可以替换 t = atan2(d.y, d.x) 和以下 sin(t) cos(t)带有 d 的单位长度图像:

float mag_d = magnitude(d); // should not become negative...
float r = (0.0f != mag_d) ? 1.0f/mag_d : 0.0f;
Vector d_hat{d.x*r, d.y*r};
float w = k * (mag_d - spring[i].rest_length);
velocity_copy[i].x += w*d_hat.x;
velocity_copy[i].y += w*d_hat.y;

没有完全优化,只是更稳定了一点。

编辑

我还注意到您正在缩放剩余长度(将其除以 100)。不要那样做。

另一个编辑

改变这个:

    }
soft_body=soft_body_copy;
velocity=velocity_copy;
}

对此:

    }
}
soft_body = move(soft_body_copy);
velocity = move(velocity_copy);

您在计算力时改变了顶点位置。

关于c++ - C++ 软体引擎,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/29129467/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com