Skip to content
Snippets Groups Projects
Commit 8b064070 authored by Loren Shih's avatar Loren Shih
Browse files

SH-1381 FIXED avatar physics behavior is tightly tied to viewer framerate

Breaking up physics into smaller integration steps.
parent 91409d40
No related branches found
No related tags found
No related merge requests found
...@@ -43,7 +43,8 @@ ...@@ -43,7 +43,8 @@
typedef std::map<std::string, std::string> controller_map_t; typedef std::map<std::string, std::string> controller_map_t;
typedef std::map<std::string, F32> default_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) inline F64 llsgn(const F64 a)
{ {
...@@ -453,7 +454,8 @@ BOOL LLPhysicsMotion::onUpdate(F32 time) ...@@ -453,7 +454,8 @@ BOOL LLPhysicsMotion::onUpdate(F32 time)
return FALSE; 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; mLastTime = time;
return FALSE; return FALSE;
...@@ -481,195 +483,207 @@ BOOL LLPhysicsMotion::onUpdate(F32 time) ...@@ -481,195 +483,207 @@ BOOL LLPhysicsMotion::onUpdate(F32 time)
if (physics_test) if (physics_test)
behavior_maxeffect = 1.0f; behavior_maxeffect = 1.0f;
// mPositon_local should be in normalized 0,1 range already. Just making sure... BOOL update_visuals = FALSE;
F32 position_current_local = llclamp(mPosition_local, // Break up the physics into a bunch of iterations so that differing framerates will show
0.0f, // roughly the same behavior.
1.0f); for (F32 time_iteration = 0; time_iteration <= time_delta; time_iteration += TIME_ITERATION_STEP)
{
// Normalize the param position to be from [0,1]. F32 time_iteration_step = TIME_ITERATION_STEP;
// We have to use normalized values because there may be more than one driven param, if (time_iteration + TIME_ITERATION_STEP > time_delta)
// 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. time_iteration_step = time_delta;
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 // mPositon_local should be in normalized 0,1 range already. Just making sure...
// to set the position to the default (i.e. user) position. F32 position_current_local = llclamp(mPosition_local,
if ((behavior_maxeffect == 0) && (position_current_local == position_user_local)) 0.0f,
{ 1.0f);
return FALSE;
} // 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.
// End parameters and settings // 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
// Calculate velocity and acceleration in parameter space. // 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 velocity_joint_local = calculateVelocity_local(time_iteration_step);
const F32 acceleration_joint_local = calculateAcceleration_local(velocity_joint_local, time_delta); 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. // Spring force is a restoring force towards the original user-set breast position.
// F = kx // F = kx
const F32 spring_length = position_current_local - position_user_local; const F32 spring_length = position_current_local - position_user_local;
const F32 force_spring = -spring_length * behavior_spring; const F32 force_spring = -spring_length * behavior_spring;
// Acceleration is the force that comes from the change in velocity of the torso. // Acceleration is the force that comes from the change in velocity of the torso.
// F = ma // F = ma
const F32 force_accel = behavior_gain * (acceleration_joint_local * behavior_mass); const F32 force_accel = behavior_gain * (acceleration_joint_local * behavior_mass);
// Gravity always points downward in world space. // Gravity always points downward in world space.
// F = mg // F = mg
const LLVector3 gravity_world(0,0,1); const LLVector3 gravity_world(0,0,1);
const F32 force_gravity = behavior_gain * (toLocal(gravity_world) * behavior_gravity * behavior_mass); const F32 force_gravity = behavior_gain * (toLocal(gravity_world) * behavior_gravity * behavior_mass);
// Damping is a restoring force that opposes the current velocity. // Damping is a restoring force that opposes the current velocity.
// F = -kv // F = -kv
const F32 force_damping = -behavior_damping * mVelocity_local; const F32 force_damping = -behavior_damping * mVelocity_local;
// Drag is a force imparted by velocity (intuitively it is similar to wind resistance) // Drag is a force imparted by velocity (intuitively it is similar to wind resistance)
// F = .5kv^2 // F = .5kv^2
const F32 force_drag = .5*behavior_drag*velocity_joint_local*velocity_joint_local*llsgn(velocity_joint_local); const F32 force_drag = .5*behavior_drag*velocity_joint_local*velocity_joint_local*llsgn(velocity_joint_local);
const F32 force_net = (force_accel + const F32 force_net = (force_accel +
force_gravity + force_gravity +
force_spring + force_spring +
force_damping + force_damping +
force_drag); force_drag);
// //
// End total force // End total force
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
// Calculate new params // Calculate new params
// //
// Calculate the new acceleration based on the net force. // Calculate the new acceleration based on the net force.
// a = F/m // a = F/m
const F32 acceleration_new_local = force_net / behavior_mass; const F32 acceleration_new_local = force_net / behavior_mass;
static const F32 max_acceleration = 10.0f; // magic number, used to be customizable. static const F32 max_acceleration = 10.0f; // magic number, used to be customizable.
F32 velocity_new_local = mVelocity_local + acceleration_new_local; F32 velocity_new_local = mVelocity_local + acceleration_new_local;
velocity_new_local = llclamp(velocity_new_local, velocity_new_local = llclamp(velocity_new_local,
-max_acceleration, max_acceleration); -max_acceleration, max_acceleration);
// Temporary debugging setting to cause all avatars to move, for profiling purposes. // Temporary debugging setting to cause all avatars to move, for profiling purposes.
if (physics_test) if (physics_test)
{ {
velocity_new_local = sin(time*4.0); velocity_new_local = sin(time*4.0);
} }
// Calculate the new parameters, or remain unchanged if max speed is 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; F32 position_new_local = position_current_local + velocity_new_local*time_iteration_step;
if (behavior_maxeffect == 0) if (behavior_maxeffect == 0)
position_new_local = position_user_local; position_new_local = position_user_local;
// Zero out the velocity if the param is being pushed beyond its limits. // Zero out the velocity if the param is being pushed beyond its limits.
if ((position_new_local < 0 && velocity_new_local < 0) || if ((position_new_local < 0 && velocity_new_local < 0) ||
(position_new_local > 1 && velocity_new_local > 0)) (position_new_local > 1 && velocity_new_local > 0))
{ {
velocity_new_local = 0; velocity_new_local = 0;
} }
// Check for NaN values. A NaN value is detected if the variables doesn't equal itself. // Check for NaN values. A NaN value is detected if the variables doesn't equal itself.
// If NaN, then reset everything. // If NaN, then reset everything.
if ((mPosition_local != mPosition_local) || if ((mPosition_local != mPosition_local) ||
(mVelocity_local != mVelocity_local) || (mVelocity_local != mVelocity_local) ||
(position_new_local != position_new_local)) (position_new_local != position_new_local))
{ {
position_new_local = 0; position_new_local = 0;
position_current_local = 0; position_current_local = 0;
position_user_local = 0; position_user_local = 0;
mVelocity_local = 0; mVelocity_local = 0;
mVelocityJoint_local = 0; mVelocityJoint_local = 0;
mAccelerationJoint_local = 0; mAccelerationJoint_local = 0;
mPosition_local = 0; mPosition_local = 0;
mPosition_world = LLVector3(0,0,0); mPosition_world = LLVector3(0,0,0);
} }
const F32 position_new_local_clamped = llclamp(position_new_local, const F32 position_new_local_clamped = llclamp(position_new_local,
0.0f, 0.0f,
1.0f); 1.0f);
LLDriverParam *driver_param = dynamic_cast<LLDriverParam *>(mParamDriver); LLDriverParam *driver_param = dynamic_cast<LLDriverParam *>(mParamDriver);
llassert_always(driver_param); llassert_always(driver_param);
if (driver_param) if (driver_param)
{ {
// If this is one of our "hidden" driver params, then make sure it's // If this is one of our "hidden" driver params, then make sure it's
// the default value. // the default value.
if ((driver_param->getGroup() != VISUAL_PARAM_GROUP_TWEAKABLE) && if ((driver_param->getGroup() != VISUAL_PARAM_GROUP_TWEAKABLE) &&
(driver_param->getGroup() != VISUAL_PARAM_GROUP_TWEAKABLE_NO_TRANSMIT)) (driver_param->getGroup() != VISUAL_PARAM_GROUP_TWEAKABLE_NO_TRANSMIT))
{ {
mCharacter->setVisualParamWeight(driver_param, mCharacter->setVisualParamWeight(driver_param,
0, 0,
FALSE); FALSE);
} }
for (LLDriverParam::entry_list_t::iterator iter = driver_param->mDriven.begin(); for (LLDriverParam::entry_list_t::iterator iter = driver_param->mDriven.begin();
iter != driver_param->mDriven.end(); iter != driver_param->mDriven.end();
++iter) ++iter)
{ {
LLDrivenEntry &entry = (*iter); LLDrivenEntry &entry = (*iter);
LLViewerVisualParam *driven_param = entry.mParam; LLViewerVisualParam *driven_param = entry.mParam;
setParamValue(driven_param,position_new_local_clamped, behavior_maxeffect); 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. // 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 // So only update if the params have changed enough, and also take into account
// the graphics LOD settings. // 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;
// For non-self, if the avatar is small enough visually, then don't update. const F32 area_for_min_settings = 1400.0;
const F32 area_for_max_settings = 0.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 area_for_min_settings = 1400.0; const F32 pixel_area = fsqrtf(mCharacter->getPixelArea());
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); const BOOL is_self = (dynamic_cast<LLVOAvatarSelf *>(mCharacter) != NULL);
if ((pixel_area > area_for_this_setting) || is_self) if ((pixel_area > area_for_this_setting) || is_self)
{ {
const F32 position_diff_local = llabs(mPositionLastUpdate_local-position_new_local_clamped); const F32 position_diff_local = llabs(mPositionLastUpdate_local-position_new_local_clamped);
const F32 min_delta = (1.0001f-lod_factor)*0.4f; const F32 min_delta = (1.0001f-lod_factor)*0.4f;
if (llabs(position_diff_local) > min_delta) if (llabs(position_diff_local) > min_delta)
{ {
update_visuals = TRUE; update_visuals = TRUE;
mPositionLastUpdate_local = position_new_local; 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 mLastTime = time;
////////////////////////////////////////////////////////////////////////////////
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;
/* /*
// Write out debugging info into a spreadsheet. // Write out debugging info into a spreadsheet.
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment