Add curved smoothing for moveable in network
This commit is contained in:
parent
e8c4f74a20
commit
3b4353a2c9
@ -140,7 +140,7 @@ public:
|
||||
// ------------------------------------------------------------------------
|
||||
/** Returns a unique identifier for this kart (name of the directory the
|
||||
* kart was loaded from). */
|
||||
const std::string& getIdent() const;
|
||||
virtual const std::string& getIdent() const;
|
||||
// ------------------------------------------------------------------------
|
||||
/** Returns the maximum steering angle for this kart, which depends on the
|
||||
* speed. */
|
||||
|
@ -59,16 +59,13 @@ void KartRewinder::reset()
|
||||
*/
|
||||
void KartRewinder::saveTransform()
|
||||
{
|
||||
m_saved_transform = getTrans();
|
||||
Moveable::prepareSmoothing();
|
||||
} // saveTransform
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
void KartRewinder::computeError()
|
||||
{
|
||||
//btTransform error = getTrans() - m_saved_transform;
|
||||
Vec3 pos_error = getTrans().getOrigin() - m_saved_transform.getOrigin();
|
||||
btQuaternion rot_error(0, 0, 0, 1);
|
||||
Kart::addError(pos_error, rot_error);
|
||||
Moveable::checkSmoothing();
|
||||
} // computeError
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
|
@ -34,8 +34,6 @@ private:
|
||||
enum { EVENT_CONTROL = 0x01,
|
||||
EVENT_ATTACH = 0x02 };
|
||||
|
||||
/** The transform of the kart before a rewind starts. */
|
||||
btTransform m_saved_transform;
|
||||
public:
|
||||
KartRewinder(const std::string& ident,
|
||||
unsigned int world_kart_id,
|
||||
|
@ -38,8 +38,14 @@ Moveable::Moveable()
|
||||
m_mesh = NULL;
|
||||
m_node = NULL;
|
||||
m_heading = 0;
|
||||
m_positional_error = Vec3(0.0f, 0.0f, 0.0f);
|
||||
m_rotational_error = btQuaternion(0.0f, 0.0f, 0.0f, 1.0f);
|
||||
|
||||
m_smoothed_transform = btTransform(btQuaternion(0.0f, 0.0f, 0.0f, 1.0f));
|
||||
m_start_smoothing_postion = m_adjust_position =
|
||||
std::make_pair(Vec3(0.0f, 0.0f, 0.0f),
|
||||
btQuaternion(0.0f, 0.0f, 0.0f, 1.0f));
|
||||
m_prev_position_data = std::make_pair(m_smoothed_transform, Vec3());
|
||||
m_smoothing = SS_NONE;
|
||||
m_adjust_time = m_adjust_time_dt = 0.0f;
|
||||
} // Moveable
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
@ -61,25 +67,61 @@ void Moveable::setNode(scene::ISceneNode *n)
|
||||
m_node = n;
|
||||
} // setNode
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
void Moveable::prepareSmoothing()
|
||||
{
|
||||
// Continuous smooth enabled
|
||||
//if (m_smoothing != SS_NONE)
|
||||
// return;
|
||||
|
||||
m_prev_position_data = std::make_pair(m_transform, getVelocity());
|
||||
} // prepareSmoothing
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
/** Adds a new error between graphical and physical position/rotation. Called
|
||||
* in case of a rewind to allow to for smoothing the visuals in case of
|
||||
* incorrect client prediction.
|
||||
* \param pos_error Positional error to add.
|
||||
* \param rot_Error Rotational error to add.
|
||||
*/
|
||||
void Moveable::addError(const Vec3& pos_error,
|
||||
const btQuaternion &rot_error)
|
||||
void Moveable::checkSmoothing()
|
||||
{
|
||||
m_positional_error += pos_error;
|
||||
#ifdef DEBUG_VISUAL_ERROR
|
||||
Log::info("VisualError", "time %f addError %f %f %f size %f",
|
||||
World::getWorld()->getTime(),
|
||||
m_positional_error.getX(), m_positional_error.getY(), m_positional_error.getZ(),
|
||||
m_positional_error.length());
|
||||
#endif
|
||||
m_rotational_error *= rot_error;
|
||||
} // addError
|
||||
// Continuous smooth enabled
|
||||
//if (m_smoothing != SS_NONE)
|
||||
// return;
|
||||
|
||||
float adjust_length = (m_transform.getOrigin() -
|
||||
m_prev_position_data.first.getOrigin()).length();
|
||||
if (adjust_length < 0.1f || adjust_length > 4.0f)
|
||||
return;
|
||||
|
||||
float speed = m_prev_position_data.second.length();
|
||||
speed = std::max(speed, getVelocity().length());
|
||||
if (speed < 0.3f)
|
||||
return;
|
||||
|
||||
float adjust_time = (adjust_length * 2.0f) / speed;
|
||||
if (adjust_time > 2.0f)
|
||||
return;
|
||||
|
||||
m_smoothing = SS_TO_ADJUST;
|
||||
m_adjust_time_dt = 0.0f;
|
||||
m_adjust_time = adjust_time;
|
||||
|
||||
m_start_smoothing_postion.first = m_smoothing == SS_NONE ?
|
||||
m_prev_position_data.first.getOrigin() :
|
||||
m_smoothed_transform.getOrigin();
|
||||
m_start_smoothing_postion.second = m_smoothing == SS_NONE ?
|
||||
m_prev_position_data.first.getRotation() :
|
||||
m_smoothed_transform.getRotation();
|
||||
|
||||
m_adjust_control_point = m_start_smoothing_postion.first +
|
||||
m_prev_position_data.second * m_adjust_time;
|
||||
Vec3 p2 = m_transform.getOrigin() + getVelocity() *
|
||||
m_adjust_time;
|
||||
|
||||
m_adjust_position.first.setInterpolate3(m_adjust_control_point, p2, 0.5f);
|
||||
m_adjust_position.second = m_transform.getRotation();
|
||||
m_adjust_position.second.slerp(m_start_smoothing_postion.second, 0.5f);
|
||||
} // checkSmoothing
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
/** Updates the graphics model. Mainly set the graphical position to be the
|
||||
@ -91,24 +133,84 @@ void Moveable::addError(const Vec3& pos_error,
|
||||
void Moveable::updateGraphics(float dt, const Vec3& offset_xyz,
|
||||
const btQuaternion& rotation)
|
||||
{
|
||||
// If this is a client, don't smooth error during rewinds
|
||||
if (World::getWorld()->isNetworkWorld() &&
|
||||
NetworkConfig::get()->isClient() &&
|
||||
!RewindManager::get()->isRewinding())
|
||||
{
|
||||
float error = m_positional_error.length();
|
||||
m_positional_error *= stk_config->m_positional_smoothing.get(error);
|
||||
#ifdef DEBUG_VISUAL_ERROR
|
||||
Log::info("VisualError", "time %f reduceError %f %f %f size %f",
|
||||
World::getWorld()->getTime(),
|
||||
m_positional_error.getX(), m_positional_error.getY(), m_positional_error.getZ(),
|
||||
m_positional_error.length());
|
||||
#endif
|
||||
}
|
||||
#ifndef SERVER_ONLY
|
||||
Vec3 xyz=getXYZ()+offset_xyz - m_positional_error;
|
||||
Vec3 cur_xyz = getXYZ();
|
||||
btQuaternion cur_rot = getRotation();
|
||||
|
||||
float ratio = 0.0f;
|
||||
if (m_smoothing != SS_NONE)
|
||||
{
|
||||
float adjust_time_dt = m_adjust_time_dt + dt;
|
||||
ratio = adjust_time_dt / m_adjust_time;
|
||||
if (ratio > 1.0f)
|
||||
{
|
||||
ratio -= 1.0f;
|
||||
m_adjust_time_dt = adjust_time_dt - m_adjust_time;
|
||||
if (m_smoothing == SS_TO_ADJUST)
|
||||
{
|
||||
m_smoothing = SS_TO_REAL;
|
||||
m_adjust_control_point = m_adjust_position.first +
|
||||
getVelocity() * m_adjust_time;
|
||||
}
|
||||
else
|
||||
m_smoothing = SS_NONE;
|
||||
}
|
||||
else
|
||||
m_adjust_time_dt = adjust_time_dt;
|
||||
}
|
||||
|
||||
assert(m_adjust_time_dt >= 0.0f);
|
||||
assert(ratio >= 0.0f);
|
||||
if (m_smoothing == SS_TO_ADJUST)
|
||||
{
|
||||
cur_xyz.setInterpolate3(m_start_smoothing_postion.first,
|
||||
m_adjust_position.first, ratio);
|
||||
Vec3 to_control;
|
||||
to_control.setInterpolate3(m_start_smoothing_postion.first,
|
||||
m_adjust_control_point, ratio);
|
||||
cur_xyz.setInterpolate3(cur_xyz, to_control, 1.0f - ratio);
|
||||
if (smoothRotation())
|
||||
{
|
||||
cur_rot = m_start_smoothing_postion.second;
|
||||
cur_rot.slerp(m_adjust_position.second, ratio);
|
||||
}
|
||||
}
|
||||
else if (m_smoothing == SS_TO_REAL)
|
||||
{
|
||||
Vec3 to_control;
|
||||
to_control.setInterpolate3(m_adjust_position.first,
|
||||
m_adjust_control_point, ratio);
|
||||
float ratio_sqrt = sqrtf(ratio);
|
||||
cur_xyz.setInterpolate3(m_adjust_position.first, cur_xyz, ratio_sqrt);
|
||||
cur_xyz.setInterpolate3(to_control, cur_xyz, ratio);
|
||||
if (smoothRotation())
|
||||
cur_rot.slerp(m_adjust_position.second, 1.0f - ratio);
|
||||
}
|
||||
|
||||
m_smoothed_transform.setOrigin(cur_xyz);
|
||||
m_smoothed_transform.setRotation(cur_rot);
|
||||
|
||||
if (m_smoothing != SS_NONE)
|
||||
{
|
||||
Vec3 lc = m_transform.inverse()(cur_xyz);
|
||||
// Adjust vertical position for up/down-sloping
|
||||
cur_xyz = m_smoothed_transform(Vec3(0.0f, -lc.y(), 0.0f));
|
||||
m_smoothed_transform.setOrigin(cur_xyz);
|
||||
}
|
||||
|
||||
#undef DEBUG_SMOOTHING
|
||||
#ifdef DEBUG_SMOOTHING
|
||||
// Gnuplot compare command
|
||||
// plot "stdout.log" u 6:8 w lp lw 2, "stdout.log" u 10:12 w lp lw 2
|
||||
Log::verbose("Smoothing", "%s smoothed-xyz(6-8) %f %f %f "
|
||||
"xyz(10-12) %f %f %f", getIdent().c_str(),
|
||||
cur_xyz.getX(), cur_xyz.getY(), cur_xyz.getZ(),
|
||||
getXYZ().getX(), getXYZ().getY(), getXYZ().getZ());
|
||||
#endif
|
||||
|
||||
Vec3 xyz = cur_xyz + offset_xyz;
|
||||
m_node->setPosition(xyz.toIrrVector());
|
||||
btQuaternion r_all = getRotation()*rotation;
|
||||
btQuaternion r_all = cur_rot * rotation;
|
||||
if(btFuzzyZero(r_all.getX()) && btFuzzyZero(r_all.getY()-0.70710677f) &&
|
||||
btFuzzyZero(r_all.getZ()) && btFuzzyZero(r_all.getW()-0.70710677f) )
|
||||
r_all.setX(0.000001f);
|
||||
@ -133,6 +235,7 @@ void Moveable::reset()
|
||||
m_node->setVisible(true); // In case that the objects was eliminated
|
||||
#endif
|
||||
|
||||
m_smoothed_transform = m_transform;
|
||||
Vec3 up = getTrans().getBasis().getColumn(1);
|
||||
m_pitch = atan2(up.getZ(), fabsf(up.getY()));
|
||||
m_roll = atan2(up.getX(), up.getY());
|
||||
|
@ -32,6 +32,8 @@ using namespace irr;
|
||||
#include "utils/no_copy.hpp"
|
||||
#include "utils/vec3.hpp"
|
||||
|
||||
#include <string>
|
||||
|
||||
class Material;
|
||||
|
||||
/**
|
||||
@ -40,6 +42,13 @@ class Material;
|
||||
class Moveable: public NoCopy
|
||||
{
|
||||
private:
|
||||
enum SmoothingState
|
||||
{
|
||||
SS_NONE = 0,
|
||||
SS_TO_ADJUST,
|
||||
SS_TO_REAL
|
||||
};
|
||||
|
||||
Vec3 m_velocityLC; /**<Velocity in kart coordinates. */
|
||||
/** The bullet transform of this rigid body. */
|
||||
btTransform m_transform;
|
||||
@ -53,10 +62,18 @@ private:
|
||||
/** Client prediction in networked games might cause the visual
|
||||
* and physical position to be different. For visual smoothing
|
||||
* this variable accumulates the error and reduces it over time. */
|
||||
Vec3 m_positional_error;
|
||||
std::pair<Vec3, btQuaternion> m_start_smoothing_postion,
|
||||
m_adjust_position;
|
||||
|
||||
/** Similar to m_positional_error for rotation. */
|
||||
btQuaternion m_rotational_error;
|
||||
Vec3 m_adjust_control_point;
|
||||
|
||||
std::pair<btTransform, Vec3> m_prev_position_data;
|
||||
|
||||
float m_adjust_time, m_adjust_time_dt;
|
||||
|
||||
SmoothingState m_smoothing;
|
||||
|
||||
btTransform m_smoothed_transform;
|
||||
|
||||
protected:
|
||||
UserPointer m_user_pointer;
|
||||
@ -129,14 +146,31 @@ public:
|
||||
&getTrans() const {return m_transform;}
|
||||
void setTrans(const btTransform& t);
|
||||
void updatePosition();
|
||||
void addError(const Vec3& pos_error,
|
||||
const btQuaternion &rot_error);
|
||||
// ------------------------------------------------------------------------
|
||||
/** Called once per rendered frame. It is used to only update any graphical
|
||||
* effects.
|
||||
* \param dt Time step size (since last call).
|
||||
*/
|
||||
virtual void updateGraphics(float dt) = 0;
|
||||
// ------------------------------------------------------------------------
|
||||
void prepareSmoothing();
|
||||
// ------------------------------------------------------------------------
|
||||
void checkSmoothing();
|
||||
// ------------------------------------------------------------------------
|
||||
const btTransform &getSmoothedTrans() const
|
||||
{ return m_smoothed_transform; }
|
||||
// ------------------------------------------------------------------------
|
||||
const Vec3& getSmoothedXYZ() const
|
||||
{ return (Vec3&)m_smoothed_transform.getOrigin(); }
|
||||
// ------------------------------------------------------------------------
|
||||
virtual bool smoothRotation() const { return true; }
|
||||
// ------------------------------------------------------------------------
|
||||
virtual const std::string& getIdent() const
|
||||
{
|
||||
static std::string unused("unused");
|
||||
return unused;
|
||||
}
|
||||
|
||||
}; // class Moveable
|
||||
|
||||
#endif
|
||||
|
@ -210,7 +210,6 @@ void RewindQueue::mergeNetworkData(int world_ticks, bool *needs_rewind,
|
||||
// Only a client ever rewinds. So the rewind time should be the latest
|
||||
// received state before current world time (if any)
|
||||
*rewind_ticks = -9999;
|
||||
bool adjust_next = false;
|
||||
|
||||
// FIXME: making m_network_events sorted would prevent the need to
|
||||
// go through the whole list of events
|
||||
@ -261,7 +260,8 @@ void RewindQueue::mergeNetworkData(int world_ticks, bool *needs_rewind,
|
||||
// any server message should be in the client's past - but it can
|
||||
// happen during debugging) we need to rewind to getTicks (in order
|
||||
// to get the latest state).
|
||||
if (NetworkConfig::get()->isClient() && (*i)->getTicks() <= world_ticks)
|
||||
if (NetworkConfig::get()->isClient() &&
|
||||
(*i)->getTicks() <= world_ticks && (*i)->isState())
|
||||
{
|
||||
// We need rewind if we receive an event in the past. This will
|
||||
// then trigger a rewind later. Note that we only rewind to the
|
||||
|
Loading…
Reference in New Issue
Block a user