两个3d对象的碰撞方程

时间:2013-07-11 12:42:22

标签: python

我正在尝试玛雅的一个剧本,看看我是否可以获得重力和那个使用球形物体的那个,目前它工作正常(尝试制作月球和地球以扩展并校准重力效果),但我想尝试更进一步并添加碰撞以使物体互相反弹,但是在昨天看了好几年之后,我发现它很难用2d物体,更不用说3d了。

我设法编写了一个可以检测到碰撞的位,它可以获取两个对象之间的距离并将其与两个对象的半径进行比较,这似乎有效(虽然需要重写),但我无法弄清楚是什么做下一个。说实话,我甚至不确定是否有可能在没有一些高级大学知识的情况下做这样的事情,这就是我最终放弃的原因:P

只是想知道它是如何工作的,这里是主要部分的当前阶段 - objSel [j]是当前选择的对象,allObjects是除了当前所选对象之外的所有对象

def moveObjects(originalTime,objSel,objMultiplySize):
    moveAmounts = []
    crashed = False
    for j in range(len(objSel)):

        #get initial values
        originalVelocity = getVelocity(objSel[j],originalTime,objMultiplySize)
        objVolume = getVolume(objSel[j],objMultiplySize)
        allObjects = selectAllOtherObjects(objSel[j], objSel)

        #calculate gravity effect on object
        xDist = 0
        yDist = 0
        zDist = 0
        for i in range (0, len(allObjects) ):
            attraction = calcuateForce(objSel[j],allObjects[i],objMultiplySize)
            distanceFromObj = getDistance(allObjects[i],objSel[j],objMultiplySize)[1]
            xDist += distanceFromObj[0] * attraction / (objVolume*2.15*math.pi)
            yDist += distanceFromObj[1] * attraction / (objVolume*2.15*math.pi)
            zDist += distanceFromObj[2] * attraction / (objVolume*2.15*math.pi)
        gravityEffect = [xDist,yDist,zDist]
        newX = (originalVelocity[0]+gravityEffect[0])/objMultiplySize
        newY = (originalVelocity[1]+gravityEffect[1])/objMultiplySize
        newZ = (originalVelocity[2]+gravityEffect[2])/objMultiplySize
        newVelocity = [newX,newY,newZ]
        moveAmounts.append( newVelocity )



    #-----------this whole bit needs rewriting--------

    py.currentTime( originalTime + 1, edit = True, update = True)
    for j in range(len(moveAmounts)):

        #collision detection
        allObjects = selectAllOtherObjects(objSel[j], objSel)
        originalRadius = getRadius(objSel[j],objMultiplySize)

        for i in range (0, len(allObjects) ):
            objRadius = getRadius(allObjects[i],objMultiplySize)
            objDistance = getDistance(allObjects[i],objSel[j],objMultiplySize)
            if objDistance[0] < objRadius + originalRadius:
                force1 = moveAmounts[j][0]*objMultiplySize * objRadius
                print "Crashed"
                crashed = True

        if crashed != True:

            #move object
            py.move( objSel[j], float(moveAmounts[j][0]), float(moveAmounts[j][1]), float(moveAmounts[j][2]), relative = True )
            py.setKeyframe( objSel[j], attribute='translateX')
            py.setKeyframe( objSel[j], attribute='translateY')
            py.setKeyframe( objSel[j], attribute='translateZ')

        else:

            #dunno what to do here
            for i in range (0, len(allObjects) ):
                mass1 = getVolume(allObjects[i],objMultiplySize)
                velocity1 = getVelocity(allObjects[i],originalTime,objMultiplySize)
                mass2 = getVolume(objSel[j],objMultiplySize)
                velocity2 = getVelocity(objSel[j],originalTime,objMultiplySize)
                m1v1m2v2X = mass1*velocity1[0] + mass2*velocity2[0]
                m1v1m2v2Y = mass1*velocity1[1] + mass2*velocity2[1]
                m1v1m2v2Z = mass1*velocity1[2] + mass2*velocity2[2]
                totalMass = mass1+mass2

3 个答案:

答案 0 :(得分:2)

引用http://en.wikipedia.org/wiki/Elastic_collision

for i in range (0, len(allObjects) ):
                mass1 = getVolume(allObjects[i],objMultiplySize)
                velocity1 = getVelocity(allObjects[i],originalTime,objMultiplySize)
                mass2 = getVolume(objSel[j],objMultiplySize)
                velocity2 = getVelocity(objSel[j],originalTime,objMultiplySize)

                v1new = velocity1; //just initialization
                v2new = velocity2; //just initialization
                v1new[0] = (velocity1[0] *( mass1-mass2) + 2*mass2*velocity2[0])/(mass1 + mass2);
                v2new[0] = (velocity2[0] *( mass2-mass1) + 2*mass1*velocity1[0])/(mass1 + mass2);
                v1new[1] = (velocity1[1] *( mass1-mass2) + 2*mass2*velocity2[1])/(mass1 + mass2);
                v2new[1] = (velocity2[1] *( mass2-mass1) + 2*mass1*velocity1[1])/(mass1 + mass2);
                v1new[2] = (velocity1[2] *( mass1-mass2) + 2*mass2*velocity2[2])/(mass1 + mass2);
                v2new[2] = (velocity2[2] *( mass2-mass1) + 2*mass1*velocity1[2])/(mass1 + mass2);

假设弹性碰撞,您可以分别对每个维度进行碰撞计算。

答案 1 :(得分:1)

虽然托马斯的碰撞是一个很好的,简单的弹性碰撞方程,但在行星体的尺度上,没有弹性碰撞这样的东西。或者,我应该说,行星本身不会弹性碰撞。而不是将行星视为大型弹力球,更准确的类比是将它们视为大而droplets of water。虽然不完全相同,但水滴和行星碰撞时的相互作用方式有很多相似之处。

可以看到能够产生这种结果的数学的快速例证here。虽然这种模拟不是天体特有的,但“柔软”碰撞背后的基本原理仍然适用。

我也为自己制作了一个版本,它有不同的模拟参数,完整的构造活动和火山,虽然没有万有引力,(使它滞后太多 - 我只有一个重力井在中心)所以它赢了不会形成任何大卫星。你可以下载它来检查/玩here,如果你愿意的话(你可以用鼠标抓住行星的大块扔掉它; g 打开/关闭重力井)。请记住,围绕中心形成的行星绕行的“彗星”巨大。如果地球的大小与地球大小相同,那么这些彗星至少会与德克萨斯大小相当。

虽然我链接的两个模拟都是用java编写的,但是相同的数学和物理可以用于任何语言。

答案 2 :(得分:0)

首先,它似乎更像是一个数学问题,而不是一个python问题,因为相同的基本原理适用于任何语言。

其次,如果你的所有物体都是球形的,那么你不需要实际检测到真正的碰撞,但实际上只是检查物体中心之间的距离是否小于它们的半径之和。你可以使用这个函数快速获得这个距离(如果你的空间是欧几里德)(我在你的代码中没有看到):

def get_distance(obj1, obj2):
    # euclidean distance in three dimensions:
    return ( (obj2.x-obj2.x)**2 + (obj2.y-obj2.y)**2 + (obj2.z-obj2.z)**2 ) ** 0.5

现在,根据我的理解,你想要BOUNCE对象。根据定义,这要求对象具有VELOCITY属性,该属性是具有方向和大小的向量。更新对象位置时,还必须更新其速度(很可能是从其先前位置)。

最后,当你弹跳时,你必须考虑物体位置,它的速度矢量,以及指向它碰撞的另一个物体中心的归一化矢量。然后,你将执行一些矢量算术来获得它的新速度矢量。

(更新):如果对象具有不同的质量,并且你想要一个逼真的弹跳,​​那么在托马斯的回答中使用Ellastic Collision概念!

所以,作为进一步的研究“方向”,我建议:

  • 研究一些基本的矢量操作,特别是点积和交叉积(你会很高兴你在“得到”之后做过);
  • 强烈考虑使用Numpy,它以非常方便的方式实现向量和向量操作,这样你就不必实现很多东西,而且它比你手工完成的任何东西都要快。你不需要全部学习,只需要学会解决问题。

希望这有帮助!