surfaceVelocity 반영

캐릭터가 배나 비행기 같이 움직이는 지형 위에 있을 때는 움직이는 지형의 속도를 캐릭터에 반영해야 한다.

하복 데모의 MovingSupportRbDemo.cpp getGround( )를 참조 하였다.

1. 표면의 속도 구하기
캐릭터가 월드의 지면과 충돌 하고 있을 때, 즉 hkpSurfaceInfo::UNSUPPORTED가 아닐때 월드에 접한 표면의 속도를 구한다. 속도는 surfaceInfo.m_surfaceVelocity로 얻어 올수 있다.

    //움직이는 월드의 속도를 캐릭터에 반영한다.

    hkpSurfaceInfo surfaceInfo;

    {

        hkArray<hkpCharacterRigidBody::SupportInfo> supportInfo;

 

        hkStepInfo stepInfo;

        stepInfo.m_deltaTime = fTimestep;

        stepInfo.m_invDeltaTime = 1.0f / fTimestep;

        stepInfo.m_endTime = TIME_STEP;

        surfaceInfo.m_supportedState = m_pHavokRigidBody->getSupportInfo( stepInfo, supportInfo );

        if ( surfaceInfo.m_supportedState != hkpSurfaceInfo::UNSUPPORTED )

            GetGround( m_pHavokRigidBody, supportInfo, surfaceInfo );

    }

hkpCharacterInput를 input으로 사용하는 경우에는 hkArray<hkpCharacterRigidBody::SupportInfo>대신 input.m_surfaceInfo를 GetGround( ) 세 번째 인자에 전달한다.

2. 속도 더하기

본 예제에서는 hkpCharacterInput로  hkpCharacterContext::update( )를 통해서 hkpCharacterOutput 구하고 있지 않기 때문에 hkpCharacterOutput 값에 직접 더해준다.

    //움직이는 월드의 속도를 더한다.

    output.m_velocity.add4( surfaceInfo.m_surfaceVelocity );

hkpCharacterInput을 이용하면 hkpCharacterOutput 값에 더하는 과정은 필요 없다.

캡슐형의 캐릭터가 움직이는 월드에 올라가면 같이 움직일 것이다.

 

참고) GetGround(  ) 소스

//하복 데모의 MovingSupportRbDemo.cpp getGround( ) 참고

void HavokCharacter::GetGround( hkpCharacterRigidBody* characterRigidBody, const hkArray<hkpCharacterRigidBody::SupportInfo>& supportInfo, hkpSurfaceInfo& ground ) const

{

    float fTimestep = 1.0f / 60.0f;

    // Produce an average version of the ground

 

    ground.m_surfaceVelocity.setZero4();

    ground.m_surfaceNormal.setZero4();

    ground.m_surfaceDistanceExcess = 0.0f;

    ground.m_surfaceIsDynamic = false;

 

    const int numSupportInfo = supportInfo.getSize();

    for ( int i = 0; i < numSupportInfo; ++i )

    {

        const hkpCharacterRigidBody::SupportInfo& support = supportInfo[i];

        ground.m_surfaceNormal.add4( support.m_point.getNormal() );

        ground.m_surfaceDistanceExcess += support.m_point.getDistance();

        const hkpMotion::MotionType motionType = support.m_rigidBody->getMotionType();

        if ( motionType == hkpMotion::MOTION_KEYFRAMED )

        {

            hkVector4 pointVelocity;

            support.m_rigidBody->getPointVelocity( support.m_point.getPosition(), pointVelocity );

            ground.m_surfaceVelocity.add4( pointVelocity );

        }

        /*

        else if ( motionType != hkpMotion::MOTION_FIXED )

        {

            ground.m_surfaceIsDynamic = true;

            if ( m_bodyType.getWithDefault ( support.m_rigidBody, false ) == hkBool32( true ) )

            {

                hkVector4 pointVelocity;

                support.m_rigidBody->getPointVelocity( support.m_point.getPosition(), pointVelocity );

                ground.m_surfaceVelocity.add4( pointVelocity );

            }

        }

        */

    }

 

    ground.m_surfaceNormal.normalize3();

    const hkReal portion = 1.f / numSupportInfo;

 

    ground.m_surfaceVelocity.mul4( portion );

    ground.m_surfaceDistanceExcess = ( ground.m_surfaceDistanceExcess * portion );

 

    if ( ground.m_surfaceIsDynamic )

    {

        // We need to apply the character's weight onto dynamic bodies. We do this by

        // setting a positive surfaceDistanceExcess which the controller should try

        // to reduce by applying gravity.

        ground.m_surfaceDistanceExcess = 0.01f;

    }

    else

    {

        // For fixed and keyframed bodies, we subtract m_hardSupportDistance from the excess

        // to ensure an extra gap below the character. This improves the smoothness of the

        // character's motion over the ground.

        ground.m_surfaceDistanceExcess -= characterRigidBody->m_hardSupportDistance;

    }

 

    // For dynamic supporting bodies which do keep velocity, we apply gravity representing the

    // force required to keep the character in position.

    hkVector4 impulse;

    {

        hkpWorld* pWorld = HavokManager::Instance()->GetWorld();

        impulse.setMul4( characterRigidBody->m_character->getMass() * fTimestep, pWorld->getGravity() );

        // We want the component of the impulse tangential to the surface.

        const hkSimdReal normal = impulse.dot3( ground.m_surfaceNormal );

        impulse.setAddMul4( impulse, ground.m_surfaceNormal, -normal );

        // Divide the amount of impulse by the number of supporting surfaces

        impulse.mul4( 1.0f / numSupportInfo );

    }

 

    /*

    for ( int i = 0; i < numSupportInfo; ++i )

    {

        const hkpCharacterRigidBody::SupportInfo& support = supportInfo[i];

 

        if ( m_bodyType.getWithDefault( support.m_rigidBody, false ) == hkBool32( true ) )

        {

            // Apply the impulse at the contact point.

            support.m_rigidBody->applyPointImpulse( impulse, support.m_point.getPosition() );

        }

    }

    */

}

  프로젝트 : havok_surfaceVelocity.zip