边界顶点固定盒

——译ZH1110

 

  为什么我选择顶点固定取代传统的 ODE 求解? 因为它更加简单并稳定。 使用 ODE 技术你必须用微积分在给定的时间间隔后计算出对象新的位置。用顶点固定则意味着通过时间间隔前后的位置得到结果,它是一种速度的近似计算 .

在真实的 3D 对象中使用顶点固定,他们被一定长度的杠杆限制在一起。用数组你可以建立盒子,三角椎,等其他杠杆组成的外形.


这是我首先建立的简单的盒子。8个质点成为角落,12个杠杆为边。但是用12个杠杆它不能很好的站立,所以我们要加入交叉的杠杆,象这样:

现在看一下他们是如何组合在一起的。顶点固定法代码;

Public num_particles As Integer
Public num_join As Integer
Public join_p1(1000) As Long
Public join_p2(1000) As Long
Public join_rl(1000) As Long

Public m_curp(1000) As D3DVECTOR
'当前位置
Public m_oldp(1000) As D3DVECTOR
'旧的位置
Public m_forc(1000) As D3DVECTOR
'力
Public m_grav As D3DVECTOR
'重力(还可用于风,或飘动的影响)
Public m_timeStep As Double
'时间间隔
Public Function TimeStep()
    '这里完成当前时间间隔必要的物理计算计算,
    AccumulateForces
    Verlet
    SatisfyConstraints
End Function

Private Function Verlet()
    Dim i As Integer
    Dim tmp As D3DVECTOR
    '施加力后的位置
    For i = 1 To num_particles
        tmp = m_curp(i)
        m_curp(i).x = (m_curp(i).x * 2 - m_oldp(i).x) + (m_forc(i).x * m_timeStep)
        m_curp(i).y = (m_curp(i).y * 2 - m_oldp(i).y) + (m_forc(i).y * m_timeStep)
        m_curp(i).z = (m_curp(i).z * 2 - m_oldp(i).z) + (m_forc(i).z * m_timeStep)
        m_oldp(i) = tmp
     Next
End Function

Private Function SatisfyConstraints()
    Dim delta As D3DVECTOR
    Dim vscale As Double
    Dim rl As Long
 '与产生地面撞击
    For i = 1 To num_particles
        If m_curp(i).y < 0 Then
            m_curp(i).y = 0
            m_oldp(i).x = m_oldp(i).x + (m_curp(i).x - m_oldp(i).x) * 0.4
            m_oldp(i).z = m_oldp(i).z + (m_curp(i).z - m_oldp(i).z) * 0.4
        End If
    Next
    '根据杠杆长度进行限制
    For i = 1 To num_join
        D3DXVec3Subtract delta, m_curp(join_p2(i)), m_curp(join_p1(i))
        rl = join_rl(i) * join_rl(i)
        vscale = rl / (delta.x * delta.x + delta.y * delta.y + delta.z * delta.z + rl) - 0.5
        D3DXVec3Scale delta, delta, vscale
        D3DXVec3Subtract m_curp(join_p1(i)), m_curp(join_p1(i)), delta
        D3DXVec3Add m_curp(join_p2(i)), m_curp(join_p2(i)), delta
        Next
    End Function

Private Function AccumulateForces()
    Dim i As Integer
    '所有节点受到重力影响
        For i = 0 To num_particles
        m_forc(i) = m_grav
    Next
End Function

代码非常小,它依次呼叫了三个过程: AccumulateForces, Verlet, SatisfyConstraints. 
最后一步进行强制约束,它保证两个节点间的距离为杠杆的长度。两个节点间向量计算我使用了D3DX helper库中的函数,然后用vscale缩放向量,最后施加到节点.
 

下载代码