首页 > 编程知识 正文

浅水方程,三叶玫瑰线的极坐标方程

时间:2023-05-05 16:19:06 阅读:127725 作者:1843

春水向量概述网格空间分割法小鼠服从tmddx奥利力

春水是一个由kinect和processing结合开发的小项目,灵感来自teamLab的Vortices。

在这个项目中,我负责的是跟随鼠标移动产生的粒子。

我们想传达的是,万物都是为别人而有意义的。 人不在的时候,春水只是一个池塘,但人不在的时候,春水开始变绿,起波澜。 人离开时,春水又恢复了寂静。

“当你没有看到这朵花的时候,这朵花会随你的心归于寂寞。 你来看这朵花的时候,我暂时知道了这朵花的颜色。 ”

概要

我们最初试图实现这样的效果,长期以来一直在讨论应该怎么实现。

第一版的想法是,人每次经过,都会产生与人的速度方向一致的粒子,粒子和粒子之间有相互作用力,相互影响。 由于规定新生成的粒子对现有粒子有很大的影响,所有粒子逐渐向与人一起行走的方向运动。

因此,此时我们重点实现的是网格空间分割法。

网格空间分割法正如《代码本色》的第6章集群中的思想一样,为了提高效率,采用了日本的网格空间分割法。

其思想是各个体周围一定范围内的个体会产生影响,传统上是在各个体更新时检测各个体与当前个体的距离,在距离小于一定值时考虑其影响。 但是,随着个体数的增多,存在复杂度呈指数级增加,效率低下的问题。

因此,采用网络空间分割法。

网络空间分割法将整个空间分割成一定大小的小网格,每个网格中的物体相互影响,网格与网格之间的物体不考虑它们的相互作用。

因此,为了计算附近个体之间的相互作用,每次更新时遍历所有物体,根据物体当时的位置分割为对应的网格即可。

void更新网格() { for } inti=0; i=yMax; I ) for(intj=0; j=xMax; j ) { grid[i][j].clear (; force grid [ I ] [ j ].set (0,0 ); } pvectorgridcount=newp vector (0,0 ); particle p : particles if (! p.isDead ()、gridcount=pvector.div ) p.getpos )、resolution ); 网格[ max (floor ) gridcount.y ),0 ) ] [ max (floor ) gridcount.x ),0 ) ].add(p ) p ); }}最后考虑各网格内个体的相互影响。

每个个体的速度是向量,可以在将这些向量相加的同时记录向量数之和,在计算出所有个体后,得到这些个体的速度之和,除以向量数,计算网格内所有个体的平均速度方向。

pvectorsumforce=newp vector (0,0; 浮动和=0.0f; for(intI=0; i=yMax; I ) for(intj=0; j=xMax; j ) sum force.set (0,0 ); sum=0.0f; if(grid[I][j].size(==0) continue; for(particlep:grid[I][j] ) sumforce.add(p.getvel ) ); sum=sum 1; } force grid [ I ] [ j ]=p vector.div (sum force,sum ); }遍历所有网格,并根据计算得到的每个网格中的力将其应用于网格中的每个个体。

在我们的系统中,粒子既想保持自己的运动,又想受到周围粒子的影响。 因此,我们的力由两部分组成,一部分是粒子自身的速度,另一部分是网格的平均速度。

通过对各个力施加一个权重并将其相加,得到受到周围个体影响的速度。

void applyGridForce () pvectorgridcount=newpvector ) ) 0,0 ); PVector force; particle p : particles if (! p.isDead ()、gridcount=pvector.div ) p.getpos )、resolution ); force=p vector.mult (force grid [ max (floor (grid count.y ),0 ) ],2 ); force.normalize (; p.applyforce(pvector.mult ) force,2 ); } } velocity=p vector.add (p vector.mu

lt(velocity, 0.7), PVector.mult(force, 0.3));

最后发现出来的结果与想象中并不一样,粒子不能很好跟随人的移动而移动。因此我们后来很快放弃了这个想法,重新写了一版主要依靠跟随鼠标移动轨迹来决定运动速度与方向的。

鼠标跟随

由粒子系统的文章中,我们可以得到完整的鼠标运动的轨迹,在这里我们需要让粒子根据鼠标移动而移动。

我们的方法是当粒子处于跟随状态时,对于其本身不设运动速度的向量,即不规定粒子本身的运动。而是根据粒子在鼠标轨迹之间的位置来确定其运动速度与方向。唯一粒子本身与运动

所以在粒子系统的控制类中,每次有粒子重生时随机选择重生的位置(见粒子系统),重生的位置用鼠标轨迹节点在ArrayList中的位置数代表。粒子重生在该节点位置,速度由此节点与下一节点之间的距离决定。

mouseCount = i; pos = mouseTrackList[mouseTrackCount].list.get(mouseCount).getPos(); speed = 8 - round(getInterval(mouseTrackCount, i).mag()/10);

由于我们想要粒子运动与鼠标运动相一致,鼠标运动快时粒子在这个区间运动也快,运动慢时粒子也随之缓慢运动。所以对于每个粒子不设置固定的速度,实时动态改变。
方法为当粒子在两个节点之间时,速度为节点A与节点B之间向量之差的1/speed,即speed次更新后粒子可以从A节点运动到B节点。

if(mouseTrackList[mouseTrackCount].list.size() > 0) { velocity = PVector.sub(mouseTrackList[mouseTrackCount].list.get(constrain(mouseCount + 1, 0, mouseTrackList[mouseTrackCount].list.size() - 1)).getPos(), mouseTrackList[mouseTrackCount].list.get(constrain(mouseCount, 0, mouseTrackList[mouseTrackCount].list.size() - 1)).getPos()); velocity.div(speed);

由于粒子通过两个节点之间的时间一定(speed次更新),所以增加一个更新次数计数器iCount,当iCount与speed - 1相等时,粒子从上一节点运动到下一节点,此时更新粒子当前在鼠标轨迹中的位置。

if(iCount++ == (speed - 1)) { iCount = 0; mouseCount++; } } else { velocity.set(0, 0); }

同时由于鼠标轨迹中中的节点会动态改变,因此要每次删除了鼠标轨迹中的节点时检测所有粒子的鼠标轨迹节点标号,使之也随之减一,保存相对不变。
(这里忍不住偷偷吐槽一句,一开始想着实现鼠标跟随非常简单,主要使用一个队列就可以了,没想到真正开始做时发现processing的数据结构里好像没有队列,只能自己用ArrayList来实现,而且也因为Java封装的问题,没有指针,所以代码写起来还是不太方便的)
在鼠标轨迹类中每次一个轨迹节点的生命周期结束,从轨迹ArrayList中移除时,将isRemoved信号置为true时,其余节点位置发生变动,因此要对所有Particle类中的粒子改变当前轨迹节点序号。

void update(PVector pos) { if(PVector.sub(pos, prevPos).mag() > 15) { add(pos); } prevPos = pos; isRemoved = false; for(int i = list.size() - 1; i >= 0; i--) { if(list.get(i).isDead()) { list.remove(i); isRemoved = true; } } } if(frameCount % 3 == 0) { updateGrid(); if(mouseTrackList[mouseTrackCount].isRemoved) { for(Particle p : particles) { if(!p.isDead()) p.mouseCount--; } } } tmddx奥利力

想要实现粒子运动时形成的旋涡的效果,讨论下来可能是模拟了洋流运动。当时查阅了很多资料,推测可能是受到tmddx奥利力影响。
然后我们得到了这样一个公式:

F= -2mω×v’

式中F为tmddx奥利力;m为质点的质量;v’为相对于转动参考系质点的运动速度(矢量);ω为旋转体系的角速度(矢量);×表示两个向量的外积符号(ω×v’:大小等于ω的大小乘以v的大小再乘以两矢量夹角的正弦值,方向满足右手螺旋定则)

当时看着这个公式,一筹莫展,以为是非常深奥的东西,不知道旋转系的角速度应该使用说明数值。到处去查资料,查到的都是物理题,ω使用的是标量0.0007292。又猜想可能与地球上的维度有关,不同维度对应的ω不同,可能会有一张对照表,但也没能查到具体的值。甚至当时在游戏群刚刚好有人上传了一份粒子做的河流模拟的源代码,观察demo后发现它也会形成漩涡后去下载了下来,仔仔细细通篇读了一遍,但也没有发现是怎样实现的。
后来失去耐心,随手填了几个数值,试出来发现ω可以是一个x、y都取0,z方向有值的向量。(现在突然意识到x、y有值也可以)然后突然想通,所谓科氏力实现的旋涡效果就是使粒子发生旋转,而发生旋转的关键在于旋转体系角速度ω与质点相对运动速度v’的叉乘,其他都只是起到确定力的大小的作用。
发现这一点时刚刚好上完将了向量叉乘与点积的互动媒体课,在高中第一次学向量时我就以为我听懂了,后来也数次重新觉得自己会了,而互动媒体课上看了视频的演示,重新有了新的认识,又以为自己是真真正正了解向量之间的运算了,但通过在春水中实现tmddx奥利力,才发现原来理解与使用还是有相当大的差距。

void applyCoriolisForce(){ float m = partSize; w = PVector.mult(direction, W); velocity.add(PVector.mult(w.cross(velocity), -2 * m)); }

版权声明:该文观点仅代表作者本人。处理文章:请发送邮件至 三1五14八八95#扣扣.com 举报,一经查实,本站将立刻删除。