unsigned int Forest::onCollideJumper(unsigned int id, Matrix4f* matrix, void* data)
{
    Forest* __this = reinterpret_cast<Forest*>( data );

    // determine obb of instance
    NxBox instanceOBB = calculateOBB( 
        __this->_canopyBatch->getBatchScheme()->lodGeometry[0], 
        *matrix,
        __this->_desc.collScale
    );
    __this->_debugBoxes.push_back( instanceOBB );

    // collide obbs
    if( NxBoxBoxIntersect( instanceOBB, __this->_jumperOBB ) )
    {
        Jumper* jumper = dynamic_cast<Jumper*>( __this->_currentJumper );
        // add impulse to jumper body
        NxVec3 linearVelocity = __this->_currentJumperActor->getLinearVelocity();
        NxVec3 impulse = linearVelocity * getCore()->getRandToolkit()->getUniform( __this->_desc.minImpulseFactor, __this->_desc.maxImpulseFactor ) * -1;
        NxVec3 localPos(
            __this->_jumperOBB.extents.x * getCore()->getRandToolkit()->getUniform( -1, 1 ),
            __this->_jumperOBB.extents.y * getCore()->getRandToolkit()->getUniform( -1, 1 ),
            __this->_jumperOBB.extents.z * getCore()->getRandToolkit()->getUniform( -1, 1 )
        );
        __this->_currentJumperActor->addForceAtLocalPos( impulse, localPos, NX_IMPULSE );
        // damage jumper
        jumper->damage( __this->_desc.damageFactor * impulse.magnitude(), 0.0f, linearVelocity.magnitude() );
        // play rustle sound
        __this->playRustleSound( __this->_currentJumperCollision->getFrame()->getPos() );
    }

    return id;
}
Exemple #2
0
NxDistanceJoint* World::CreateDistanceJoint(NxActor* a0, NxActor* a1, const NxVec3& anchor0, const NxVec3& anchor1, const NxVec3& globalAxis)
{
	NxDistanceJointDesc distanceDesc;
	distanceDesc.actor[0] = a0;
	distanceDesc.actor[1] = a1;
	distanceDesc.localAnchor[0] = anchor0;
	distanceDesc.localAnchor[1] = anchor1;
	distanceDesc.setGlobalAxis(globalAxis);

	NxVec3 dist = a1->getGlobalPose()*anchor1 - a0->getGlobalPose()*anchor0;
	printf("dist is %f %f %f\n",dist.x, dist.y, dist.z);
	distanceDesc.maxDistance = dist.magnitude()*1.5f;
	distanceDesc.minDistance = dist.magnitude()*0.1f;

	printf("maxDistance %f, minDistance %f\n", distanceDesc.maxDistance, distanceDesc.minDistance);

	NxSpringDesc spring;
	spring.spring = 1000;		// х»лн¤х╩§
	spring.damper = 0.5;
	distanceDesc.spring = spring;
	distanceDesc.flags = (NX_DJF_MIN_DISTANCE_ENABLED | NX_DJF_MAX_DISTANCE_ENABLED);
	distanceDesc.flags |= NX_DJF_SPRING_ENABLED;
	distanceDesc.jointFlags |= NX_JF_COLLISION_ENABLED;

	return (NxDistanceJoint*)gScene->createJoint(distanceDesc);
}
unsigned int Forest::onCollideCanopy(unsigned int id, Matrix4f* matrix, void* data)
{
    Forest* __this = reinterpret_cast<Forest*>( data );

    // determine obb of instance
    NxBox instanceOBB = calculateOBB( 
        __this->_canopyBatch->getBatchScheme()->lodGeometry[0], 
        *matrix,
        __this->_desc.collScale
    );
    __this->_debugBoxes.push_back( instanceOBB );

    // collide obbs
    if( NxBoxBoxIntersect( instanceOBB, __this->_canopyOBB ) )
    {
        CanopySimulator* canopy = dynamic_cast<CanopySimulator*>( __this->_currentCanopy );
        // calculate intersection details
        float volume;
        NxVec3 globalIntersectionCenter;
        calculateIntersectionDetails( instanceOBB, __this->_canopyOBB, volume, globalIntersectionCenter );
        assert( volume <= 1.0f );
        // add force to canopy
        NxVec3 linearVelocity = __this->_currentCanopyActor->getLinearVelocity();
        float linearVelocityMagnitude = linearVelocity.magnitude();
        linearVelocity.normalize();
        NxVec3 force = linearVelocity * 0.2f * sqr( linearVelocityMagnitude ) * __this->_currentCanopyInfo->square * -volume;
        __this->_currentCanopyActor->addForceAtPos( force, globalIntersectionCenter, NX_FORCE );
        // damage canopy
        canopy->rip( __this->_desc.ripFactor * force.magnitude() );
        // entangle canopy
        if( volume > __this->_desc.entangleFactor )
        {            
            canopy->entangle( globalIntersectionCenter );
            __this->playSqueakSound( wrap( globalIntersectionCenter ) );
        }
        else
        {
            __this->playRustleSound( wrap( globalIntersectionCenter ) );
        }
    }

    return id;
}
void DrawForce(NxActor* actor, NxVec3& forceVec, const NxVec3& color)
{
	// Draw only if the force is large enough
	NxReal force = forceVec.magnitude();
	if (force < 0.1f)  return;

	forceVec = 3*forceVec/force;

	NxVec3 pos = actor->getCMassGlobalPosition();
	DrawArrow(pos, pos + forceVec, color);
}
void Jumper::CanopyOpening::updatePhysics(void)
{
    // velocity of base jumper's body
    NxVec3 velocity = _phActor->getLinearVelocity();

    // local coordinate system of base jumper
    NxMat34 pose = _phActor->getGlobalPose();
    NxVec3 x = pose.M.getColumn(0);
    NxVec3 y = pose.M.getColumn(1);
    NxVec3 z = pose.M.getColumn(2);

    // air resistance force
    float AR = _jumper->getVirtues()->getTrackingAirResistance();

    // terminal velocity
    float Vt = sqrt( 9.8f * _phActor->getMass() / AR );
    float It = velocity.magnitude() / Vt;

    // air resistance force
    NxVec3 Far = NxVec3(0,1,0) * getAirResistancePower( velocity.magnitude() / Vt ) * _phActor->getMass() * 9.8f;

    // finalize motion equation    
    _phActor->addForce( Far );

    // linear damping is function of jumper velocity    
    // this is prevents calculation errors due to high speed rates
    float minVel     = 50.0f;
    float minDamping = _initialLD;
    float maxVel     = 70.0f;
    float maxDamping = 2.5f;
    float factor = ( velocity.magnitude() - minVel ) / ( maxVel - minVel );
    factor = factor < 0 ? 0 : ( factor > 1 ? 1 : factor );
    float damping = minDamping * ( factor - 1 ) + maxDamping * ( factor );
    _phActor->setLinearDamping( damping );

    // shallow brake setting
    _canopy->setLeftDeep( 0.0f );
    _canopy->setRightDeep( 0.0f );

}
Exemple #6
0
    void DynamicImage::update()
    {
        


        if (!sleep)
        {
            NxVec3 towardsVector = tarPos - curPos;

            switch (mode)
            {
            case 0:     //Linear
                if (towardsVector.magnitude() < LINEAR_VELOCITY)
                {
                    curPos = tarPos;
                    sleep = true;
                }
                else
                {
                    towardsVector.normalize();
                    curPos = curPos + (towardsVector * LINEAR_VELOCITY);
                }
                break;


            case 1:     //Halfling
                if (towardsVector.magnitude() < THRESHOLD)
                {
                    curPos = tarPos;
                    sleep = true;
                }
                else
                {
                    curPos = curPos + (towardsVector * 0.033f);
                }
                break;

            }
        }
    }
Exemple #7
0
void DrawForceAtShape(NxActor* actor, NxShape* shape, NxVec3& forceVec, const NxVec3& color)
{
	// Draw only if the force is large enough
	NxReal force = forceVec.magnitude();
	if (force < 0.1f)  return;

	forceVec = 3*forceVec/force;

	NxVec3 pos;	
	if (bShapeSelectMode && bForceMode)
		pos = shape->getGlobalPosition();
	else
		pos = actor->getCMassGlobalPosition();
	DrawArrow(pos, pos + forceVec, color);
}
Exemple #8
0
void CreateExperiment()
{
	switch (gExperimentType)
	{
	case LANDER:
		  {
			  gScene->releaseActor(*groundPlane); groundPlane=NULL; // will be recreated with the container cell
			  CreateExperimentMaterials();
			  CreateContainerCell(gCellSize);
			  gPhysicsSDK->setParameter(NX_VISUALIZE_ACTOR_AXES,0);
			  gPhysicsSDK->setParameter(NX_VISUALIZE_COLLISION_FNORMALS,0);
			  gPhysicsSDK->setParameter(NX_VISUALIZE_COLLISION_SHAPES,1);
			  gPhysicsSDK->setParameter(NX_VISUALIZE_WORLD_AXES,0);
			  //gLander=CreateLander(NxVec3(0.0f,0.0f,0.0f));
			  gLander=CreateLander(NxVec3(0.0f,gCellSize/2.0f,0.0f));
			  IdentifyGravitators();
			  if (gLander) {
			  ReOrientActor(gLander);
			  SpinActor(gLander,gLandingRoughness*sqrt(gCellSize*gDefaultGravity.magnitude()/(gLander->getMassSpaceInertiaTensor().magnitude())));
			  LaunchActor(gLander,gLandingRoughness*sqrt(gCellSize*gDefaultGravity.magnitude()));
			  gSelectedActor=gLander;
			  gPhysicsSDK->setParameter(NX_VISUALIZE_ACTOR_AXES,gLanderSize.magnitude());
			  isRunning=true;
			  }
			  else {
				  printf("Error: Unable to create lander\a\n");
				  isRunning=false;
			  }
			  break;
		  }
	case LAY_SUBSTRATE:
		{
			gScene->releaseActor(*groundPlane); groundPlane=NULL; // will be recreated with the container cell
			CreateExperimentMaterials();
			CreateContainerCell(gCellSize);
			gPhysicsSDK->setParameter(NX_VISUALIZE_ACTOR_AXES,0);
			gPhysicsSDK->setParameter(NX_VISUALIZE_COLLISION_FNORMALS,0);
			gPhysicsSDK->setParameter(NX_VISUALIZE_COLLISION_SHAPES,1);
			gPhysicsSDK->setParameter(NX_VISUALIZE_WORLD_AXES,0);
			//ThrowStone();
			isRunning=true;
			break;
		}
	default:				
		{printf("Error: unimplemented experiment type\a\n"); isRunning=false; break;}
	}
}
void PxSingleActor::sweepTest( MatrixF *mat )
{
   NxVec3 nxCurrPos = getPosition();

   // If the position is zero, 
   // the parent hasn't been updated yet
   // and we don't even need to do the sweep test.
   // This is a fix for a problem that was happening
   // where on the add of the PxSingleActor, it would
   // set the position to a very small value because it would be getting a hit
   // even though the current position was 0.
   if ( nxCurrPos.isZero() )
      return;
   
   // Set up the flags and the query structure.
   NxU32 flags = NX_SF_STATICS | NX_SF_DYNAMICS;

   NxSweepQueryHit sweepResult;
   dMemset( &sweepResult, 0, sizeof( sweepResult ) );

   NxVec3 nxNewPos = mat->getPosition();

   // Get the velocity which will be our sweep direction and distance.
   NxVec3 nxDir = nxNewPos - nxCurrPos;
   if ( nxDir.isZero() )
      return;

   // Get the scene and do the sweep.
   mActor->wakeUp();
   mActor->linearSweep( nxDir, flags, NULL, 1, &sweepResult, NULL );

   if ( sweepResult.hitShape && sweepResult.t < nxDir.magnitude() )
   {
      nxDir.normalize();
      nxDir *= sweepResult.t;
      nxCurrPos += nxDir;

      mat->setPosition( Point3F( nxCurrPos.x, nxCurrPos.y, nxCurrPos.z ) );
   }
}
void PxSingleActor::applyCorrection( const MatrixF& mat, const NxVec3& linVel, const NxVec3& angVel )
{
   // Sometimes the actor hasn't been
   // created yet during the call from unpackUpdate.
   if ( !mActor || !mWorld )
      return;

   mWorld->releaseWriteLock();

   NxVec3 newPos = mat.getPosition();
   NxVec3 currPos = getPosition();

   NxVec3 offset = newPos - currPos;

   // If the difference isn't large enough,
   // just set the new transform, no correction.
   if ( offset.magnitude() > 0.3f )
   {
      // If we're going to set the linear or angular velocity,
      // we do it before we add a corrective force, since it would be overwritten otherwise.
      NxVec3 currLinVel, currAngVel;
      currLinVel = mActor->getLinearVelocity();
      currAngVel = mActor->getAngularVelocity();

      // Scale the corrective force by half,
      // otherwise it will over correct and oscillate.
      NxVec3 massCent = mActor->getCMassGlobalPosition();
      mActor->addForceAtPos( offset, massCent, NX_VELOCITY_CHANGE );

      // If the linear velocity is divergent enough, change to server linear velocity.
      if ( (linVel - currLinVel).magnitude() > 0.3f )
         mActor->setLinearVelocity( linVel );
      // Same for angular.
      if ( (angVel - currAngVel).magnitude() > 0.3f )
         mActor->setAngularVelocity( angVel );   
   }

   Parent::setTransform( mat );
}
void WindPointer::onEvent(Actor* initiator, unsigned int eventId, void* eventData)
{
    if( eventId == EVENT_CAMERA_IS_ACTUAL )
    {
        // current wind
        NxVec3 wind = _scene->getWindAtPoint( NxVec3( 0,0,0 ) );

        // make signature worldspace position
        Matrix4f cameraPose = _scene->getCamera()->getPose();
        Vector3f cameraPos( cameraPose[3][0], cameraPose[3][1], cameraPose[3][2] );
        Vector3f pos( wind.x, wind.y, wind.z );
        pos.normalize();
        pos *= 10000.0f;
        pos += cameraPos;

        // update signature window
        Vector3f screenPos = Gameplay::iEngine->getDefaultCamera()->projectPosition( pos );
        if( screenPos[2] > 1 )
        {
            _signature->getPanel()->setVisible( false );
            return;
        }
        else
        {
            _signature->getPanel()->setVisible( true );
            gui::Rect oldRect = _signature->getPanel()->getRect();
            gui::Rect newRect(
                int( screenPos[0] ), int( screenPos[1] ),
                int( screenPos[0] ) + oldRect.getWidth(),
                int( screenPos[1] ) + oldRect.getHeight()
            );
            _signature->getPanel()->setRect( newRect );
            _windSpeed->getStaticText()->setText( wstrformat( Gameplay::iLanguage->getUnicodeString(295), wind.magnitude() ).c_str() );
        }        
    }
}
Exemple #12
0
// This is the generic sweep test for all swept volumes, but not character-controller specific
bool SweepTest::DoSweepTest(void* user_data,
							void* user_data2,
							NxU32 nb_boxes, const NxExtendedBounds3* boxes, const void** box_user_data,
							NxU32 nb_capsules, const NxExtendedCapsule* capsules, const void** capsule_user_data,
							SweptVolume& swept_volume,
							const NxVec3& direction, NxU32 max_iter, NxU32* nb_collisions,
							NxU32 group_flags, float min_dist, const NxGroupsMask* groupsMask, bool down_pass)
{
	// Early exit when motion is zero. Since the motion is decomposed into several vectors
	// and this function is called for each of them, it actually happens quite often.
	if(direction.isZero())
		return false;

	bool HasMoved = false;
	mValidTri = false;

	NxExtendedVec3 CurrentPosition = swept_volume.mCenter;
	NxExtendedVec3 TargetPosition = swept_volume.mCenter;
	TargetPosition += direction;

	NxU32 NbCollisions = 0;
	while(max_iter--)
	{
		gNbIters++;
		// Compute current direction
		NxVec3 CurrentDirection = TargetPosition - CurrentPosition;

		// Make sure the new TBV is still valid
		{
			// Compute temporal bounding box. We could use a capsule or an OBB instead:
			// - the volume would be smaller
			// - but the query would be slower
			// Overall it's unclear whether it's worth it or not.
			// TODO: optimize this part ?
			NxExtendedBounds3 TemporalBox;
			swept_volume.ComputeTemporalBox(*this, TemporalBox, CurrentPosition, CurrentDirection);

			// Gather touched geoms
			UpdateTouchedGeoms(user_data, swept_volume,
								nb_boxes, boxes, box_user_data,
								nb_capsules, capsules, capsule_user_data,
								group_flags, TemporalBox, groupsMask);
		}

		const float Length = CurrentDirection.magnitude();
		if(Length<min_dist)	break;

		CurrentDirection /= Length;

		// From Quake2: "if velocity is against the original velocity, stop dead to avoid tiny occilations in sloping corners"
		if((CurrentDirection|direction) <= 0.0f)	break;

		// From this point, we're going to update the position at least once
		HasMoved = true;

		// Find closest collision
		SweptContact C;
		C.mDistance = Length + mSkinWidth;

		if(!CollideGeoms(this, swept_volume, mGeomStream, CurrentPosition, CurrentDirection, C))
		{
			// no collision found => move to desired position
			CurrentPosition = TargetPosition;
			break;
		}

		ASSERT(C.mGeom);	// If we reach this point, we must have touched a geom

		if(C.mGeom->mType==TOUCHED_USER_BOX || C.mGeom->mType==TOUCHED_USER_CAPSULE)
		{
			// We touched a user object, typically another CCT
			if(mValidateCallback)	UserHitCallback(user_data2, C, CurrentDirection, Length);

			// Trying to solve the following problem:
			// - by default, the CCT "friction" is infinite, i.e. a CCT will not slide on a slope (this is by design)
			// - this produces bad results when a capsule CCT stands on top of another capsule CCT, without sliding. Visually it looks
			//   like the character is standing on the other character's head, it looks bad. So, here, we would like to let the CCT
			//   slide away, i.e. we don't want friction.
			// So here we simply increase the number of iterations (== let the CCT slide) when the first down collision is with another CCT.
			if(down_pass && !NbCollisions)
				max_iter += 9;
		}
		else
		{
			// We touched a normal object
#ifdef USE_CONTACT_NORMAL_FOR_SLOPE_TEST
			mValidTri = true;
			mCN = C.mWorldNormal;
#else
			if(C.mIndex!=INVALID_ID)
			{
				mValidTri = true;
				mTouched = mWorldTriangles[C.mIndex];
			}
#endif
			{
				if(mValidateCallback)	ShapeHitCallback(user_data2, C, CurrentDirection, Length);
			}
		}

		NbCollisions++;
		mContactPointHeight = (float)C.mWorldPos[mUpDirection];	// UBI

		const float DynSkin = mSkinWidth;

		if(C.mDistance>DynSkin/*+0.01f*/)
			CurrentPosition += CurrentDirection*(C.mDistance-DynSkin);

		NxVec3 WorldNormal = C.mWorldNormal;
		if(mWalkExperiment)
		{
			// Make sure the auto-step doesn't bypass this !
			WorldNormal[mUpDirection]=0.0f;
			WorldNormal.normalize();
		}

		const float Bump = 0.0f;	// ### doesn't work when !=0 because of Quake2 hack!
		const float Friction = 1.0f;
		CollisionResponse(TargetPosition, CurrentPosition, CurrentDirection, WorldNormal, Bump, Friction, mNormalizeResponse);
	}

	if(nb_collisions)	*nb_collisions = NbCollisions;

	// Final box position that should be reflected in the graphics engine
	swept_volume.mCenter = CurrentPosition;

	// If we didn't move, don't update the box position at all (keeping possible lazy-evaluated structures valid)
	return HasMoved;
}
void Jumper::Flight::updatePhysics(void)
{
    SpinalCord* spinalCord = _jumper->getSpinalCord();
    Virtues* virtues = _jumper->getVirtues();
	CanopySimulator* canopy = _jumper->getDominantCanopy();

    // velocity of base jumper's body
    NxVec3 velocity = _phActor->getLinearVelocity();
    
    // horizontal velocity (including wind)
    NxVec3 velocityH = velocity; 
    velocityH += _jumper->getScene()->getWindAtPoint( _phActor->getGlobalPosition() );    
    velocityH.y = 0;

    // shock penalty
    float penalty = _jumper->getVirtues()->getControlPenalty( _jumper->getShock() );
    penalty = ( 1 - penalty );

    // update canopy controls
	// modifier to 50% input
	if (spinalCord->modifier) {
		float dt = _jumper->getDeltaTime();
		if (spinalCord->left > 0.5f && Gameplay::iGameplay->getActionChannel(iaLeft)->getTrigger()) Gameplay::iGameplay->getActionChannel(iaLeft)->downAmplitude(dt, 0.5f);
		if (spinalCord->right > 0.5f && Gameplay::iGameplay->getActionChannel(iaRight)->getTrigger()) Gameplay::iGameplay->getActionChannel(iaRight)->downAmplitude(dt, 0.5f);
		if (spinalCord->leftWarp > 0.5f && Gameplay::iGameplay->getActionChannel(iaLeftWarp)->getTrigger()) Gameplay::iGameplay->getActionChannel(iaLeftWarp)->downAmplitude(dt, 0.5f);
		if (spinalCord->rightWarp > 0.5f && Gameplay::iGameplay->getActionChannel(iaRightWarp)->getTrigger()) Gameplay::iGameplay->getActionChannel(iaRightWarp)->downAmplitude(dt, 0.5f);
		if (spinalCord->leftRearRiser > 0.5f && Gameplay::iGameplay->getActionChannel(iaLeftRearRiser)->getTrigger()) Gameplay::iGameplay->getActionChannel(iaLeftRearRiser)->downAmplitude(dt, 0.5f);
		if (spinalCord->rightRearRiser > 0.5f && Gameplay::iGameplay->getActionChannel(iaRightRearRiser)->getTrigger()) Gameplay::iGameplay->getActionChannel(iaRightRearRiser)->downAmplitude(dt, 0.5f);

		if (spinalCord->leftReserve > 0.5f && Gameplay::iGameplay->getActionChannel(iaReserveLeft)->getTrigger()) Gameplay::iGameplay->getActionChannel(iaReserveLeft)->downAmplitude(dt, 0.5f);
		if (spinalCord->rightReserve > 0.5f && Gameplay::iGameplay->getActionChannel(iaReserveRight)->getTrigger()) Gameplay::iGameplay->getActionChannel(iaReserveRight)->downAmplitude(dt, 0.5f);
		if (spinalCord->leftReserveWarp > 0.5f && Gameplay::iGameplay->getActionChannel(iaReserveLeftWarp)->getTrigger()) Gameplay::iGameplay->getActionChannel(iaReserveLeftWarp)->downAmplitude(dt, 0.5f);
		if (spinalCord->rightReserveWarp > 0.5f && Gameplay::iGameplay->getActionChannel(iaReserveRightWarp)->getTrigger()) Gameplay::iGameplay->getActionChannel(iaReserveRightWarp)->downAmplitude(dt, 0.5f);
		if (spinalCord->leftReserveRearRiser > 0.5f && Gameplay::iGameplay->getActionChannel(iaReserveLeftRearRiser)->getTrigger()) Gameplay::iGameplay->getActionChannel(iaReserveLeftRearRiser)->downAmplitude(dt, 0.5f);
		if (spinalCord->rightReserveRearRiser > 0.5f && Gameplay::iGameplay->getActionChannel(iaReserveRightRearRiser)->getTrigger()) Gameplay::iGameplay->getActionChannel(iaReserveRightRearRiser)->downAmplitude(dt, 0.5f);
	}


	// set risers
    canopy->setLeftWarpDeep( spinalCord->leftWarp * penalty );
    canopy->setRightWarpDeep( spinalCord->rightWarp * penalty );
    canopy->setLeftRearRiser( spinalCord->leftRearRiser * penalty );
    canopy->setRightRearRiser( spinalCord->rightRearRiser * penalty );

	canopy->setWLOToggles( spinalCord->trigger_wlo );
    canopy->setHookKnife( spinalCord->trigger_hook );


    // update reserve canopy controls
	if (_jumper->isPlayer() &&
		_jumper->getCanopyReserveSimulator() &&
		_jumper->getDominantCanopy() != _jumper->getCanopyReserveSimulator() && 
		_jumper->getCanopyReserveSimulator()->isOpened()) {

		// set toggles
		CanopySimulator *reserve_canopy = _jumper->getCanopyReserveSimulator();
		reserve_canopy->setLeftDeep( spinalCord->leftReserve * penalty );
		reserve_canopy->setRightDeep( spinalCord->rightReserve * penalty );
		// set risers
		reserve_canopy->setLeftWarpDeep( spinalCord->leftReserveWarp * penalty );
		reserve_canopy->setRightWarpDeep( spinalCord->rightReserveWarp * penalty );
		reserve_canopy->setLeftRearRiser( spinalCord->leftReserveRearRiser * penalty );
		reserve_canopy->setRightRearRiser( spinalCord->rightReserveRearRiser * penalty );

		reserve_canopy->setWLOToggles( spinalCord->trigger_wlo );
		reserve_canopy->setHookKnife( spinalCord->trigger_hook );
	}
    // determine animation sequence to be played
    _targetSequence = &passiveFlightSequence;

	// get total left and right input
	float totalInputLeft = 0.0f;
	float totalInputRight = 0.0f;
	float toggleLeft = spinalCord->left;
	float toggleRight = spinalCord->right;
	if (canopy->getLeftForcedDeep() != -1.0f) toggleLeft = 0.0f;
	if (canopy->getRightForcedDeep() != -1.0f) toggleRight = 0.0f;

	// hard toggle input if unstowing
	if (canopy->getLeftStowed() && spinalCord->trigger_left) {
		toggleLeft = 0.75f;
	}
	if (canopy->getRightStowed() && spinalCord->trigger_right) {
		toggleRight = 0.75f;
	}

	// set toggles
	canopy->setLeftDeep( spinalCord->left * penalty );
	canopy->setRightDeep( spinalCord->right * penalty );

	if (toggleLeft > spinalCord->leftRearRiser && toggleLeft > spinalCord->leftWarp) {
		totalInputLeft = toggleLeft;
	} else if (spinalCord->leftRearRiser > toggleLeft && spinalCord->leftRearRiser > spinalCord->leftWarp) {
		totalInputLeft = spinalCord->leftRearRiser;
	} else {
		totalInputLeft = spinalCord->leftWarp;
	}
	if (toggleRight > spinalCord->rightRearRiser && toggleRight > spinalCord->rightWarp) {
		totalInputRight = toggleRight;
	} else if (spinalCord->rightRearRiser > toggleRight && spinalCord->rightRearRiser > spinalCord->rightWarp) {
		totalInputRight = spinalCord->rightRearRiser;
	} else {
		totalInputRight = spinalCord->rightWarp;
	}


	if( totalInputLeft != 0 && totalInputRight == 0 ) {
		if (canopy->getLeftStowed() && spinalCord->trigger_left) {
			_targetSequence = &unstowLeftSequence;
		} else if (spinalCord->modifier) {
			_targetSequence = &steerLeftSequenceHalf;
		} else {
			_targetSequence = &steerLeftSequence;
		}
	}
	if( totalInputRight != 0 && totalInputLeft == 0 ) {
		if (canopy->getRightStowed() && spinalCord->trigger_right) {
			_targetSequence = &unstowRightSequence;
		} else if (spinalCord->modifier) {
			_targetSequence = &steerRightSequenceHalf;
		} else {
			_targetSequence = &steerRightSequence;
		}
	}
	if( totalInputLeft != 0 && totalInputRight != 0 ) {
		if (canopy->getLeftStowed() || canopy->getRightStowed()) {
			_targetSequence = &groupingUnstowSequence;
		} else if (spinalCord->modifier) {
			_targetSequence = &groupingSequenceHalf;
		} else {
			_targetSequence = &groupingSequence;
		}
	}

	// unstow toggles
	if (spinalCord->left > 0.1f) {
		canopy->setLeftStowed(false);
	}
	if (spinalCord->right > 0.1f) {
		canopy->setRightStowed(false);
	}

    // local coordinate system of base jumper
    NxMat34 pose = _phActor->getGlobalPose();
    NxVec3 x = pose.M.getColumn(0);
    NxVec3 y = pose.M.getColumn(1);
    NxVec3 z = pose.M.getColumn(2);



	// altitude [m]
	//NxVec3 pos = _phActor->getGlobalPosition();
	//const float altitude = pos.y;
	//const float arch_pose_area = 1.9f;

	//// air density: converted to linear from barometric equation [0:10] km altitude
	//// http://www.denysschen.com/catalogue/density.aspx
	//const float AirDensityOld = altitude <= 10000.0f ? (1.196f - 0.0000826f * altitude) : (0.27f);

	//// add drag force
	//float Cd = 0.4f;	// altitude suit = 0.4f
	//const float mTracking = database::Suit::getRecord( _jumper->getVirtues()->equipment.suit.id )->mTracking;
	//Cd *= mTracking;
	//// Drag force vector
	//NxVec3 VecFd = -_phActor->getLinearVelocity();
	//VecFd.normalize();

	//float Fd = 0.5f * AirDensityOld * velocity.magnitudeSquared() * Cd * arch_pose_area * getCore()->getRandToolkit()->getUniform(0.94f, 1.06f);
	//_phActor->addForceAtLocalPos(Fd*VecFd, NxVec3(0, -3.0f, 0));

    // air resistance coefficient
    const float ARmult = 2.5f;
    float AR = ARmult * virtues->getTrackingAirResistance();
    if( database::Suit::getRecord( virtues->equipment.suit.id )->wingsuit )
    {
        AR = ARmult * virtues->getFrogAirResistance();
    }

    // terminal velocity
    const float Vt = sqrt( 9.8f * _phActor->getMass() / AR );
    const float It = velocity.magnitude() / Vt;

    NxVec3 dir = velocity * -1;
    dir.normalize();

    // air resistance force
    const NxVec3 Far = dir * getAirResistancePower( velocity.magnitude() / Vt ) * _phActor->getMass() * 9.8f;

    // finalize motion equation    
    _phActor->addForce( Far );
}
Exemple #14
0
void CanopySimulator::Rope::initialize(NxActor* actor1, NxVec3 anchor1, NxActor* actor2, NxVec3 anchor2)
{
    _nxActor1 = actor1; assert( _nxActor1 );
    _nxActor2 = actor2; assert( _nxActor2 );
    _anchor1 = anchor1;
    _anchor2 = anchor2;

    // calculate worldspace positions for connections points
    Matrix4f ltm1  = wrap( _nxActor1->getGlobalPose() );
    Matrix4f ltm2  = wrap( _nxActor2->getGlobalPose() );
    NxVec3 pos1 = wrap( Gameplay::iEngine->transformCoord( wrap( _anchor1 ), ltm1 ) );
    NxVec3 pos2 = wrap( Gameplay::iEngine->transformCoord( wrap( _anchor2 ), ltm2 ) );
    NxVec3 dir  = pos2 - pos1;

    // check distance btw connection points (correction just for stability purpose)
    float idist = dir.magnitude();
    dir.normalize();

    // create intermediate segment bodies
    NxVec3 pos = pos1;
    float step = idist / _numJoints;
    for( unsigned int i=0; i<_numJoints-1; i++ )
    {
        // segment position
        pos += dir * step;
        // create segment body
        NxBodyDesc nxBodyDesc;
        nxBodyDesc.mass = _mass / ( _numJoints - 1 );
        nxBodyDesc.massSpaceInertia.set( nxBodyDesc.mass, nxBodyDesc.mass, nxBodyDesc.mass );
        nxBodyDesc.linearDamping = 2.0f;
        nxBodyDesc.angularDamping = 0.0f;
        nxBodyDesc.flags = NX_BF_VISUALIZATION;
        nxBodyDesc.solverIterationCount = 32;
        NxActorDesc nxActorDesc;
        nxActorDesc.body = &nxBodyDesc;
        nxActorDesc.globalPose.M.id();
        nxActorDesc.globalPose.t = pos;
        _nxSegmentBody[i] = _nxScene->createActor( nxActorDesc );
        assert( _nxSegmentBody[i] );
        // initialize velocity
        _nxSegmentBody[i]->addForce( _nxActor1->getLinearVelocity(), NX_VELOCITY_CHANGE );
    }

    // create joints
    for( i=0; i<_numJoints; i++ )
    {
        // first joint (actor1-segment1)
        if( i == 0 )
        {
            NxDistanceJointDesc jointDesc;
            jointDesc.actor[0] = _nxActor1;
            jointDesc.actor[1] = _nxSegmentBody[0];
            jointDesc.maxDistance = _length / _numJoints;
            jointDesc.minDistance = 0.0f;
            jointDesc.flags = NX_DJF_MAX_DISTANCE_ENABLED;
            jointDesc.localAnchor[0] = _anchor1;
            jointDesc.localAnchor[1].set( 0,0,0 );
            jointDesc.jointFlags = NX_JF_VISUALIZATION;
            _nxSegmentJoint[i] = _nxScene->createJoint( jointDesc );
            assert( _nxSegmentJoint[i] );
        }
        // last joint (segmentN-actor2)
        else if( i == _numJoints-1 )
        {
            NxDistanceJointDesc jointDesc;
            jointDesc.actor[0] = _nxSegmentBody[_numJoints-2];
            jointDesc.actor[1] = _nxActor2;
            jointDesc.maxDistance = _length / _numJoints;
            jointDesc.minDistance = 0.0f;
            jointDesc.flags = NX_DJF_MAX_DISTANCE_ENABLED;
            jointDesc.localAnchor[0].set( 0,0,0 );
            jointDesc.localAnchor[1] = _anchor2;
            jointDesc.jointFlags = NX_JF_VISUALIZATION;
            _nxSegmentJoint[i] = _nxScene->createJoint( jointDesc );
            assert( _nxSegmentJoint[i] );
        }
        // intermediate joint
        else
        {
            NxDistanceJointDesc jointDesc;
            jointDesc.actor[0] = _nxSegmentBody[i-1];
            jointDesc.actor[1] = _nxSegmentBody[i];
            jointDesc.maxDistance = _length / _numJoints;
            jointDesc.minDistance = 0.0f;
            jointDesc.flags = NX_DJF_MAX_DISTANCE_ENABLED;
            jointDesc.localAnchor[0].set( 0,0,0 );
            jointDesc.localAnchor[1].set( 0,0,0 );
            jointDesc.jointFlags = NX_JF_VISUALIZATION;
            _nxSegmentJoint[i] = _nxScene->createJoint( jointDesc );
            assert( _nxSegmentJoint[i] );
        }
    }
}
void DrawWireCapsule(const NxCapsule& capsule, const NxVec3& color)
{
	NxReal r = capsule.radius;
	NxVec3 dir = capsule.p0 - capsule.p1;
	NxReal h = dir.magnitude();
	NxMat34 pose;
	pose.t = (capsule.p0 + capsule.p1)*0.5f;

	if(h!=0.0f)
	{
		dir/=h;
		NxVec3 right, up;
		computeBasis(dir, right, up);
		pose.M.setColumn(0, right);
		pose.M.setColumn(1, dir);
		pose.M.setColumn(2, up);
	}
	else
	{
		pose.M.id();
	}

//	NxMat34 pose = capsule->getGlobalPose();
//	const NxReal & r = capsule->isCapsule()->getRadius();
//	const NxReal & h = capsule->isCapsule()->getHeight();



	NxSegment SG;
	pose.M.getColumn(1, SG.p1);
	SG.p1 *= 0.5f*h;
	SG.p0 = -SG.p1;
	SG.p0 += pose.t;
	SG.p1 += pose.t;

	NxVec3 c0;	pose.M.getColumn(0, c0);
	NxVec3 c1;	pose.M.getColumn(1, c1);
	NxVec3 c2;	pose.M.getColumn(2, c2);
	DrawLine(SG.p0 + c0*r, SG.p1 + c0*r, color);
	DrawLine(SG.p0 - c0*r, SG.p1 - c0*r, color);
	DrawLine(SG.p0 + c2*r, SG.p1 + c2*r, color);
	DrawLine(SG.p0 - c2*r, SG.p1 - c2*r, color);

	pose.M.setColumn(0, -c1);
	pose.M.setColumn(1, -c0);
	pose.M.setColumn(2, c2);
	pose.t = SG.p0;
	DrawCircle(20, pose, color, r, true);	//halfcircle -- flipped

	pose.M.setColumn(0, c1);
	pose.M.setColumn(1, -c0);
	pose.M.setColumn(2, c2);
	pose.t = SG.p1;
	DrawCircle(20, pose, color, r, true);

	pose.M.setColumn(0, -c1);
	pose.M.setColumn(1, c2);
	pose.M.setColumn(2, c0);
	pose.t = SG.p0;
	DrawCircle(20, pose, color, r, true);//halfcircle -- good

	pose.M.setColumn(0, c1);
	pose.M.setColumn(1, c2);
	pose.M.setColumn(2, c0);
	pose.t = SG.p1;
	DrawCircle(20, pose, color, r, true);

	pose.M.setColumn(0, c2);
	pose.M.setColumn(1, c0);
	pose.M.setColumn(2, c1);
	pose.t = SG.p0;
	DrawCircle(20, pose, color, r);	//full circle
	pose.t = SG.p1;
	DrawCircle(20, pose, color, r);
}
void NPCFreefall_DZ::onUpdate(float dt)
{
    // obtain spinal cord
    SpinalCord* spinalCord = getNPC()->getSpinalCord();
    spinalCord->reset();

    // update target position
    Matrix4f catToyPose = getNPC()->getCatToy()->getCurrentPose();
	
    _targetPos.set( catToyPose[3][0], catToyPose[3][1], catToyPose[3][2] );

	// jump only when the wind is right
	Vector2f pos = Vector2f(catToyPose[3][0], catToyPose[3][2]);
	pos.normalize();
	
	NxVec3 wind = getNPC()->getJumper()->getScene()->getWindAtPoint(NxVec3(catToyPose[3][0], catToyPose[3][1], catToyPose[3][2]));
	wind.normalize();
	Vector2f wind2(wind.x, wind.z);
	float wind_angle = 0.0;
	if (wind.magnitude() < 1.5f) {
		wind_angle = 1.0f;
	} else {
		wind2.normalize();
		wind_angle = pos.dot(wind2);
	}


    // if my character is still roaming
	if (wind_angle >= 0.8f && catToyPose[3][1] >= 300.0f) _timeUntilJump -= dt;
	//getCore()->logMessage("%s has %2.4f seconds to jump", getNPC()->getNPCName(), _timeUntilJump);

	if( _timeUntilJump <= 0.0f && getNPC()->getJumper()->getPhase() == ::jpRoaming )
    {
		Vector3f pos = Vector3f(catToyPose[3][0], catToyPose[3][1], catToyPose[3][2]);
        // if npc on airplane
        if( getNPC()->getJumper()->getAirplane() != NULL )
        {
            // just jump!
            spinalCord->phase = true;
            return;
        }
        // if npc at the exit point and ready to jump        
        else if( _positionIsSucceed && _directionIsSucceed )
        {
            // jump!
            spinalCord->phase = true;
            return;            
        }
        // if npc at the exit point and not surely ready to clear jump
        else
        {
            if( !_positionIsSucceed )
            {
                // move to abyss
                Matrix4f jumpPose = getNPC()->getCatToy()->getJumpPose();
                Vector3f jumpPos( jumpPose[3][0], jumpPose[3][1], jumpPose[3][2] );
                call( new NPCMove( getNPC(), jumpPos ) );
                _positionIsSucceed = true;
                return;
            }
            if( !_directionIsSucceed )
            {
                // jumper absolute orientation
                Vector3f jumperAt = getNPC()->getJumper()->getClump()->getFrame()->getAt();
                jumperAt.normalize();

                // direction of cat toy jump
                Matrix4f jumpPose = getNPC()->getCatToy()->getJumpPose();
                Vector3f targetDir( jumpPose[2][0], 0.0f, jumpPose[2][2] );
                targetDir.normalize();

                // angle to target
                Vector3f atH = jumperAt; atH[1] = 0; atH.normalize();
                Vector3f dirH = targetDir; dirH[1] = 0; dirH.normalize();
                float targetAngle = ::calcAngle( dirH, atH, Vector3f( 0,1,0 ) );

                if( fabs( targetAngle ) < 1.0f )
                {
                    _directionIsSucceed = true;
                    return;
                }
                else
                {
                    // turn jumper by AI algo
                    float aiRotationVel = 180.0f;
                    float aiRotationAngle = sgn( targetAngle ) * aiRotationVel * dt;
                    if( fabs( aiRotationAngle ) > fabs( targetAngle ) ) aiRotationAngle = targetAngle;
                    getNPC()->getJumper()->getClump()->getFrame()->rotateRelative( Vector3f( 0,1,0 ), aiRotationAngle );
                }
            }
        }
    }
    // else, turn & track towards the target
    else if( getNPC()->getJumper()->getPhase() == ::jpFreeFalling )
    {
         // jumper absolute orientation
        Vector3f jumperAt = getNPC()->getJumper()->getClump()->getFrame()->getAt();
        jumperAt.normalize();

        Vector3f jumperRight = getNPC()->getJumper()->getClump()->getFrame()->getRight();
        jumperRight.normalize();

        Vector3f jumperUp = getNPC()->getJumper()->getClump()->getFrame()->getUp();
        jumperUp.normalize();

        // retrieve current jumper position    
        Vector3f jumperPos = getNPC()->getJumper()->getClump()->getFrame()->getPos();
        jumperPos += Vector3f( 0, jumperRoamingSphereSize, 0 );

		// wingsuit
		bool wingsuit = database::Suit::getRecord(getNPC()->getJumper()->getVirtues()->equipment.suit.id)->wingsuit;

		// leveling
		// wlo - when npc higher
		//if (!wingsuit) {
		//	if (jumperPos[1] - _targetPos[1] > 1500.0f) {
		//		spinalCord->wlo = true;
		//	} else if (jumperPos[1] - _targetPos[1] < -1500.0f)  {
		//		spinalCord->hook = true;
		//	}
		//}

        // direction to target
        Vector3f targetDir = _targetPos - jumperPos;
        float distanceToTarget = Vector3f( targetDir[0], 0, targetDir[2] ).length();
        targetDir.normalize();

		// landing too far away? let's deploy in order to return safely
		// glide ratio is based on canopy size
		database::Canopy *canopy = database::Canopy::getRecord(getNPC()->getJumper()->getVirtues()->equipment.canopy.id);
		Vector3f pos = getNPC()->getJumper()->getClump()->getFrame()->getPos();
		float glide = canopy->square / 150.0f;
		float alt = pos[1];
		pos[1] = 0;
		bool farEnough = pos.length() >= alt*glide;
		//getCore()->logMessage("alt: %2.5f; dst: %2.5f; coverage: %2.5f", alt, pos.length(), alt*glide);
		// deploy now?
		if ((alt <= 85000.0f || farEnough) && alt <= 150000.0f) {
			if (getNPC()->getJumper()->getCanopySimulator()) {
				//getCore()->logMessage("npc pull. Far enough: %d", (int)farEnough);
				spinalCord->phase = true;
				spinalCord->modifier = wingsuit;
			} else {
				//getCore()->logMessage("npc pull reserve. Far enough: %d", (int)farEnough);
				spinalCord->pullReserve = true;
				spinalCord->modifier = wingsuit;
			}
		}

        // if toy tracking modifier is on
		if( wingsuit /* getNPC()->getCatToy()->getModifier()*/ )
        {
            // sum up target direction 
            Vector3f targetFlatAt(
                getNPC()->getCatToy()->getCurrentPose()[2][0],
                0,
                getNPC()->getCatToy()->getCurrentPose()[2][2]
            );
            /*getCore()->logMessage(                 
                "POS: %3.2f %3.2f %3.2f AT : %3.2f 0.0 %3.2f", 
                getNPC()->getCatToy()->getCurrentPose()[3][0],
                getNPC()->getCatToy()->getCurrentPose()[3][1],
                getNPC()->getCatToy()->getCurrentPose()[3][2],
                targetFlatAt[0], targetFlatAt[2] 
            );*/
            targetFlatAt.normalize();
            targetDir += targetFlatAt * 3;
            targetDir.normalize();
        }

        // horizontal steering
		float minAngle = 5.0f;
		float minValue = 0.0f;
        float maxAngle = 45.0f;
        float maxValue = 1.0f;

        // angle to target
		Vector3f atH = jumperAt; 
		// headdown
		if (getNPC()->getJumper()->getDefaultPose() == 1) {
			atH = jumperUp;
			minAngle = 25.0f;
			maxValue = 0.1f;
		// sitfly
		} else if (getNPC()->getJumper()->getDefaultPose() == 2) {
			atH = jumperUp;
			atH[2] *= -1;
			//minAngle = 25.0f;
			maxValue = 0.1f;
		}

        atH[1] = 0; atH.normalize();
        Vector3f dirH = targetDir; dirH[1] = 0; dirH.normalize();
        float targetAngle = ::calcAngle( dirH, atH, Vector3f( 0,1,0 ) );

        // inclination angle relative to the horizont
        float horizontalAngle = -1 * ::calcAngle( atH, jumperUp, jumperRight );

        // horizontal steering 
        float factor = ( fabs( targetAngle ) - minAngle ) / ( maxAngle - minAngle );
        factor = ( factor < 0 ) ? 0 : ( ( factor > 1 ) ? 1 : factor );
        float impulse = minValue * ( 1 - factor ) + maxValue * factor;
		
		if (wingsuit) impulse = 0.0f;
        // smooth impulse
        impulse = pow( impulse, 1.25f );
		if (alt <= 130000.0f) impulse = 0.0f;
        // apply impulse
        if( targetAngle < 0 )
        {            
            spinalCord->right = impulse;
        }
        else
        {
            spinalCord->left = impulse;
        }
       
        // relation btw desired inclination and target angle
        minAngle = 5.0f;
        minValue = 25.0f;
        maxAngle = 90.0f;
        maxValue = 0.0f;

        factor = ( fabs( targetAngle ) - minAngle ) / ( maxAngle - minAngle );
        factor = ( factor < 0 ) ? 0 : ( ( factor > 1 ) ? 1 : factor );
        float desiredInclination = minValue * ( 1 - factor ) + maxValue * factor;

        // inclination difference
        float inclinationDifference = desiredInclination - horizontalAngle;

        // vertical steering
        minAngle = 0.0f;
        minValue = 0.0f;
        maxAngle = 30.0f;
        maxValue = 1.0f;
        factor = ( fabs( inclinationDifference ) - minAngle ) / ( maxAngle - minAngle );
        factor = ( factor < 0 ) ? 0 : ( ( factor > 1 ) ? 1 : factor );
        impulse = minValue * ( 1 - factor ) + maxValue * factor;

		if (!wingsuit && distanceToTarget > 2500.0f && alt > 130000.0f) {
			if( inclinationDifference < 0 )
			{            
				spinalCord->down += impulse;
				if (spinalCord->down > 1.0f) spinalCord->down = 1.0f;
			}
			else
			{
				spinalCord->up += impulse;
				if (spinalCord->up > 1.0f) spinalCord->up = 1.0f;
			}
		}

        // tracking modifier
        if( fabs( targetAngle ) < 90.0f && distanceToTarget > 2500.0f )
        {
            spinalCord->modifier = 0.0f;
			spinalCord->trigger_modifier = false;
        }
        else
        {
            spinalCord->modifier = 0.0f;
			spinalCord->trigger_modifier = false;
        }

		if (wingsuit || alt <= 130000.0f) spinalCord->modifier = 1.0f;
		if (wingsuit || alt <= 130000.0f) spinalCord->trigger_modifier = true;
		return;

        // force tracking in several condition        
        if( getNPC()->getCatToy()->getModifier() )
        {
            // not a skydiving?
            if( !getNPC()->getJumper()->getCanopySimulator()->getGearRecord()->skydiving )
            {
                // imitate cat toy modifier
                spinalCord->modifier = getNPC()->getCatToy()->getModifier();
            }
            else
            {
                Vector3f cattoyFaceH( catToyPose[2][0], 0, catToyPose[2][2] );
                cattoyFaceH.normalize();
                Vector3f npcFaceH = getNPC()->getJumper()->getClump()->getFrame()->getAt();
                npcFaceH[1] = 0;
                npcFaceH.normalize();
                //if( Vector3f::dot( dirH, cattoyFaceH ) > 0.85f ) spinalCord->modifier = true;
            }
        }
    }
}