Add positional smoothing for physical objects in network

This commit is contained in:
Benau 2018-07-13 20:27:37 +08:00
parent 1333fe2d19
commit 0cee131b9f
12 changed files with 320 additions and 218 deletions

View File

@ -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

View File

@ -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"))

View File

@ -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. */

View File

@ -54,6 +54,8 @@ void KartRewinder::reset()
{
Kart::reset();
Rewinder::reset();
SmoothNetworkBody::setEnable(true);
SmoothNetworkBody::setSmoothRotation(true);
} // reset
// ----------------------------------------------------------------------------

View File

@ -76,8 +76,6 @@ public:
// -------------------------------------------------------------------------
virtual void undoEvent(BareNetworkString *p) OVERRIDE {}
// ------------------------------------------------------------------------
virtual bool enableSmoothing() const OVERRIDE { return true; }
// ------------------------------------------------------------------------
virtual std::function<void()> getLocalStateRestoreFunction() OVERRIDE;

View File

@ -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());

View File

@ -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
{

View 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

View 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

View File

@ -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
// ----------------------------------------------------------------------------

View File

@ -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. */