草庐IT

c++ - C++ 软体引擎

coder 2024-02-23 原文

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

有关c++ - C++ 软体引擎的更多相关文章

  1. ruby-on-rails - 如何优雅地重启 thin + nginx? - 2

    我的瘦服务器配置了nginx,我的ROR应用程序正在它们上运行。在我发布代码更新时运行thinrestart会给我的应用程序带来一些停机时间。我试图弄清楚如何优雅地重启正在运行的Thin实例,但找不到好的解决方案。有没有人能做到这一点? 最佳答案 #Restartjustthethinserverdescribedbythatconfigsudothin-C/etc/thin/mysite.ymlrestartNginx将继续运行并代理请求。如果您将Nginx设置为使用多个上游服务器,例如server{listen80;server

  2. ruby - 在没有 sass 引擎的情况下使用 sass 颜色函数 - 2

    我想在一个没有Sass引擎的类中使用Sass颜色函数。我已经在项目中使用了sassgem,所以我认为搭载会像以下一样简单:classRectangleincludeSass::Script::FunctionsdefcolorSass::Script::Color.new([0x82,0x39,0x06])enddefrender#hamlengineexecutedwithcontextofself#sothatwithintemlateicouldcall#%stop{offset:'0%',stop:{color:lighten(color)}}endend更新:参见上面的#re

  3. ruby-on-rails - Rails 中的推荐引擎 - 2

    我想为我的Rails网络应用程序提供推荐功能。特别是,我想向新注册的用户推荐他可能想要关注的其他用户。Rails中是否有用于此目的的引擎/gem?如果没有,我应该从哪里开始构建它?谢谢。 最佳答案 有Coletivogemhttps://github.com/diogenes/coletivo我试了一下。在MySQL上运行。Neo4jhttp://neo4j.org真的很容易实现一个“跟随谁”。事实上,大多数展示其能力的样本都涉及“跟随谁”。快速提示-只有在JRuby上运行时,Neo4j.rb才会很酷。如果不是-使用Neograph

  4. 世界前沿3D开发引擎HOOPS全面讲解——集3D数据读取、3D图形渲染、3D数据发布于一体的全新3D应用开发工具 - 2

    无论您是想搭建桌面端、WEB端或者移动端APP应用,HOOPSPlatform组件都可以为您提供弹性的3D集成架构,同时,由工业领域3D技术专家组成的HOOPS技术团队也能为您提供技术支持服务。如果您的客户期望有一种在多个平台(桌面/WEB/APP,而且某些客户端是“瘦”客户端)快速、方便地将数据接入到3D应用系统的解决方案,并且当访问数据时,在各个平台上的性能和用户体验保持一致,HOOPSPlatform将帮助您完成。利用HOOPSPlatform,您可以开发在任何环境下的3D基础应用架构。HOOPSPlatform可以帮您打造3D创新型产品,HOOPSSDK包含的技术有:快速且准确的CAD

  5. 叮咚买菜基于 Apache Doris 统一 OLAP 引擎的应用实践 - 2

    导读:随着叮咚买菜业务的发展,不同的业务场景对数据分析提出了不同的需求,他们希望引入一款实时OLAP数据库,构建一个灵活的多维实时查询和分析的平台,统一数据的接入和查询方案,解决各业务线对数据高效实时查询和精细化运营的需求。经过调研选型,最终引入ApacheDoris作为最终的OLAP分析引擎,Doris作为核心的OLAP引擎支持复杂地分析操作、提供多维的数据视图,在叮咚买菜数十个业务场景中广泛应用。作者|叮咚买菜资深数据工程师韩青叮咚买菜创立于2017年5月,是一家专注美好食物的创业公司。叮咚买菜专注吃的事业,为满足更多人“想吃什么”而努力,通过美好食材的供应、美好滋味的开发以及美食品牌的孵

  6. ruby - 使用 `+=` 和 `send` 方法 - 2

    如何将send与+=一起使用?a=20;a.send"+=",10undefinedmethod`+='for20:Fixnuma=20;a+=10=>30 最佳答案 恐怕你不能。+=不是方法,而是语法糖。参见http://www.ruby-doc.org/docs/ProgrammingRuby/html/tut_expressions.html它说Incommonwithmanyotherlanguages,Rubyhasasyntacticshortcut:a=a+2maybewrittenasa+=2.你能做的最好的事情是:

  7. UE4 源码阅读:从引擎启动到Receive Begin Play - 2

    一、引擎主循环UE版本:4.27一、引擎主循环的位置:Launch.cpp:GuardedMain函数二、、GuardedMain函数执行逻辑:1、EnginePreInit:加载大多数模块int32ErrorLevel=EnginePreInit(CmdLine);PreInit模块加载顺序:模块加载过程:(1)注册模块中定义的UObject,同时为每个类构造一个类默认对象(CDO,记录类的默认状态,作为模板用于子类实例创建)(2)调用模块的StartUpModule方法2、FEngineLoop::Init()1、检查Engine的配置文件找出使用了哪一个GameEngine类(UGame

  8. ruby - 如何计算 Liquid 中的变量 +1 - 2

    我对如何计算通过{%assignvar=0%}赋值的变量加一完全感到困惑。这应该是最简单的任务。到目前为止,这是我尝试过的:{%assignamount=0%}{%forvariantinproduct.variants%}{%assignamount=amount+1%}{%endfor%}Amount:{{amount}}结果总是0。也许我忽略了一些明显的东西。也许有更好的方法。我想要存档的只是获取运行的迭代次数。 最佳答案 因为{{incrementamount}}将输出您的变量值并且不会影响{%assign%}定义的变量,我

  9. arrays - Ruby 数组 += vs 推送 - 2

    我有一个数组数组,想将元素附加到子数组。+=做我想做的,但我想了解为什么push不做。我期望的行为(并与+=一起工作):b=Array.new(3,[])b[0]+=["apple"]b[1]+=["orange"]b[2]+=["frog"]b=>[["苹果"],["橙子"],["Frog"]]通过推送,我将推送的元素附加到每个子数组(为什么?):a=Array.new(3,[])a[0].push("apple")a[1].push("orange")a[2].push("frog")a=>[[“苹果”、“橙子”、“Frog”]、[“苹果”、“橙子”、“Frog”]、[“苹果”、“

  10. += 的 Ruby 方法 - 2

    有没有办法让Ruby能够做这样的事情?classPlane@moved=0@x=0defx+=(v)#thisiserror@x+=v@moved+=1enddefto_s"moved#{@moved}times,currentxis#{@x}"endendplane=Plane.newplane.x+=5plane.x+=10putsplane.to_s#moved2times,currentxis15 最佳答案 您不能在Ruby中覆盖复合赋值运算符。任务在内部处理。您应该覆盖+,而不是+=。plane.a+=b与plane.a=

随机推荐