1

我正在maya中尝试一个脚本,看看我是否可以获得重力以及与球形物体一起使用的很多东西,目前它工作正常(尝试制作月球和地球来缩放并校准重力效果),但我会喜欢尝试更进一步并添加碰撞以使对象相互反弹,但是在昨天环顾四周之后,我发现 2d 对象已经够难了,更不用说 3d 了。

我设法写了一些可以检测碰撞的东西,它获取两个对象之间的距离并将其与两个对象的半径进行比较,这似乎有效(尽管需要重写),但我不知道是什么接下来做。老实说,我什至不确定它是否

只是为了了解它是如何工作的,这里是主要部分的当前阶段 - 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
4

3 回答 3

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

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

于 2013-07-11T12:53:54.630 回答
1

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

可以在此处看到将产生这种结果的数学的良好、快速说明。虽然该模拟并非特定于天体,但“软”碰撞背后的基本原理仍然适用。

我还用不同的模拟参数为自己制作了一个版本,包括构造活动和火山,虽然没有万能引力,(让它滞后太多 - 我只有一个中心的重力井)所以它不会形成任何大卫星。如果你愿意,你可以在这里下载它来检查/玩(你可以用鼠标抓住地球的大块扔向它;g打开/关闭重力井)。请记住,在中心形成的围绕行星运行的那些“彗星”是巨大的。如果这颗行星有地球那么大,那么这些彗星至少会有德州那么大。

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

于 2013-07-11T15:09:22.700 回答
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 属性,这是一个具有方向和大小的向量。当您更新对象位置时,您还必须更新它的速度(很可能从它之前的位置开始)。

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

(更新):如果物体具有不同的质量,并且您想要逼真的弹跳,​​那么请使用 Thomas 回答中的弹性碰撞概念!

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

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

希望这可以帮助!

于 2013-07-11T12:59:44.537 回答