两个三维对象的碰撞方程式



我正在maya中尝试一个脚本,看看我是否可以获得重力和大量处理球形物体的功能,目前它运行良好(尝试制作月球和地球来缩放并校准重力效应),但我想尝试更进一步,添加碰撞以使物体相互反弹,但在昨天环顾四周很久之后,我发现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

引用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);

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

虽然托马斯的碰撞是一个很好的、简单的弹性碰撞方程,但在行星体的尺度上,不存在弹性碰撞这回事。或者,我应该说,行星本身并没有弹性碰撞。与其把行星想象成大的弹性球,更准确的类比是把它们想象成大水滴。虽然不完全相同,但水滴和行星在碰撞时的相互作用方式有很多相似之处。

这里可以看到一个很好的、快速的数学说明,它将产生这样的结果。虽然这种模拟并不是针对天体的,但"黏糊糊"碰撞背后的基本原理仍然适用。

我还为自己制作了一个版本,带有不同的模拟参数,包括构造活动和火山,尽管没有普遍的重力,(这让它滞后太多了——我只有一个位于中心的重力井),所以它不会形成任何大卫星。如果你想的话,你可以下载它在这里检查/玩(你可以用鼠标抓住行星的碎片扔给它;g可以很好地打开/关闭重力)。请记住,那些围绕中心形成的行星运行的"彗星"是巨大的。如果这颗行星有地球那么大,那么这些彗星至少有德克萨斯州那么大。

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

首先,它看起来更像是一个数学问题,而不是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

现在,根据我的理解,你想要绑定对象。根据定义,这需要对象在任何时刻都具有VELOCITY属性,该属性是一个具有方向和大小的向量。更新对象位置时,还必须更新其速度(很可能是从其上一个位置开始)。

最后,当您反弹时,您必须考虑对象的位置、速度向量以及指向与其碰撞的另一个对象中心的归一化向量。然后,你可以执行一些矢量运算,得到它的新速度矢量。

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

因此,作为进一步研究的"方向",我建议:

  • 学习一些基本的向量运算,特别是点积和叉积(当你"得到"它后,你会很高兴你做了)
  • 考虑一下STRONGLY使用Numpy,它以一种非常非常方便的方式实现向量和向量运算,这样你就不必实现很多事情,而且它比你手工做的任何事情都快。你不必学习所有的东西,只需学习足够的东西来解决你的问题

希望这能有所帮助!

最新更新