SH-1381 FIXED avatar physics behavior is tightly tied to viewer framerate
Breaking up physics into smaller integration steps.meow-7.2.2
parent
ca3ddbcf97
commit
8bc118c934
|
|
@ -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.
|
||||
//
|
||||
|
||||
const F32 velocity_joint_local = calculateVelocity_local(time_delta);
|
||||
const F32 acceleration_joint_local = calculateAcceleration_local(velocity_joint_local, time_delta);
|
||||
|
||||
//
|
||||
// End velocity and acceleration
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// 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;
|
||||
|
||||
// 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);
|
||||
|
||||
// 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);
|
||||
|
||||
const F32 force_net = (force_accel +
|
||||
force_gravity +
|
||||
force_spring +
|
||||
force_damping +
|
||||
force_drag);
|
||||
|
||||
//
|
||||
// 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);
|
||||
|
||||
// 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;
|
||||
}
|
||||
|
||||
// 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))
|
||||
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)
|
||||
{
|
||||
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);
|
||||
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_iteration_step);
|
||||
const F32 acceleration_joint_local = calculateAcceleration_local(velocity_joint_local, time_iteration_step);
|
||||
|
||||
//
|
||||
// End velocity and acceleration
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// 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;
|
||||
|
||||
// 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);
|
||||
|
||||
// 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);
|
||||
|
||||
const F32 force_net = (force_accel +
|
||||
force_gravity +
|
||||
force_spring +
|
||||
force_damping +
|
||||
force_drag);
|
||||
|
||||
//
|
||||
// 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);
|
||||
|
||||
// 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);
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// End calculate new 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.
|
||||
|
||||
// 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;
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// 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();
|
||||
|
||||
}
|
||||
|
||||
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
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// 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.
|
||||
|
||||
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());
|
||||
|
||||
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();
|
||||
mLastTime = time;
|
||||
mLastTime = time;
|
||||
|
||||
/*
|
||||
// Write out debugging info into a spreadsheet.
|
||||
|
|
|
|||
Loading…
Reference in New Issue