我正在尝试使用 SDL2 用 C++ 制作一个基本的软体引擎。它的工作原理是考虑软体的所有顶点都由相同长度和刚度的弹簧互连(具有相同的弹簧常数
k
和长度 natural_length
)。为了让它更真实,我还引入了阻尼常数c
。
然而,我遇到了一个令人沮丧的问题。过去 6-7 个小时我一直在尝试调试它,但没有成功。软体遇到很多奇怪的我不明白的bug
这两个错误在此图片中都可见:
以下 2 个函数(它们与所有变量属于同一类,因此不需要接受任何参数)是代码的实际模拟部分。 (我省略了其余的代码,因为它是不必要的。)
我使用
vector
的 SDL_Points
来存储每个点,并使用 vector
的 Vector
来存储它们的速度。如果您想知道 Vector
是什么,它只是我创建的一个 struct
,它只有 2 个 float
成员 x
和 y
。
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
和弹簧常数 k
的值分别为 0.5、10 和 100。
这里是完整的代码。您需要 SDL 和一个文件夹“img”,其中“img/point.bmp”中有一个“.bmp”文件。
基于弹簧的软体模拟需要“静止配置”,其中没有重力或其他外力,身体将保持内部静止。
模拟中的每个弹簧都需要有自己的长度。共享的
natural_length
将导致弹簧在体内施加力,其中连接点之间的输入间隔不同,这似乎是导致您描述的问题的原因。
从一组点生成软体(或“点斑点”)的典型方法如下所示:
为简单起见,您可以仅连接所有点对,而不是生成三角剖分。
模拟本身可以分三个步骤进行:
本着您发布的代码的精神,
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);
您在计算力时改变了顶点位置。