Exemple #1
0
void VisibleEntity::onPose(Array<shared_ptr<Surface> >& surfaceArray) {

    // We have to pose in order to compute bounds that are used for selection in the editor
    // and collisions in simulation, so pose anyway if not visible,
    // but then roll back.
    debugAssert(isFinite(m_frame.translation.x));
    debugAssert(! isNaN(m_frame.rotation[0][0]));
    const int oldLen = surfaceArray.size();

    const bool boundsChangedSincePreviousFrame = poseModel(surfaceArray);

    // Compute bounds for objects that moved
    if (m_lastAABoxBounds.isEmpty() || boundsChangedSincePreviousFrame || (m_lastChangeTime > m_lastBoundsTime)) {

        m_lastSphereBounds = Sphere(m_frame.translation, 0);
        
        const CFrame& myFrameInverse = frame().inverse();

        m_lastObjectSpaceAABoxBounds = AABox::empty();
        m_lastBoxBoundArray.fastClear();

        // Look at all surfaces produced
        for (int i = oldLen; i < surfaceArray.size(); ++i) {
            AABox b;
            Sphere s;
            const shared_ptr<Surface>& surf = surfaceArray[i];

            // body to world transformation for the surface
            CoordinateFrame cframe;
            surf->getCoordinateFrame(cframe, false);
            debugAssertM(cframe.translation.x == cframe.translation.x, "NaN translation");


            surf->getObjectSpaceBoundingSphere(s);
            s = cframe.toWorldSpace(s);
            m_lastSphereBounds.radius = max(m_lastSphereBounds.radius,
                                            (s.center - m_lastSphereBounds.center).length() + s.radius);


            // Take the entity's frame out of consideration, so that we get tight AA bounds 
            // in the Entity's frame
            CFrame osFrame = myFrameInverse * cframe;

            surf->getObjectSpaceBoundingBox(b);

            m_lastBoxBoundArray.append(cframe.toWorldSpace(b));
            const Box& temp = osFrame.toWorldSpace(b);
            m_lastObjectSpaceAABoxBounds.merge(temp);
        }

        // Box can't represent an empty box, so we make empty boxes into real boxes with zero volume here
        if (m_lastObjectSpaceAABoxBounds.isEmpty()) {
            m_lastObjectSpaceAABoxBounds = AABox(Point3::zero());
            m_lastAABoxBounds = AABox(frame().translation);
        }

        m_lastBoxBounds = frame().toWorldSpace(m_lastObjectSpaceAABoxBounds);
        m_lastBoxBounds.getBounds(m_lastAABoxBounds);
        m_lastBoundsTime = System::time();
    }

    if (! m_visible) {
        // Discard my surfaces if I'm invisible; they were only needed for bounds
        surfaceArray.resize(oldLen, false);
    }
}
void vHavokBehaviorComponent::OnAfterHavokUpdate()
{
	if( m_character == HK_NULL || m_entityOwner == HK_NULL )
	{
		return;
	}

	// Update WFM of skin or override it
	if ( m_useBehaviorWorldFromModel )
	{
		const hkQsTransform& worldFromModel = m_character->getWorldFromModel();

		// Copy the Behavior result into vision
		hkvMat3 visionRotation;
		hkvVec3 visionTranslation;
		vHavokConversionUtils::HkQuatToVisMatrix( worldFromModel.getRotation(), visionRotation );
		vHavokConversionUtils::PhysVecToVisVecWorld( worldFromModel.getTranslation(), visionTranslation );
		m_entityOwner->SetPosition( visionTranslation );
		m_entityOwner->SetRotationMatrix( visionRotation );
	}
	else
	{
		// Override Behavior results.
		// This will currently cause Behavior data being sent to HBT during remote debug to be one frame off.
		// However, the only other solution with the current APIs is to disable motion accumulation on *all*
		// Characters.  A slight delay/offset in the special case of remote debugging in HBT isn't worth that change.
		UpdateHavokTransformFromVision();
	}

	if( m_entityOwner->GetMesh() == HK_NULL || m_entityOwner->GetMesh()->GetSkeleton() == HK_NULL )
	{
		return;
	}

	VisAnimConfig_cl* animConfig = m_entityOwner->GetAnimConfig();
	if( !animConfig )
	{
		return;
	}

	VisAnimFinalSkeletalResult_cl* skeletalResult = animConfig->GetFinalResult();
	if( !skeletalResult )
	{
		return;
	}

	// Try updating the bone index list in case a mesh was added
	if( m_boneIndexList.getSize() == 0 )
	{
		UpdateAnimationAndBoneIndexList();

		// Exit early if there's no bone index list
		if( m_boneIndexList.getSize() == 0 )
		{
			return;
		}
	}

	// Convert pose to Havok model space
	const hkQsTransform* poseLocal = m_character->getPoseLocal();
	hkArray<hkQsTransform> poseModel( m_character->getNumPoseLocal() );
	hkaSkeletonUtils::transformLocalPoseToModelPose( m_character->getNumPoseLocal(), m_character->getSetup()->m_animationSkeleton->m_parentIndices.begin(), poseLocal, poseModel.begin() );
	const hkQsTransform* pose = poseModel.begin();

	float const inverseCharacterScale = 1.0f / m_character->getSetup()->getData()->m_scale;

	// Convert pose to vision units
	VisSkeleton_cl* visionSkeleton = m_entityOwner->GetMesh()->GetSkeleton();

	
	for( int havokBoneIndex = 0; havokBoneIndex < m_character->getNumPoseLocal(); havokBoneIndex++ )
	{
		// Find the bone index
		int visionBoneIndex = m_boneIndexList[havokBoneIndex];
		if( visionBoneIndex != -1 )
		{
			HK_ON_DEBUG( VisSkeletalBone_cl* bone = visionSkeleton->GetBone(visionBoneIndex) );
			HK_ASSERT2(0x68b6649, hkString::strCmp( bone->m_sBoneName.AsChar(), m_character->getSetup()->m_animationSkeleton->m_bones[havokBoneIndex].m_name.cString() ) == 0, "" );

			const hkQsTransform& transform = pose[havokBoneIndex];

			// Convert Havok pose to Vision pose
			hkvQuat quat;
			quat.setIdentity();
			vHavokConversionUtils::HkQuatToVisQuat( transform.getRotation(), quat );
			hkvVec3 scale; vHavokConversionUtils::PhysVecToVisVec_noscale( transform.getScale(), scale );
			hkvVec3 translation; vHavokConversionUtils::PhysVecToVisVecWorld( transform.getTranslation(), translation );

			// Behavior propagates character scale through the skeleton; need to compensate when scaling to Vision
			scale *= inverseCharacterScale;

			// Set the skeletal result
			skeletalResult->SetCustomBoneScaling( visionBoneIndex, scale, VIS_REPLACE_BONE | VIS_OBJECT_SPACE );
			skeletalResult->SetCustomBoneRotation( visionBoneIndex, quat, VIS_REPLACE_BONE | VIS_OBJECT_SPACE );
			skeletalResult->SetCustomBoneTranslation( visionBoneIndex, translation, VIS_REPLACE_BONE | VIS_OBJECT_SPACE );
		}
	}

#if 0

	// Draw skeleton
	for( int i = 0; i < visionSkeleton->GetBoneCount(); i++ )
	{
		VisSkeletalBone_cl* bone = visionSkeleton->GetBone(i);
		if( bone->m_iParentIndex != -1 )
		{
			hkvVec3 translation, subTranslation;
			hkvQuat rotation, subRotation;
			m_entityOwner->GetBoneCurrentWorldSpaceTransformation( i, translation, rotation );
			m_entityOwner->GetBoneCurrentWorldSpaceTransformation( bone->m_iParentIndex, subTranslation, subRotation );

			Vision::Game.DrawSingleLine( translation.x, translation.y, translation.z, subTranslation.x, subTranslation.y, subTranslation.z );
		}
	}

#endif

}