Simplified camera code somewhat, added support for final-camera, and made reverse
faster. git-svn-id: svn+ssh://svn.code.sf.net/p/supertuxkart/code/main/trunk@4306 178a84e3-b1eb-0310-8ba1-8eac791a3b58
This commit is contained in:
parent
f6b4197b7d
commit
de0e948c9a
@ -38,8 +38,6 @@ Camera::Camera(int camera_index, const Kart* kart)
|
||||
setupCamera();
|
||||
m_distance = kart->getKartProperties()->getCameraDistance() * 0.5f;
|
||||
m_kart = kart;
|
||||
m_angle_up = 0.0f;
|
||||
m_angle_around = 0.0f;
|
||||
m_ambient_light = RaceManager::getTrack()->getDefaultAmbientColor();
|
||||
|
||||
// TODO: Put these values into a config file
|
||||
@ -136,12 +134,49 @@ void Camera::setupCamera()
|
||||
} // setupCamera
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
/** Sets the mode of the camera.
|
||||
* \param mode Mode the camera should be switched to.
|
||||
*/
|
||||
void Camera::setMode(Mode mode)
|
||||
{
|
||||
m_mode = mode;
|
||||
// If we switch from reverse view, move the camera immediately to the
|
||||
// correct position.
|
||||
if(m_mode==CM_REVERSE && mode==CM_NORMAL)
|
||||
{
|
||||
Vec3 wanted_position, wanted_target;
|
||||
computeNormalCameraPosition(&wanted_position, &wanted_target);
|
||||
m_camera->setPosition(wanted_position.toIrrVector());
|
||||
m_camera->setTarget(wanted_target.toIrrVector());
|
||||
}
|
||||
if(mode==CM_FINAL)
|
||||
{
|
||||
const Track* track = RaceManager::getTrack();
|
||||
core::vector3df wanted_position(track->getCameraPosition().toIrrVector());
|
||||
core::vector3df curr_position(m_camera->getPosition());
|
||||
m_lin_velocity = (wanted_position-curr_position)
|
||||
/ stk_config->m_final_camera_time;
|
||||
float distance = (m_kart->getXYZ() - curr_position).length();
|
||||
core::vector3df hpr = track->getCameraHPR().toIrrHPR();
|
||||
core::vector3df target = hpr.rotationToDirection(core::vector3df(0, 0, 1)*distance)
|
||||
+ wanted_position;
|
||||
core::vector3df curr_hpr = m_camera->getRotation();
|
||||
m_target_velocity = (target - m_camera->getTarget())
|
||||
/ stk_config->m_final_camera_time;
|
||||
m_final_time = 0.0f;
|
||||
}
|
||||
|
||||
// If the camera is set to final mode but there is no camera
|
||||
// end position defined, ignore this request and leave the camera
|
||||
// in normal mode.
|
||||
if(mode!=CM_FINAL || RaceManager::getTrack()->hasFinalCamera())
|
||||
{
|
||||
m_mode = mode;
|
||||
}
|
||||
} // setMode
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
/** Returns the current mode of the camera.
|
||||
*/
|
||||
Camera::Mode Camera::getMode()
|
||||
{
|
||||
return m_mode;
|
||||
@ -154,9 +189,6 @@ Camera::Mode Camera::getMode()
|
||||
void Camera::reset()
|
||||
{
|
||||
setMode(CM_NORMAL);
|
||||
// m_position, m_target etc. are set when the worlds has computed the right starting
|
||||
// position of all karts and calls setInitialTransform for each camera.
|
||||
|
||||
} // reset
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
@ -165,107 +197,30 @@ void Camera::reset()
|
||||
*/
|
||||
void Camera::setInitialTransform()
|
||||
{
|
||||
m_target = m_kart->getXYZ();
|
||||
m_position = m_target - Vec3(0,50,-25);
|
||||
m_temp_position = m_position;
|
||||
m_temp_target = m_target;
|
||||
} // updateKartPosition
|
||||
m_camera->setPosition( m_kart->getXYZ().toIrrVector() - core::vector3df(0, -25, 50) );
|
||||
} // setInitialTransform
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
void Camera::update(float dt)
|
||||
/** Moves the camera smoothly from the current camera position (and target)
|
||||
* to the new position and target.
|
||||
* \param wanted_position The position the camera wanted to reach.
|
||||
* \param wanted_target The point the camera wants to point to.
|
||||
*/
|
||||
void Camera::smoothMoveCamera(float dt, const Vec3 &wanted_position,
|
||||
const Vec3 &wanted_target)
|
||||
{
|
||||
const Track* track=RaceManager::getTrack();
|
||||
float steering;
|
||||
float dampened_steer;
|
||||
|
||||
// Each case should set m_target and m_position according to what is needed for that mode.
|
||||
// Yes, there is a lot of duplicate code but it is (IMHO) much easier to follow this way.
|
||||
switch(m_mode)
|
||||
{
|
||||
case CM_NORMAL:
|
||||
// This first line moves the camera around behind the kart, pointing it
|
||||
// towards where the kart is turning (and turning even more while skidding).
|
||||
steering = m_kart->getSteerPercent() * (1.0f + (m_kart->getSkidding() - 1.0f)/2.3f ); // dampen skidding effect
|
||||
dampened_steer = fabsf(steering) * steering; // quadratically to dampen small variations (but keep sign)
|
||||
m_angle_around = m_kart->getHPR().getX() + m_rotation_range * dampened_steer * 0.5f;
|
||||
m_angle_up = m_kart->getHPR().getY() - 30.0f*DEGREE_TO_RAD;
|
||||
|
||||
m_target = m_kart->getXYZ();
|
||||
m_target.setZ(m_target.getZ()+0.75f);
|
||||
|
||||
m_position.setX( sin(m_angle_around));
|
||||
m_position.setY(-cos(m_angle_around));
|
||||
m_position.setZ(-sin(m_angle_up));
|
||||
m_position *= m_distance;
|
||||
m_position += m_target;
|
||||
|
||||
break;
|
||||
case CM_REVERSE: // Same as CM_NORMAL except it looks backwards
|
||||
m_angle_around = m_kart->getHPR().getX() - m_rotation_range * m_kart->getSteerPercent() * m_kart->getSkidding();
|
||||
m_angle_up = m_kart->getHPR().getY() + 30.0f*DEGREE_TO_RAD;
|
||||
|
||||
m_target = m_kart->getXYZ();
|
||||
m_target.setZ(m_target.getZ()+0.75f);
|
||||
|
||||
m_position.setX(-sin(m_angle_around));
|
||||
m_position.setY( cos(m_angle_around));
|
||||
m_position.setZ( sin(m_angle_up));
|
||||
m_position *= m_distance * 2.0f;
|
||||
m_position += m_target;
|
||||
|
||||
break;
|
||||
case CM_CLOSEUP: // Lower to the ground and closer to the kart
|
||||
m_angle_around = m_kart->getHPR().getX() + m_rotation_range * m_kart->getSteerPercent() * m_kart->getSkidding();
|
||||
m_angle_up = m_kart->getHPR().getY() - 20.0f*DEGREE_TO_RAD;
|
||||
|
||||
m_target = m_kart->getXYZ();
|
||||
m_target.setZ(m_target.getZ()+0.75f);
|
||||
|
||||
m_position.setX( sin(m_angle_around));
|
||||
m_position.setY(-cos(m_angle_around));
|
||||
m_position.setZ(-sin(m_angle_up));
|
||||
m_position *= m_distance * 0.5f;
|
||||
m_position += m_target;
|
||||
|
||||
break;
|
||||
case CM_LEADER_MODE: // Follows the leader kart, higher off of the ground, further from the kart,
|
||||
// and turns in the opposite direction from the kart for a nice effect. :)
|
||||
m_angle_around = RaceManager::getKart(0)->getHPR().getX();
|
||||
m_angle_up = RaceManager::getKart(0)->getHPR().getY() + 40.0f*DEGREE_TO_RAD;
|
||||
|
||||
m_target = RaceManager::getKart(0)->getXYZ();
|
||||
|
||||
m_position.setX(sin(m_angle_around));
|
||||
m_position.setY(cos(m_angle_around));
|
||||
m_position.setZ(sin(m_angle_up));
|
||||
m_position *= m_distance * 2.0f;
|
||||
m_position += m_target;
|
||||
|
||||
break;
|
||||
case CM_FINAL:
|
||||
if(!track->hasFinalCamera())
|
||||
{
|
||||
m_mode = CM_NORMAL;
|
||||
break;
|
||||
}
|
||||
m_position = track->getCameraPosition();
|
||||
m_target.setX(-sin( track->getCameraHPR().getX() ) );
|
||||
m_target.setY( cos( track->getCameraHPR().getX() ) );
|
||||
m_target.setZ( sin( track->getCameraHPR().getY() ) );
|
||||
m_target *= 10.0f;
|
||||
m_target += m_position;
|
||||
break;
|
||||
case CM_SIMPLE_REPLAY:
|
||||
// TODO: Implement
|
||||
break;
|
||||
}
|
||||
|
||||
// Smoothly interpolate towards the position and target
|
||||
m_temp_target += ((m_target - m_temp_target) * m_target_speed) * dt;
|
||||
m_temp_position += ((m_position - m_temp_position) * m_position_speed) * dt;
|
||||
core::vector3df current_position = m_camera->getPosition();
|
||||
core::vector3df current_target = m_camera->getTarget();
|
||||
current_target += ((wanted_target.toIrrVector() - current_target ) * m_target_speed ) * dt;
|
||||
current_position += ((wanted_position.toIrrVector() - current_position) * m_position_speed) * dt;
|
||||
m_camera->setPosition(current_position);
|
||||
m_camera->setTarget(current_target);
|
||||
|
||||
if(race_manager->getNumLocalPlayers() < 2)
|
||||
sound_manager->positionListener(current_position,
|
||||
current_target - current_position);
|
||||
|
||||
m_camera->setPosition(m_temp_position.toIrrVector());
|
||||
m_camera->setTarget(m_temp_target.toIrrVector());
|
||||
// The following settings give a debug camera which shows the track from
|
||||
// high above the kart straight down.
|
||||
#undef DEBUG_CAMERA
|
||||
@ -275,9 +230,120 @@ void Camera::update(float dt)
|
||||
xyz.Y = xyz.Y+30;
|
||||
m_camera->setPosition(xyz);
|
||||
#endif
|
||||
} // smoothMoveCamera
|
||||
|
||||
if(race_manager->getNumLocalPlayers() < 2)
|
||||
sound_manager->positionListener(m_temp_position, m_temp_target - m_temp_position);
|
||||
//-----------------------------------------------------------------------------
|
||||
/** Computes the wanted camera position and target for normal camera mode.
|
||||
* Besides being used in update(dt), it is also used when switching the
|
||||
* camera from reverse mode to normal mode - in which case we don't want
|
||||
* to have a smooth camera.
|
||||
* \param wanted_position The position the camera should be.
|
||||
* \param wanted_target The target position the camera should target.
|
||||
*/
|
||||
void Camera::computeNormalCameraPosition(Vec3 *wanted_position,
|
||||
Vec3 *wanted_target)
|
||||
{
|
||||
*wanted_target = m_kart->getXYZ();
|
||||
wanted_target->setZ(wanted_target->getZ()+ 0.75f);
|
||||
// This first line moves the camera around behind the kart, pointing it
|
||||
// towards where the kart is turning (and turning even more while skidding).
|
||||
float steering = m_kart->getSteerPercent() * (1.0f + (m_kart->getSkidding() - 1.0f)/2.3f ); // dampen skidding effect
|
||||
float dampened_steer = fabsf(steering) * steering; // quadratically to dampen small variations (but keep sign)
|
||||
float angle_around = m_kart->getHPR().getX() + m_rotation_range * dampened_steer * 0.5f;
|
||||
float angle_up = m_kart->getHPR().getY() - 30.0f*DEGREE_TO_RAD;
|
||||
wanted_position->setX( sin(angle_around));
|
||||
wanted_position->setY(-cos(angle_around));
|
||||
wanted_position->setZ(-sin(angle_up) );
|
||||
*wanted_position *= m_distance;
|
||||
*wanted_position += *wanted_target;
|
||||
} // computeNormalCameraPosition
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
/** Called once per time frame to move the camera to the right position.
|
||||
* \param dt Time step.
|
||||
*/
|
||||
void Camera::update(float dt)
|
||||
{
|
||||
printf("cam: %f %f %f\n",
|
||||
m_camera->getRotation().X,
|
||||
m_camera->getRotation().Y,
|
||||
m_camera->getRotation().Z);
|
||||
|
||||
Vec3 wanted_position;
|
||||
Vec3 wanted_target = m_kart->getXYZ();
|
||||
|
||||
// Each case should set wanted_position and wanted_target according to
|
||||
// what is needed for that mode. Yes, there is a lot of duplicate code
|
||||
// but it is (IMHO) much easier to follow this way.
|
||||
switch(m_mode)
|
||||
{
|
||||
case CM_NORMAL:
|
||||
{
|
||||
computeNormalCameraPosition(&wanted_position, &wanted_target);
|
||||
smoothMoveCamera(dt, wanted_position, wanted_target);
|
||||
break;
|
||||
}
|
||||
case CM_REVERSE: // Same as CM_NORMAL except it looks backwards
|
||||
{
|
||||
wanted_target.setZ(wanted_target.getZ()+ 0.75f);
|
||||
float angle_around = m_kart->getHPR().getX() - m_rotation_range * m_kart->getSteerPercent() * m_kart->getSkidding();
|
||||
float angle_up = m_kart->getHPR().getY() + 30.0f*DEGREE_TO_RAD;
|
||||
wanted_position.setX(-sin(angle_around));
|
||||
wanted_position.setY( cos(angle_around));
|
||||
wanted_position.setZ( sin(angle_up) );
|
||||
wanted_position *= m_distance * 2.0f;
|
||||
wanted_position += wanted_target;
|
||||
smoothMoveCamera(dt, wanted_position, wanted_target);
|
||||
m_camera->setPosition(wanted_position.toIrrVector());
|
||||
m_camera->setTarget(wanted_target.toIrrVector());
|
||||
break;
|
||||
}
|
||||
case CM_CLOSEUP: // Lower to the ground and closer to the kart
|
||||
{
|
||||
wanted_target.setZ(wanted_target.getZ()+0.75f);
|
||||
float angle_around = m_kart->getHPR().getX() + m_rotation_range * m_kart->getSteerPercent() * m_kart->getSkidding();
|
||||
float angle_up = m_kart->getHPR().getY() - 20.0f*DEGREE_TO_RAD;
|
||||
wanted_position.setX( sin(angle_around));
|
||||
wanted_position.setY(-cos(angle_around));
|
||||
wanted_position.setZ(-sin(angle_up) );
|
||||
wanted_position *= m_distance * 0.5f;
|
||||
wanted_position += wanted_target;
|
||||
smoothMoveCamera(dt, wanted_position, wanted_target);
|
||||
break;
|
||||
}
|
||||
case CM_LEADER_MODE:
|
||||
{
|
||||
wanted_target = RaceManager::getKart(0)->getXYZ().toIrrVector();
|
||||
// Follows the leader kart, higher off of the ground, further from the kart,
|
||||
// and turns in the opposite direction from the kart for a nice effect. :)
|
||||
float angle_around = RaceManager::getKart(0)->getHPR().getX();
|
||||
float angle_up = RaceManager::getKart(0)->getHPR().getY() + 40.0f*DEGREE_TO_RAD;
|
||||
wanted_position.setX(sin(angle_around));
|
||||
wanted_position.setY(cos(angle_around));
|
||||
wanted_position.setZ(sin(angle_up) );
|
||||
wanted_position *= m_distance * 2.0f;
|
||||
wanted_position += wanted_target;
|
||||
smoothMoveCamera(dt, wanted_position, wanted_target);
|
||||
break;
|
||||
}
|
||||
case CM_FINAL:
|
||||
{
|
||||
m_final_time +=dt;
|
||||
if(m_final_time < stk_config->m_final_camera_time)
|
||||
{
|
||||
const Track* track=RaceManager::getTrack();
|
||||
core::vector3df new_pos = m_camera->getPosition()+m_lin_velocity*dt;
|
||||
m_camera->setPosition(new_pos);
|
||||
core::vector3df new_target = m_camera->getTarget()+m_target_velocity*dt;
|
||||
m_camera->setTarget(new_target);
|
||||
}
|
||||
return;
|
||||
break;
|
||||
}
|
||||
case CM_SIMPLE_REPLAY:
|
||||
// TODO: Implement
|
||||
break;
|
||||
}
|
||||
|
||||
} // update
|
||||
|
||||
|
@ -51,35 +51,16 @@ private:
|
||||
* attached to. */
|
||||
unsigned int m_index;
|
||||
|
||||
/** The ultimate position which the camera wants to obtain. */
|
||||
Vec3 m_position;
|
||||
|
||||
/** The position the camera currently has. */
|
||||
Vec3 m_temp_position;
|
||||
|
||||
/** The ultimate target which the camera wants to obtain. */
|
||||
Vec3 m_target;
|
||||
|
||||
/** The target the camera currently has. */
|
||||
Vec3 m_temp_target;
|
||||
|
||||
/** Current ambient light for this camera. */
|
||||
video::SColor m_ambient_light;
|
||||
|
||||
/** Distance between the camera and the kart. */
|
||||
float m_distance;
|
||||
|
||||
/** Angle between the ground and the camera (with the kart as the
|
||||
* vertex of the angle). */
|
||||
float m_angle_up;
|
||||
|
||||
/** Angle around the kart (should actually match the rotation of the kart). */
|
||||
float m_angle_around;
|
||||
|
||||
/** The speed at which the camera changes position. */
|
||||
float m_position_speed;
|
||||
|
||||
/** The speed at which the camera changes targets. */
|
||||
/** The speed at which the camera target changes position. */
|
||||
float m_target_speed;
|
||||
|
||||
/** Factor of the effects of steering in camera aim. */
|
||||
@ -100,8 +81,21 @@ private:
|
||||
/** Aspect ratio for camera. */
|
||||
float m_aspect;
|
||||
|
||||
void setupCamera();
|
||||
/** Linear velocity of the camera, only used for end camera. */
|
||||
core::vector3df m_lin_velocity;
|
||||
|
||||
/** Velocity of the target of the camera, only used for end camera. */
|
||||
core::vector3df m_target_velocity;
|
||||
|
||||
/** Counts the time for the end camera only, to indicate when
|
||||
* the end camera should stop moving. */
|
||||
float m_final_time;
|
||||
|
||||
void setupCamera();
|
||||
void smoothMoveCamera(float dt, const Vec3 &wanted_position,
|
||||
const Vec3 &wanted_target);
|
||||
void computeNormalCameraPosition(Vec3 *wanted_position,
|
||||
Vec3 *wanted_target);
|
||||
public:
|
||||
Camera (int camera_index, const Kart* kart);
|
||||
~Camera ();
|
||||
|
@ -278,9 +278,9 @@ void PlayerKart::update(float dt)
|
||||
if (m_powerup.getType()==POWERUP_NOTHING)
|
||||
Kart::beep();
|
||||
}
|
||||
|
||||
m_camera->setMode(m_controls.m_look_back ? Camera::CM_REVERSE
|
||||
: Camera::CM_NORMAL);
|
||||
if(m_camera->getMode()!=Camera::CM_FINAL)
|
||||
m_camera->setMode(m_controls.m_look_back ? Camera::CM_REVERSE
|
||||
: Camera::CM_NORMAL);
|
||||
|
||||
// We can't restrict rescue to fulfil isOnGround() (which would be more like
|
||||
// MK), since e.g. in the City track it is possible for the kart to end
|
||||
|
@ -237,14 +237,6 @@ void Track::loadTrackInfo(const std::string &filename)
|
||||
|
||||
if(m_groups.size()==0)
|
||||
m_groups.push_back("standard");
|
||||
// if both camera position and rotation are defined,
|
||||
// set the flag that the track has final camera position
|
||||
m_has_final_camera = root->get("camera-final-position",
|
||||
&m_camera_final_position)!=1;
|
||||
m_has_final_camera &= root->get("camera-final-hpr",
|
||||
&m_camera_final_hpr) !=1;
|
||||
m_camera_final_hpr.degreeToRad();
|
||||
|
||||
const XMLNode *xml_node = root->getNode("curves");
|
||||
if(xml_node)
|
||||
loadCurves(*xml_node);
|
||||
@ -614,9 +606,13 @@ void Track::createWater(const XMLNode &node)
|
||||
* animations, items, ... It is called from world during initialisation.
|
||||
* Track is the first model to be loaded, so at this stage the root scene node
|
||||
* is empty.
|
||||
* \param mode_id Which of the modes of a track to use. This determines which
|
||||
* scene, quad, and graph file to load.
|
||||
*/
|
||||
void Track::loadTrackModel(unsigned int mode_id)
|
||||
{
|
||||
m_has_final_camera = false;
|
||||
m_is_arena = false;
|
||||
item_manager->setStyle();
|
||||
|
||||
// Load the graph only now: this function is called from world, after
|
||||
@ -740,6 +736,10 @@ void Track::loadTrackModel(unsigned int mode_id)
|
||||
{
|
||||
handleSky(*node, path);
|
||||
}
|
||||
else if (name=="camera")
|
||||
{
|
||||
handleCamera(*node);
|
||||
}
|
||||
else
|
||||
{
|
||||
fprintf(stderr, "Warning: element '%s' not found.\n",
|
||||
@ -862,8 +862,26 @@ void Track::handleSky(const XMLNode &xml_node, const std::string &filename)
|
||||
} // handleSky
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
/** Reads the final camera position.
|
||||
* \param root The XML node with the camera node.
|
||||
*/
|
||||
void Track::handleCamera(const XMLNode &root)
|
||||
{
|
||||
m_has_final_camera = true;
|
||||
root.get("final-position", &m_camera_final_position);
|
||||
root.get("final-hpr", &m_camera_final_hpr );
|
||||
m_camera_final_hpr.degreeToRad();
|
||||
} // handleCamera
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
/** Handle creation and placement of an item.
|
||||
* \param xyz The position of the item.
|
||||
* \param type The item type.
|
||||
* \param need_height True if the item Z position should be determined based on
|
||||
* the track topology.
|
||||
*/
|
||||
void Track::itemCommand(const Vec3 &xyz, Item::ItemType type,
|
||||
int bNeedHeight)
|
||||
int need_height)
|
||||
{
|
||||
// Some modes (e.g. time trial) don't have any bonus boxes
|
||||
if(type==Item::ITEM_BONUS_BOX &&
|
||||
@ -872,7 +890,7 @@ void Track::itemCommand(const Vec3 &xyz, Item::ItemType type,
|
||||
|
||||
Vec3 loc(xyz);
|
||||
// if only 2d coordinates are given, let the item fall from very high
|
||||
if(bNeedHeight)
|
||||
if(need_height)
|
||||
{
|
||||
loc.setZ(1000);
|
||||
loc.setZ(getTerrainHeight(loc));
|
||||
|
@ -73,14 +73,20 @@ private:
|
||||
scene::ILightSceneNode *m_sun;
|
||||
TriangleMesh* m_track_mesh;
|
||||
TriangleMesh* m_non_collision_mesh;
|
||||
/** True if the track/scene has a final camera position. */
|
||||
bool m_has_final_camera;
|
||||
/** The final xyz coordinates of the camera. */
|
||||
Vec3 m_camera_final_position;
|
||||
/** The final hpr rotation of the camera. */
|
||||
Vec3 m_camera_final_hpr;
|
||||
/** Minimum coordinates of this track. */
|
||||
Vec3 m_aabb_min;
|
||||
/** Maximum coordinates of this track. */
|
||||
Vec3 m_aabb_max;
|
||||
/** True if this track is an arena. */
|
||||
bool m_is_arena;
|
||||
/** The version of this track. A certain STK version will only support
|
||||
* certain track versions. */
|
||||
int m_version;
|
||||
|
||||
/** The graph used to connect the quads. */
|
||||
@ -166,6 +172,7 @@ private:
|
||||
void loadCurves(const XMLNode &node);
|
||||
void handleAnimatedTextures(scene::ISceneNode *node, const XMLNode &xml);
|
||||
void handleSky(const XMLNode &root, const std::string &filename);
|
||||
void handleCamera(const XMLNode &root);
|
||||
|
||||
public:
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user