diff options
| author | Loren Shih <seraph@lindenlab.com> | 2011-04-20 12:37:44 -0400 | 
|---|---|---|
| committer | Loren Shih <seraph@lindenlab.com> | 2011-04-20 12:37:44 -0400 | 
| commit | 8b0640704d58984efd0d54e3350d21e9f5845c85 (patch) | |
| tree | ece45a431f9398219740dfc97581ecf0388c4fd8 | |
| parent | 91409d40cb4171815b7ef9f767dc5c5e8d5f3e44 (diff) | |
SH-1381 FIXED avatar physics behavior is tightly tied to viewer framerate
Breaking up physics into smaller integration steps.
| -rw-r--r-- | indra/newview/llphysicsmotion.cpp | 354 | 
1 files changed, 184 insertions, 170 deletions
| diff --git a/indra/newview/llphysicsmotion.cpp b/indra/newview/llphysicsmotion.cpp index 5c4d006288..e4335d968f 100644 --- a/indra/newview/llphysicsmotion.cpp +++ b/indra/newview/llphysicsmotion.cpp @@ -43,7 +43,8 @@  typedef std::map<std::string, std::string> controller_map_t;
  typedef std::map<std::string, F32> default_controller_map_t;
 -#define MIN_REQUIRED_PIXEL_AREA_AVATAR_PHYSICS_MOTION 0.f;
 +#define MIN_REQUIRED_PIXEL_AREA_AVATAR_PHYSICS_MOTION 0.f
 +#define TIME_ITERATION_STEP 0.1f
  inline F64 llsgn(const F64 a)
  {
 @@ -453,7 +454,8 @@ BOOL LLPhysicsMotion::onUpdate(F32 time)  		return FALSE;
  	}
 -        if (time_delta > 3.0)
 +	// If less than 1FPS, we don't want to be spending time updating physics at all.
 +        if (time_delta > 1.0)
          {
                  mLastTime = time;
                  return FALSE;
 @@ -481,195 +483,207 @@ BOOL LLPhysicsMotion::onUpdate(F32 time)          if (physics_test)
                  behavior_maxeffect = 1.0f;
 -        // mPositon_local should be in normalized 0,1 range already.  Just making sure...
 -        F32 position_current_local = llclamp(mPosition_local,
 -                                             0.0f,
 -                                             1.0f);
 -
 -        // Normalize the param position to be from [0,1].
 -        // We have to use normalized values because there may be more than one driven param,
 -        // and each of these driven params may have its own range.
 -        // This means we'll do all our calculations in normalized [0,1] local coordinates.
 -        F32 position_user_local = mParamDriver->getWeight();
 -        position_user_local = (position_user_local - mParamDriver->getMinWeight()) / (mParamDriver->getMaxWeight() - mParamDriver->getMinWeight());
 -
 -        // If the effect is turned off then don't process unless we need one more update
 -        // to set the position to the default (i.e. user) position.
 -        if ((behavior_maxeffect == 0) && (position_current_local == position_user_local))
 -        {
 -            return FALSE;
 -        }
 -
 -        //
 -        // End parameters and settings
 -        ////////////////////////////////////////////////////////////////////////////////
 -
 -
 -        ////////////////////////////////////////////////////////////////////////////////
 -        // Calculate velocity and acceleration in parameter space.
 -        //
 +	BOOL update_visuals = FALSE; 
 +	// Break up the physics into a bunch of iterations so that differing framerates will show
 +	// roughly the same behavior.
 +	for (F32 time_iteration = 0; time_iteration <= time_delta; time_iteration += TIME_ITERATION_STEP)
 +	{
 +		F32 time_iteration_step = TIME_ITERATION_STEP;
 +		if (time_iteration + TIME_ITERATION_STEP > time_delta)
 +		{
 +			time_iteration_step = time_delta;
 +		}
 +		
 +
 +		// mPositon_local should be in normalized 0,1 range already.  Just making sure...
 +		F32 position_current_local = llclamp(mPosition_local,
 +						     0.0f,
 +						     1.0f);
 +
 +		// Normalize the param position to be from [0,1].
 +		// We have to use normalized values because there may be more than one driven param,
 +		// and each of these driven params may have its own range.
 +		// This means we'll do all our calculations in normalized [0,1] local coordinates.
 +		F32 position_user_local = mParamDriver->getWeight();
 +		position_user_local = (position_user_local - mParamDriver->getMinWeight()) / (mParamDriver->getMaxWeight() - mParamDriver->getMinWeight());
 +
 +		// If the effect is turned off then don't process unless we need one more update
 +		// to set the position to the default (i.e. user) position.
 +		if ((behavior_maxeffect == 0) && (position_current_local == position_user_local))
 +		{
 +			return FALSE;
 +		}
 +
 +		//
 +		// End parameters and settings
 +		////////////////////////////////////////////////////////////////////////////////
 +
 +
 +		////////////////////////////////////////////////////////////////////////////////
 +		// Calculate velocity and acceleration in parameter space.
 +		//
 -        const F32 velocity_joint_local = calculateVelocity_local(time_delta);
 -        const F32 acceleration_joint_local = calculateAcceleration_local(velocity_joint_local, time_delta);
 +		const F32 velocity_joint_local = calculateVelocity_local(time_iteration_step);
 +		const F32 acceleration_joint_local = calculateAcceleration_local(velocity_joint_local, time_iteration_step);
 -        //
 -        // End velocity and acceleration
 -        ////////////////////////////////////////////////////////////////////////////////
 +		//
 +		// End velocity and acceleration
 +		////////////////////////////////////////////////////////////////////////////////
 -        ////////////////////////////////////////////////////////////////////////////////
 -        // Calculate the total force 
 -        //
 +		////////////////////////////////////////////////////////////////////////////////
 +		// Calculate the total force 
 +		//
 -        // Spring force is a restoring force towards the original user-set breast position.
 -        // F = kx
 -        const F32 spring_length = position_current_local - position_user_local;
 -        const F32 force_spring = -spring_length * behavior_spring;
 +		// Spring force is a restoring force towards the original user-set breast position.
 +		// F = kx
 +		const F32 spring_length = position_current_local - position_user_local;
 +		const F32 force_spring = -spring_length * behavior_spring;
 -        // Acceleration is the force that comes from the change in velocity of the torso.
 -        // F = ma
 -        const F32 force_accel = behavior_gain * (acceleration_joint_local * behavior_mass);
 +		// Acceleration is the force that comes from the change in velocity of the torso.
 +		// F = ma
 +		const F32 force_accel = behavior_gain * (acceleration_joint_local * behavior_mass);
 -        // Gravity always points downward in world space.
 -        // F = mg
 -        const LLVector3 gravity_world(0,0,1);
 -        const F32 force_gravity = behavior_gain * (toLocal(gravity_world) * behavior_gravity * behavior_mass);
 +		// Gravity always points downward in world space.
 +		// F = mg
 +		const LLVector3 gravity_world(0,0,1);
 +		const F32 force_gravity = behavior_gain * (toLocal(gravity_world) * behavior_gravity * behavior_mass);
 -        // Damping is a restoring force that opposes the current velocity.
 -        // F = -kv
 -        const F32 force_damping = -behavior_damping * mVelocity_local;
 +		// Damping is a restoring force that opposes the current velocity.
 +		// F = -kv
 +		const F32 force_damping = -behavior_damping * mVelocity_local;
 -        // Drag is a force imparted by velocity (intuitively it is similar to wind resistance)
 -        // F = .5kv^2
 -        const F32 force_drag = .5*behavior_drag*velocity_joint_local*velocity_joint_local*llsgn(velocity_joint_local);
 +		// Drag is a force imparted by velocity (intuitively it is similar to wind resistance)
 +		// F = .5kv^2
 +		const F32 force_drag = .5*behavior_drag*velocity_joint_local*velocity_joint_local*llsgn(velocity_joint_local);
 -        const F32 force_net = (force_accel + 
 -                               force_gravity +
 -                               force_spring + 
 -                               force_damping + 
 -                               force_drag);
 +		const F32 force_net = (force_accel + 
 +				       force_gravity +
 +				       force_spring + 
 +				       force_damping + 
 +				       force_drag);
 -        //
 -        // End total force
 -        ////////////////////////////////////////////////////////////////////////////////
 +		//
 +		// End total force
 +		////////////////////////////////////////////////////////////////////////////////
 -        ////////////////////////////////////////////////////////////////////////////////
 -        // Calculate new params
 -        //
 -
 -        // Calculate the new acceleration based on the net force.
 -        // a = F/m
 -        const F32 acceleration_new_local = force_net / behavior_mass;
 -        static const F32 max_acceleration = 10.0f; // magic number, used to be customizable.
 -        F32 velocity_new_local = mVelocity_local + acceleration_new_local;
 -        velocity_new_local = llclamp(velocity_new_local, 
 -                                     -max_acceleration, max_acceleration);
 +		////////////////////////////////////////////////////////////////////////////////
 +		// Calculate new params
 +		//
 +
 +		// Calculate the new acceleration based on the net force.
 +		// a = F/m
 +		const F32 acceleration_new_local = force_net / behavior_mass;
 +		static const F32 max_acceleration = 10.0f; // magic number, used to be customizable.
 +		F32 velocity_new_local = mVelocity_local + acceleration_new_local;
 +		velocity_new_local = llclamp(velocity_new_local, 
 +					     -max_acceleration, max_acceleration);
 -        // Temporary debugging setting to cause all avatars to move, for profiling purposes.
 -        if (physics_test)
 -        {
 -                velocity_new_local = sin(time*4.0);
 -        }
 -        // Calculate the new parameters, or remain unchanged if max speed is 0.
 -        F32 position_new_local = position_current_local + velocity_new_local*time_delta;
 -        if (behavior_maxeffect == 0)
 -            position_new_local = position_user_local;
 -
 -        // Zero out the velocity if the param is being pushed beyond its limits.
 -        if ((position_new_local < 0 && velocity_new_local < 0) || 
 -            (position_new_local > 1 && velocity_new_local > 0))
 -        {
 -                velocity_new_local = 0;
 -        }
 +		// Temporary debugging setting to cause all avatars to move, for profiling purposes.
 +		if (physics_test)
 +		{
 +			velocity_new_local = sin(time*4.0);
 +		}
 +		// Calculate the new parameters, or remain unchanged if max speed is 0.
 +		F32 position_new_local = position_current_local + velocity_new_local*time_iteration_step;
 +		if (behavior_maxeffect == 0)
 +			position_new_local = position_user_local;
 +
 +		// Zero out the velocity if the param is being pushed beyond its limits.
 +		if ((position_new_local < 0 && velocity_new_local < 0) || 
 +		    (position_new_local > 1 && velocity_new_local > 0))
 +		{
 +			velocity_new_local = 0;
 +		}
 -	// Check for NaN values.  A NaN value is detected if the variables doesn't equal itself.  
 -	// If NaN, then reset everything.
 -	if ((mPosition_local != mPosition_local) ||
 -	    (mVelocity_local != mVelocity_local) ||
 -	    (position_new_local != position_new_local))
 -	{
 -		position_new_local = 0;
 -		position_current_local = 0;
 -		position_user_local = 0;
 -		mVelocity_local = 0;
 -		mVelocityJoint_local = 0;
 -		mAccelerationJoint_local = 0;
 -		mPosition_local = 0;
 -		mPosition_world = LLVector3(0,0,0);
 -	}
 -
 -        const F32 position_new_local_clamped = llclamp(position_new_local,
 -						       0.0f,
 -						       1.0f);
 -
 -        LLDriverParam *driver_param = dynamic_cast<LLDriverParam *>(mParamDriver);
 -        llassert_always(driver_param);
 -        if (driver_param)
 -        {
 -                // If this is one of our "hidden" driver params, then make sure it's
 -                // the default value.
 -                if ((driver_param->getGroup() != VISUAL_PARAM_GROUP_TWEAKABLE) &&
 -                    (driver_param->getGroup() != VISUAL_PARAM_GROUP_TWEAKABLE_NO_TRANSMIT))
 -                {
 -                        mCharacter->setVisualParamWeight(driver_param,
 -                                                         0,
 -                                                         FALSE);
 -                }
 -                for (LLDriverParam::entry_list_t::iterator iter = driver_param->mDriven.begin();
 -                     iter != driver_param->mDriven.end();
 -                     ++iter)
 -                {
 -                        LLDrivenEntry &entry = (*iter);
 -                        LLViewerVisualParam *driven_param = entry.mParam;
 -                        setParamValue(driven_param,position_new_local_clamped, behavior_maxeffect);
 -                }
 -        }
 +		// Check for NaN values.  A NaN value is detected if the variables doesn't equal itself.  
 +		// If NaN, then reset everything.
 +		if ((mPosition_local != mPosition_local) ||
 +		    (mVelocity_local != mVelocity_local) ||
 +		    (position_new_local != position_new_local))
 +		{
 +			position_new_local = 0;
 +			position_current_local = 0;
 +			position_user_local = 0;
 +			mVelocity_local = 0;
 +			mVelocityJoint_local = 0;
 +			mAccelerationJoint_local = 0;
 +			mPosition_local = 0;
 +			mPosition_world = LLVector3(0,0,0);
 +		}
 +
 +		const F32 position_new_local_clamped = llclamp(position_new_local,
 +							       0.0f,
 +							       1.0f);
 +
 +		LLDriverParam *driver_param = dynamic_cast<LLDriverParam *>(mParamDriver);
 +		llassert_always(driver_param);
 +		if (driver_param)
 +		{
 +			// If this is one of our "hidden" driver params, then make sure it's
 +			// the default value.
 +			if ((driver_param->getGroup() != VISUAL_PARAM_GROUP_TWEAKABLE) &&
 +			    (driver_param->getGroup() != VISUAL_PARAM_GROUP_TWEAKABLE_NO_TRANSMIT))
 +			{
 +				mCharacter->setVisualParamWeight(driver_param,
 +								 0,
 +								 FALSE);
 +			}
 +			for (LLDriverParam::entry_list_t::iterator iter = driver_param->mDriven.begin();
 +			     iter != driver_param->mDriven.end();
 +			     ++iter)
 +			{
 +				LLDrivenEntry &entry = (*iter);
 +				LLViewerVisualParam *driven_param = entry.mParam;
 +				setParamValue(driven_param,position_new_local_clamped, behavior_maxeffect);
 +			}
 +		}
 -        //
 -        // End calculate new params
 -        ////////////////////////////////////////////////////////////////////////////////
 +		//
 +		// End calculate new params
 +		////////////////////////////////////////////////////////////////////////////////
 -        ////////////////////////////////////////////////////////////////////////////////
 -        // Conditionally update the visual params
 -        //
 +		////////////////////////////////////////////////////////////////////////////////
 +		// Conditionally update the visual params
 +		//
 -        // Updating the visual params (i.e. what the user sees) is fairly expensive.
 -        // So only update if the params have changed enough, and also take into account
 -        // the graphics LOD settings.
 +		// Updating the visual params (i.e. what the user sees) is fairly expensive.
 +		// So only update if the params have changed enough, and also take into account
 +		// the graphics LOD settings.
 -        BOOL update_visuals = FALSE;
 -
 -        // For non-self, if the avatar is small enough visually, then don't update.
 -        const F32 area_for_max_settings = 0.0;
 -        const F32 area_for_min_settings = 1400.0;
 -        const F32 area_for_this_setting = area_for_max_settings + (area_for_min_settings-area_for_max_settings)*(1.0-lod_factor);
 -        const F32 pixel_area = fsqrtf(mCharacter->getPixelArea());
 +		// For non-self, if the avatar is small enough visually, then don't update.
 +		const F32 area_for_max_settings = 0.0;
 +		const F32 area_for_min_settings = 1400.0;
 +		const F32 area_for_this_setting = area_for_max_settings + (area_for_min_settings-area_for_max_settings)*(1.0-lod_factor);
 +		const F32 pixel_area = fsqrtf(mCharacter->getPixelArea());
 -        const BOOL is_self = (dynamic_cast<LLVOAvatarSelf *>(mCharacter) != NULL);
 -        if ((pixel_area > area_for_this_setting) || is_self)
 -        {
 -                const F32 position_diff_local = llabs(mPositionLastUpdate_local-position_new_local_clamped);
 -                const F32 min_delta = (1.0001f-lod_factor)*0.4f;
 -                if (llabs(position_diff_local) > min_delta)
 -                {
 -                        update_visuals = TRUE;
 -                        mPositionLastUpdate_local = position_new_local;
 -                }
 -        }
 +		const BOOL is_self = (dynamic_cast<LLVOAvatarSelf *>(mCharacter) != NULL);
 +		if ((pixel_area > area_for_this_setting) || is_self)
 +		{
 +			const F32 position_diff_local = llabs(mPositionLastUpdate_local-position_new_local_clamped);
 +			const F32 min_delta = (1.0001f-lod_factor)*0.4f;
 +			if (llabs(position_diff_local) > min_delta)
 +			{
 +				update_visuals = TRUE;
 +				mPositionLastUpdate_local = position_new_local;
 +			}
 +		}
 +
 +		//
 +		// End update visual params
 +		////////////////////////////////////////////////////////////////////////////////
 +
 +		mVelocityJoint_local = velocity_joint_local;
 +
 +		mVelocity_local = velocity_new_local;
 +		mAccelerationJoint_local = acceleration_joint_local;
 +		mPosition_local = position_new_local;
 +
 +		mPosition_world = joint->getWorldPosition();
 -        //
 -        // End update visual params
 -        ////////////////////////////////////////////////////////////////////////////////
 -
 -        mVelocityJoint_local = velocity_joint_local;
 -
 -        mVelocity_local = velocity_new_local;
 -        mAccelerationJoint_local = acceleration_joint_local;
 -        mPosition_local = position_new_local;
 -
 -        mPosition_world = joint->getWorldPosition();
 -        mLastTime = time;
 +	}
 +	mLastTime = time;
          /*
            // Write out debugging info into a spreadsheet.
 | 
