重要说明:这个问题与“ PhysX”完全无关,后者是一个计算机游戏物理系统(用于诸如球类游戏等街机游戏中的物理);PhysX是Unity3D和其他游戏引擎的内置系统。PhysX与此处完全无关。
//////////////////// UPDATE(先读底)///////////////////////
我一直在记录值并搜索确切的问题在哪里,我想我找到了它。我的代码中有类似的内容
Velocity += Acceleration * Time.deltaTime;
position += Velocity * Time.deltaTime;
现在的加速度是0,0000000000000009 .. 随着代码的流动,速度会按照预期的速度增加,浮子没有问题。但是在开始时,地球的初始位置是(0,0,23500f)您可以在我最后给出的图表中看到。
好吧,现在当我将速度* timedelta(此时约为0,00000000000000005)添加到23500的位置时,基本上不会添加它。位置仍然是(0,0,23500)而不是(0,0,23500.00000000000005),因此地球不会移动,因此加速度不会改变。
如果我将地球的初始位置设置为0,0,0,并且仍然将加速度设置为0.0000000000000000009,以假设其位置为(0,0,23500),则“添加”速度* timedelta。它变成(0,0,000000000000000000005)并保持增加。当float为0时,添加如此小的值没有问题。但是,如果float类似于23500,则不会将小数值相加。
我不知道这到底是统一的问题还是c#的浮动。
这就是为什么我无法使其以较小的值起作用。如果我能克服这个问题,我的问题将得到解决。
//////////////////////////////////////////////////// //////////////////////////////
我一直在开发n体物理模型来模拟我们的太阳系,因此我一直在收集数据以使其尽可能逼真。但是数据大小有问题。我搜寻了互联网的每一个微小部分,却找不到一个能解释人们如何克服这一点的单一解释。(如果他们这样),所以我在这里尝试射击。
因此,为了保持行星之间的距离,半径和“质量”之比固定,我创建了一个Excel文件来计算所有数据。(因为为什么有人会在互联网上放“如果地球上有“那个”半径图”,地球将是什么?)我将附上ss。它从根本上“标准化”或换句话说“缩放”行星的每个属性到给定的参考。在这种情况下,我将其称为“地球半径”。
我团结一致,您知道,不能统一使用“太大”或“太小”的价值观。所以我不得不将太阳系缩小,“很多!”
因此,我使用牛顿万有引力定律F = GMm / r ^ 2来简化,我直接针对所有其他物体的给定物体计算a = GM / r ^ 2。
因此,地球引力加速度“朝着太阳”的真实值大约为0,000006 km / s ^ 2,这即使是一个很小的值,也可以统一使用,但它可以起作用。但是,要获得该值,1我需要将地球的半径(比例)设置为6371单位,将太阳的比例设置为696,342 !,这太大了,无法使其统一。
所以我说,让地球半径为1,以单位为单位。因此,当半径改变时,一切都改变了,质量,距离……我保持了行星的密度,并从具有新半径的新体积中计算出质量。所有计算都在附件中。
所以问题是,当我将地球半径设为1时,朝向太阳的重力加速度变为0,0000000000009之类的,这简直太小了。当然,Unity不能使用该值。
因此,如果我改为增加地球的半径,那么太阳的质量和半径会变得非常大,然后再一次,我将无法使用它。
我不知道其他人如何解决这个问题,他们如何解决这个问题,但是正如我从这里看到的那样,似乎无法对太阳系进行逼真的n体模拟。(至少一致)
所以我需要10位代表才能发布图片-_-,我会改为提供链接。http://berkaydursun.com/solar_system_simulator/data.PNG还有一个目录是使用n体计算但具有UNREALISTIC值的工作实验太阳系模拟。它运作良好,甚至看起来与真实情况都差不多,但是不,它没有正确的比率^^如果希望http://berkaydursun.com/solar_system_simulator/,可以在此处进行测试
编辑:哇,我几乎每个段落都以“ So”开头^^
我也做了程序溶胶系统仿真,所以这是我的见解:
渲染
我使用的OpenGL用1:1的比例。所有单位均为SI如此[M,S,公斤,...] 。问题开始于Z-buffer。通常的Z缓冲区宽只有16/24/32 bit
您所需要的。我正在从0.1m渲染到1000 AU,那么如何克服这个问题?
我确实通过同时结合Z排序和Z缓冲的3个平截头渲染来管理它(Z排序是必需的,因为透明环...和其他效果)。因此,首先我将最远的部分渲染到zfar=1000AU
。天顶投影到z=750AU
远处,然后清除Z缓冲区并渲染对象直到zfar=0.1AU
。然后再次清除Z缓冲区并渲染直到的关闭对象zfar=100000 m
。
为了完成这项工作,您必须拥有尽可能精确的投影矩阵。该gluPerspective
有unprecise cotangens所以它需要修复有关的元素(让我很长的时间来发现这一点)。Z near
值取决于Z缓冲区的位宽。如果编码正确,则即使缩放也能很好地工作10000x
。我从矿井主视图实时地将该程序用作矿井望远镜:)的对象导航/搜索器。我结合了3D星星,天体,船,真实地面(通过DTM和卫星纹理)。它甚至可以输出红蓝浮雕:)。可以从表面,大气,空间...(不仅限于地球)进行渲染。没有其他第三方库,则使用OpenGL。看起来是这样的:
As you can see it works fine on any altitude or zoom the atmosphere is done like this atmosphere scattering shader
simulation
I am not using n-body gravity simulation because for that you need a lot of data that is very very hard to get (and almost impossible in desired precision). The computations must be done very precisely.
I use Kepler's equation instead so see these:
If you still want to use gravity model then use JPL horizons from NASA. I think they have also source codes in C/C++ there but they are using incompatible reference frame with mine maps so it is unusable for me.
In general Kepler's equation has bigger error but it is not increasing with time too much. The gravity model is more precise but its error is rising with time and you need to update the astro body data continuously to make it work ...
[edit1] integration precision
your current implementation is like this:
// object variables
double acc[3],vel[3],pos[3];
// timer iteration
double dt=timer.interval;
for (int i=0;i<3;i++)
{
vel[i]+=acc[i]*dt;
pos[i]+=vel[i]*dt;
}
The problem is when you are adding very small and very big value then they are shifted to the same exponent before addition which will round off significant data To avoid this just change it to this:
// object variables
double vel0[3],pos0[3]; // low
double vel1[3],pos1[3]; // high
double acc [3],vel [3],pos [3]; // full
// timer iteration
double dt =timer.interval;
double max=10.0; // precision range constant
for (int i=0;i<3;i++)
{
vel0[i]+=acc[i]*dt; if (fabs(vel0[i]>=max)) { vel1[i]+=vel0[i]; vel0[i]=0.0; } vel[i]=vel0[i]+vel1[i];
pos0[i]+=vel[i]*dt; if (fabs(pos0[i]>=max)) { pos1[i]+=pos0[i]; pos0[i]=0.0; } pos[i]=pos0[i]+pos1[i];
}
Now xxx0
is integrated up to max
and the whole thing is added to xxx1
The rounding is still there but it is not cumulative anymore. You have to select max
value that the integration itself is safe and also the addition xxx0+xxx1
have to be safe. So if the numbers are too different for one spliting then split twice or more ...
xxx0+=yyy*dt; if (fabs(xxx0>max0))... if (fabs(xxx1>max1))...
[Edit2] Stars
[Edit3] Improving Newton D'ALembert integration precision even more
The basic problem with iterative integration is that applaying gravity based acceleration based on current body position will result in bigger orbits because durring integration step dt
the position changes a bit which is not accounted in the naive integration. To remedy this take a look at this picture:
Let assume our body is at circular orbit and in the 0 deg position. Instead of using acceleration direction based on current position I used position after 0.5*dt
. This augment the acceleration small bit resulting in much much higher precision (correspondence to Kepler orbits). With this tweak I was able to successfully convert from Kepler orbit into Newton D'Alembert for 2 body system. (doing this for n-body is the next step). Of coarse correlating with real data from our solar system is only possible for 2 body system not affected by tidal effects and or moons. To construct own fictional data you can use Kepler circular orbit and contripedal force equalizing gravity:
G = 6.67384e-11;
v = sqrt(G*M/a); // orbital speed
T = sqrt((4.0*M_PI*M_PI*a*a*a)/(G*(m+M))); // orbital period
其中a
,圆形轨道半径m
是体重,M
是焦点体重(太阳)。为了使精度保持在可接受的公差范围内(对我而言),集成步骤dt
应为:
dt = 0.000001*T
因此,要放置新的测试主体,只需将其放在:
pos = (a,0,0)
vel = (0,sqrt(G*M/a),0)
当主要焦点(太阳)位于:
pos = (0,0,0)
vel = (0,0,0)
这将使您的身体处于圆形轨道,因此您可以将开普勒与牛顿D'Alembert进行比较,以评估模拟的精度。
本文收集自互联网,转载请注明来源。
如有侵权,请联系[email protected] 删除。
我来说两句