我试图使用SDL2在C中制作一个基本的软体引擎.它的工作原理是考虑通过相同长度和刚度的弹簧(具有相同的弹簧常数k和长度natural_length)相互连接的软体的所有顶点.为了使其更逼真,我还介绍了阻尼常数c.
但是,我遇到了一个令人沮丧的问题.我一直试图调试它过去6-7个小时但无济于事.柔软的身体遇到许多奇怪的虫子,我不明白
>首先,“软体”根本不是“软”.每次都会变成一堆皱巴巴的点.我曾经尝试过只计算相邻点的力量,但它仍然变成了一个皱巴巴的混乱.
>即使我没有施加任何外力,柔软的身体每次都会飞到顶角(原点).
这张图片中都可以看到这两个错误 –
以下两个函数(它们与所有变量在同一个类中,因此不需要接受任何参数)是代码的实际模拟部分. (我已经省略了其余的代码,因为它是不必要的.)
我使用SDL_Points向量来存储Vector的每个点和向量来存储它们的速度.如果你想知道Vector是什么,它只是我创建的一个结构,只有2个浮点成员x和y.
accelePoints()函数为每个点指定速度和位置,并且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.
感谢您抽出时间来阅读!非常感谢帮助.
编辑
如果有人想测试它,则Here是整个代码.您需要SDL和’img’以及’img / point.bmp’中的’.bmp’文件夹’img’.
最佳答案 基于弹簧的软体模拟需要“静止配置”,其中在没有重力或其他外力的情况下,身体将保持内部静止.
模拟中的每个弹簧都需要自己的长度.共享的natural_length将导致弹簧在连接点之间的输入分离不同的体内施加力,这似乎导致您描述的问题.
从一组点生成软体(或“点斑点”)的典型方法如下所示:
>生成点集的Delaunay三角剖分(或3D中的四面体化).
>在三角测量的每个边缘上创建弹簧,使用边缘的长度作为弹簧的静止长度.
>模拟“重力”和其他外力!
为简单起见,您可以只连接所有点对,而不是生成三角测量.
模拟本身可以分三步执行:
>清除顶点力累加器
>将弹簧力添加到其连接的顶点
>更新每个顶点的速度和位置
根据您发布的代码的精神,Spring可能看起来像:
struct Spring
{
int point_index[2];
float rest_length;
};
在旁边
在你的代码中,你可以用d的单位长度图像替换t = atan2(d.y,d.x)和下面的sin(t)cos(t):
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);
您在计算力时正在改变顶点位置.