Add positional smoothing for physical objects in network
This commit is contained in:
parent
1333fe2d19
commit
0cee131b9f
@ -180,14 +180,8 @@
|
||||
|
||||
<!-- Networking
|
||||
state-frequency: how many states the server will send per second.
|
||||
positional-smoothing: smoothing factor used in exponential smoothing
|
||||
depending on error.
|
||||
rotational-smoothing: slerp factor used in exponential smoothing
|
||||
of rotations depending on error.
|
||||
-->
|
||||
<networking state-frequency="10"
|
||||
positional-smoothing="0.25:0.95 1.0:0.85"
|
||||
rotational-smoothing="0.25:0.95 1.0:0.85" />
|
||||
<networking state-frequency="10"/>
|
||||
|
||||
<!-- The field od views for 1-4 player split screen. fov-3 is
|
||||
actually not used (since 3 player split screen uses the
|
||||
|
@ -117,15 +117,6 @@ void STKConfig::load(const std::string &filename)
|
||||
Log::fatal("StkConfig", "Wrong number of item switches defined in stk_config");
|
||||
}
|
||||
|
||||
if (m_positional_smoothing.size() == 0)
|
||||
{
|
||||
Log::fatal("StkConfig", "No positional smoothing defined in stk_config.");
|
||||
}
|
||||
if (m_rotational_smoothing.size() == 0)
|
||||
{
|
||||
Log::fatal("StkConfig", "No rotationalsmoothing defined in stk_config.");
|
||||
}
|
||||
|
||||
if (m_client_port == 0 || m_server_port == 0 || m_server_discovery_port == 0 ||
|
||||
m_client_port == m_server_port || m_client_port == m_server_discovery_port ||
|
||||
m_server_port == m_server_discovery_port)
|
||||
@ -400,8 +391,6 @@ void STKConfig::getAllData(const XMLNode * root)
|
||||
if (const XMLNode *networking_node = root->getNode("networking"))
|
||||
{
|
||||
networking_node->get("state-frequency", &m_network_state_frequeny);
|
||||
networking_node->get("positional-smoothing", &m_positional_smoothing );
|
||||
networking_node->get("rotational-smoothing", &m_rotational_smoothing );
|
||||
}
|
||||
|
||||
if(const XMLNode *replay_node = root->getNode("replay"))
|
||||
|
@ -89,13 +89,6 @@ public:
|
||||
/** How many state updates per second the server will send. */
|
||||
int m_network_state_frequeny;
|
||||
|
||||
/** Smoothing of prediction errors for position, defined as an
|
||||
* InterpolationArray. */
|
||||
InterpolationArray m_positional_smoothing;
|
||||
/** Smoothing of prediction errors for rotations, defined as an
|
||||
* InterpolationArray. */
|
||||
InterpolationArray m_rotational_smoothing;
|
||||
|
||||
/** If the angle between a normal on a vertex and the normal of the
|
||||
* triangle are more than this value, the physics will use the normal
|
||||
* of the triangle in smoothing normal. */
|
||||
|
@ -54,6 +54,8 @@ void KartRewinder::reset()
|
||||
{
|
||||
Kart::reset();
|
||||
Rewinder::reset();
|
||||
SmoothNetworkBody::setEnable(true);
|
||||
SmoothNetworkBody::setSmoothRotation(true);
|
||||
} // reset
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
|
@ -76,8 +76,6 @@ public:
|
||||
// -------------------------------------------------------------------------
|
||||
virtual void undoEvent(BareNetworkString *p) OVERRIDE {}
|
||||
// ------------------------------------------------------------------------
|
||||
virtual bool enableSmoothing() const OVERRIDE { return true; }
|
||||
// ------------------------------------------------------------------------
|
||||
virtual std::function<void()> getLocalStateRestoreFunction() OVERRIDE;
|
||||
|
||||
|
||||
|
@ -38,14 +38,6 @@ Moveable::Moveable()
|
||||
m_mesh = NULL;
|
||||
m_node = NULL;
|
||||
m_heading = 0;
|
||||
|
||||
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
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
@ -67,156 +59,21 @@ 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.
|
||||
*/
|
||||
void Moveable::checkSmoothing()
|
||||
{
|
||||
// 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_start_smoothing_postion.second.normalize();
|
||||
|
||||
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.normalize();
|
||||
} // checkSmoothing
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
void Moveable::updateSmoothedGraphics(float dt)
|
||||
{
|
||||
#ifndef SERVER_ONLY
|
||||
Vec3 cur_xyz = getXYZ();
|
||||
btQuaternion cur_rot = getRotation();
|
||||
|
||||
if (!enableSmoothing())
|
||||
{
|
||||
m_smoothed_transform.setOrigin(cur_xyz);
|
||||
m_smoothed_transform.setRotation(cur_rot);
|
||||
return;
|
||||
}
|
||||
|
||||
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;
|
||||
if (dot(cur_rot, m_adjust_position.second) < 0.0f)
|
||||
cur_rot = -cur_rot;
|
||||
cur_rot = 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.normalize();
|
||||
if (dot(cur_rot, m_adjust_position.second) < 0.0f)
|
||||
cur_rot = -cur_rot;
|
||||
cur_rot = 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);
|
||||
}
|
||||
|
||||
SmoothNetworkBody::updateSmoothedGraphics(m_transform, getVelocity(), dt);
|
||||
#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(),
|
||||
getSmoothedTrans().getOrigin().getX(),
|
||||
getSmoothedTrans().getOrigin().getY(),
|
||||
getSmoothedTrans().getOrigin().getZ(),
|
||||
getXYZ().getX(), getXYZ().getY(), getXYZ().getZ());
|
||||
#endif
|
||||
|
||||
#endif
|
||||
} // updateSmoothedGraphics
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
@ -230,9 +87,9 @@ void Moveable::updateGraphics(const Vec3& offset_xyz,
|
||||
const btQuaternion& rotation)
|
||||
{
|
||||
#ifndef SERVER_ONLY
|
||||
Vec3 xyz = m_smoothed_transform.getOrigin() + offset_xyz;
|
||||
Vec3 xyz = getSmoothedTrans().getOrigin() + offset_xyz;
|
||||
m_node->setPosition(xyz.toIrrVector());
|
||||
btQuaternion r_all = m_smoothed_transform.getRotation() * rotation;
|
||||
btQuaternion r_all = getSmoothedTrans().getRotation() * 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);
|
||||
@ -257,7 +114,8 @@ void Moveable::reset()
|
||||
m_node->setVisible(true); // In case that the objects was eliminated
|
||||
#endif
|
||||
|
||||
m_smoothed_transform = m_transform;
|
||||
SmoothNetworkBody::reset();
|
||||
SmoothNetworkBody::setSmoothedTransform(m_transform);
|
||||
Vec3 up = getTrans().getBasis().getColumn(1);
|
||||
m_pitch = atan2(up.getZ(), fabsf(up.getY()));
|
||||
m_roll = atan2(up.getX(), up.getY());
|
||||
|
@ -27,6 +27,7 @@ namespace irr
|
||||
using namespace irr;
|
||||
#include "btBulletDynamicsCommon.h"
|
||||
|
||||
#include "network/smooth_network_body.hpp"
|
||||
#include "physics/kart_motion_state.hpp"
|
||||
#include "physics/user_pointer.hpp"
|
||||
#include "utils/no_copy.hpp"
|
||||
@ -39,16 +40,10 @@ class Material;
|
||||
/**
|
||||
* \ingroup karts
|
||||
*/
|
||||
class Moveable: public NoCopy
|
||||
class Moveable: public NoCopy,
|
||||
public SmoothNetworkBody
|
||||
{
|
||||
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;
|
||||
@ -58,32 +53,18 @@ private:
|
||||
float m_pitch;
|
||||
/** The roll between -180 and 180 degrees. */
|
||||
float m_roll;
|
||||
|
||||
/** 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. */
|
||||
std::pair<Vec3, btQuaternion> m_start_smoothing_postion,
|
||||
m_adjust_position;
|
||||
|
||||
Vec3 m_adjust_control_point;
|
||||
|
||||
std::pair<btTransform, Vec3> m_prev_position_data;
|
||||
|
||||
btTransform m_smoothed_transform;
|
||||
|
||||
float m_adjust_time, m_adjust_time_dt;
|
||||
|
||||
SmoothingState m_smoothing;
|
||||
|
||||
protected:
|
||||
UserPointer m_user_pointer;
|
||||
scene::IMesh *m_mesh;
|
||||
scene::ISceneNode *m_node;
|
||||
btRigidBody *m_body;
|
||||
KartMotionState *m_motion_state;
|
||||
virtual void updateSmoothedGraphics(float dt);
|
||||
// ------------------------------------------------------------------------
|
||||
void updateSmoothedGraphics(float dt);
|
||||
// ------------------------------------------------------------------------
|
||||
virtual void updateGraphics(const Vec3& off_xyz = Vec3(0.0f, 0.0f, 0.0f),
|
||||
const btQuaternion& off_rotation = btQuaternion(0.0f, 0.0f, 0.0f, 1.0f));
|
||||
const btQuaternion& off_rotation =
|
||||
btQuaternion(0.0f, 0.0f, 0.0f, 1.0f));
|
||||
|
||||
public:
|
||||
Moveable();
|
||||
@ -153,19 +134,21 @@ public:
|
||||
*/
|
||||
virtual void updateGraphics(float dt) = 0;
|
||||
// ------------------------------------------------------------------------
|
||||
void prepareSmoothing();
|
||||
void prepareSmoothing()
|
||||
{
|
||||
SmoothNetworkBody::prepareSmoothing(m_transform, getVelocity());
|
||||
}
|
||||
// ------------------------------------------------------------------------
|
||||
void checkSmoothing();
|
||||
void checkSmoothing()
|
||||
{
|
||||
SmoothNetworkBody::checkSmoothing(m_transform, getVelocity());
|
||||
}
|
||||
// ------------------------------------------------------------------------
|
||||
const btTransform &getSmoothedTrans() const
|
||||
{ return m_smoothed_transform; }
|
||||
{ return SmoothNetworkBody::getSmoothedTrans(); }
|
||||
// ------------------------------------------------------------------------
|
||||
const Vec3& getSmoothedXYZ() const
|
||||
{ return (Vec3&)m_smoothed_transform.getOrigin(); }
|
||||
// ------------------------------------------------------------------------
|
||||
virtual bool enableSmoothing() const { return false; }
|
||||
// ------------------------------------------------------------------------
|
||||
virtual bool smoothRotation() const { return true; }
|
||||
{ return (Vec3&)SmoothNetworkBody::getSmoothedTrans().getOrigin(); }
|
||||
// ------------------------------------------------------------------------
|
||||
virtual const std::string& getIdent() const
|
||||
{
|
||||
|
170
src/network/smooth_network_body.cpp
Normal file
170
src/network/smooth_network_body.cpp
Normal file
@ -0,0 +1,170 @@
|
||||
//
|
||||
// SuperTuxKart - a fun racing game with go-kart
|
||||
// Copyright (C) 2018 SuperTuxKart-Team
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU General Public License
|
||||
// as published by the Free Software Foundation; either version 3
|
||||
// of the License, or (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program; if not, write to the Free Software
|
||||
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
|
||||
#include "network/smooth_network_body.hpp"
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
void SmoothNetworkBody::prepareSmoothing(const btTransform& current_transform,
|
||||
const Vec3& current_velocity)
|
||||
{
|
||||
#ifndef SERVER_ONLY
|
||||
// Continuous smooth enabled
|
||||
//if (m_smoothing != SS_NONE)
|
||||
// return;
|
||||
|
||||
m_prev_position_data = std::make_pair(current_transform,
|
||||
current_velocity);
|
||||
#endif
|
||||
} // 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.
|
||||
*/
|
||||
void SmoothNetworkBody::checkSmoothing(const btTransform& current_transform,
|
||||
const Vec3& current_velocity)
|
||||
{
|
||||
#ifndef SERVER_ONLY
|
||||
// Continuous smooth enabled
|
||||
//if (m_smoothing != SS_NONE)
|
||||
// return;
|
||||
|
||||
float adjust_length = (current_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, current_velocity.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_start_smoothing_postion.second.normalize();
|
||||
|
||||
m_adjust_control_point = m_start_smoothing_postion.first +
|
||||
m_prev_position_data.second * m_adjust_time;
|
||||
Vec3 p2 = current_transform.getOrigin() + current_velocity * m_adjust_time;
|
||||
|
||||
m_adjust_position.first.setInterpolate3(m_adjust_control_point, p2, 0.5f);
|
||||
m_adjust_position.second = current_transform.getRotation();
|
||||
m_adjust_position.second.normalize();
|
||||
#endif
|
||||
} // checkSmoothing
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
void SmoothNetworkBody::updateSmoothedGraphics(
|
||||
const btTransform& current_transform, const Vec3& current_velocity,
|
||||
float dt)
|
||||
{
|
||||
#ifndef SERVER_ONLY
|
||||
Vec3 cur_xyz = current_transform.getOrigin();
|
||||
btQuaternion cur_rot = current_transform.getRotation();
|
||||
|
||||
if (!m_enabled)
|
||||
{
|
||||
m_smoothed_transform.setOrigin(cur_xyz);
|
||||
m_smoothed_transform.setRotation(cur_rot);
|
||||
return;
|
||||
}
|
||||
|
||||
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 +
|
||||
current_velocity * 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 (m_smooth_rotation)
|
||||
{
|
||||
cur_rot = m_start_smoothing_postion.second;
|
||||
if (dot(cur_rot, m_adjust_position.second) < 0.0f)
|
||||
cur_rot = -cur_rot;
|
||||
cur_rot = 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 (m_smooth_rotation)
|
||||
{
|
||||
cur_rot.normalize();
|
||||
if (dot(cur_rot, m_adjust_position.second) < 0.0f)
|
||||
cur_rot = -cur_rot;
|
||||
cur_rot = 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 = current_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);
|
||||
}
|
||||
#endif
|
||||
} // updateSmoothedGraphics
|
103
src/network/smooth_network_body.hpp
Normal file
103
src/network/smooth_network_body.hpp
Normal file
@ -0,0 +1,103 @@
|
||||
//
|
||||
// SuperTuxKart - a fun racing game with go-kart
|
||||
// Copyright (C) 2018 SuperTuxKart-Team
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU General Public License
|
||||
// as published by the Free Software Foundation; either version 3
|
||||
// of the License, or (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program; if not, write to the Free Software
|
||||
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
|
||||
#ifndef HEADER_SMOOTH_NETWORK_BODY_HPP
|
||||
#define HEADER_SMOOTH_NETWORK_BODY_HPP
|
||||
|
||||
#include "utils/log.hpp"
|
||||
#include "utils/vec3.hpp"
|
||||
|
||||
#include "LinearMath/btTransform.h"
|
||||
|
||||
#include <utility>
|
||||
|
||||
class SmoothNetworkBody
|
||||
{
|
||||
private:
|
||||
enum SmoothingState
|
||||
{
|
||||
SS_NONE = 0,
|
||||
SS_TO_ADJUST,
|
||||
SS_TO_REAL
|
||||
};
|
||||
|
||||
/** Client prediction in networked games might cause the visual
|
||||
* and physical position to be different. For visual smoothing
|
||||
* these variable accumulate the error and reduces it over time. */
|
||||
std::pair<Vec3, btQuaternion> m_start_smoothing_postion,
|
||||
m_adjust_position;
|
||||
|
||||
Vec3 m_adjust_control_point;
|
||||
|
||||
std::pair<btTransform, Vec3> m_prev_position_data;
|
||||
|
||||
btTransform m_smoothed_transform;
|
||||
|
||||
float m_adjust_time, m_adjust_time_dt;
|
||||
|
||||
SmoothingState m_smoothing;
|
||||
|
||||
bool m_enabled;
|
||||
|
||||
bool m_smooth_rotation;
|
||||
|
||||
public:
|
||||
SmoothNetworkBody(bool enable = false)
|
||||
{
|
||||
reset();
|
||||
m_enabled = enable;
|
||||
m_smooth_rotation = true;
|
||||
}
|
||||
// ------------------------------------------------------------------------
|
||||
void reset()
|
||||
{
|
||||
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;
|
||||
}
|
||||
// ------------------------------------------------------------------------
|
||||
void setEnable(bool val) { m_enabled = val; }
|
||||
// ------------------------------------------------------------------------
|
||||
void setSmoothRotation(bool val) { m_smooth_rotation = val; }
|
||||
// ------------------------------------------------------------------------
|
||||
void prepareSmoothing(const btTransform& current_transform,
|
||||
const Vec3& current_velocity);
|
||||
// ------------------------------------------------------------------------
|
||||
void checkSmoothing(const btTransform& current_transform,
|
||||
const Vec3& current_velocity);
|
||||
// ------------------------------------------------------------------------
|
||||
void updateSmoothedGraphics(const btTransform& current_transform,
|
||||
const Vec3& current_velocity,
|
||||
float dt);
|
||||
// ------------------------------------------------------------------------
|
||||
void setSmoothedTransform(const btTransform& t)
|
||||
{ m_smoothed_transform = t; }
|
||||
// ------------------------------------------------------------------------
|
||||
const btTransform& getSmoothedTrans() const
|
||||
{ return m_smoothed_transform; }
|
||||
// ------------------------------------------------------------------------
|
||||
const Vec3& getSmoothedXYZ() const
|
||||
{ return (Vec3&)m_smoothed_transform.getOrigin(); }
|
||||
|
||||
};
|
||||
|
||||
#endif // HEADER_SMOOTH_NETWORK_BODY_HPP
|
@ -615,13 +615,16 @@ void PhysicalObject::updateGraphics(float dt)
|
||||
{
|
||||
if (!m_is_dynamic)
|
||||
return;
|
||||
Vec3 xyz = m_current_transform.getOrigin();
|
||||
|
||||
SmoothNetworkBody::updateSmoothedGraphics(m_body->getWorldTransform(),
|
||||
m_body->getLinearVelocity(), dt);
|
||||
Vec3 xyz = SmoothNetworkBody::getSmoothedTrans().getOrigin();
|
||||
|
||||
// Offset the graphical position correctly:
|
||||
xyz += m_current_transform.getBasis()*m_graphical_offset;
|
||||
xyz += SmoothNetworkBody::getSmoothedTrans().getBasis()*m_graphical_offset;
|
||||
|
||||
Vec3 hpr;
|
||||
hpr.setHPR(m_current_transform.getRotation());
|
||||
hpr.setHPR(SmoothNetworkBody::getSmoothedTrans().getRotation());
|
||||
|
||||
// This will only update the visual position, so it can be
|
||||
// called in updateGraphics()
|
||||
@ -683,6 +686,7 @@ bool PhysicalObject::castRay(const btVector3 &from, const btVector3 &to,
|
||||
// ----------------------------------------------------------------------------
|
||||
void PhysicalObject::reset()
|
||||
{
|
||||
Rewinder::reset();
|
||||
m_body->setCenterOfMassTransform(m_init_pos);
|
||||
m_body->setAngularVelocity(btVector3(0,0,0));
|
||||
m_body->setLinearVelocity(btVector3(0,0,0));
|
||||
@ -784,6 +788,8 @@ void PhysicalObject::hit(const Material *m, const Vec3 &normal)
|
||||
// ----------------------------------------------------------------------------
|
||||
void PhysicalObject::addForRewind()
|
||||
{
|
||||
SmoothNetworkBody::setEnable(true);
|
||||
SmoothNetworkBody::setSmoothRotation(false);
|
||||
Rewinder::setUniqueIdentity(std::string("P") + StringUtils::toString
|
||||
(Track::getCurrentTrack()->getPhysicalObjectUID()));
|
||||
Rewinder::add();
|
||||
@ -793,11 +799,15 @@ void PhysicalObject::addForRewind()
|
||||
void PhysicalObject::saveTransform()
|
||||
{
|
||||
m_no_server_state = true;
|
||||
SmoothNetworkBody::prepareSmoothing(m_body->getWorldTransform(),
|
||||
m_body->getLinearVelocity());
|
||||
} // saveTransform
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
void PhysicalObject::computeError()
|
||||
{
|
||||
SmoothNetworkBody::checkSmoothing(m_body->getWorldTransform(),
|
||||
m_body->getLinearVelocity());
|
||||
} // computeError
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
|
@ -24,6 +24,7 @@
|
||||
#include "btBulletDynamicsCommon.h"
|
||||
|
||||
#include "network/rewinder.hpp"
|
||||
#include "network/smooth_network_body.hpp"
|
||||
#include "physics/user_pointer.hpp"
|
||||
#include "utils/vec3.hpp"
|
||||
#include "utils/leak_check.hpp"
|
||||
@ -36,7 +37,8 @@ class XMLNode;
|
||||
/**
|
||||
* \ingroup physics
|
||||
*/
|
||||
class PhysicalObject : public Rewinder
|
||||
class PhysicalObject : public Rewinder,
|
||||
public SmoothNetworkBody
|
||||
{
|
||||
public:
|
||||
/** The supported collision shapes. */
|
||||
|
Loading…
Reference in New Issue
Block a user