Brand new camera using smooth transitions.
Does not yet support: splitscreen, 'final camera' mode, 'replay' mode, or looking backwards. Also, *No support for plib* uses only irrlicht. git-svn-id: svn+ssh://svn.code.sf.net/p/supertuxkart/code/main/branches/irrlicht@3466 178a84e3-b1eb-0310-8ba1-8eac791a3b58
This commit is contained in:
parent
14b49c58cb
commit
7dd6011a8e
@ -37,18 +37,14 @@ Camera::Camera(int camera_index, const Kart* kart)
|
|||||||
m_camera = irr_driver->addCamera();
|
m_camera = irr_driver->addCamera();
|
||||||
m_distance = kart->getKartProperties()->getCameraDistance();
|
m_distance = kart->getKartProperties()->getCameraDistance();
|
||||||
m_kart = kart;
|
m_kart = kart;
|
||||||
m_xyz = kart->getXYZ();
|
m_angle_up = 0.0f;
|
||||||
m_hpr = Vec3(0,0,0);
|
m_angle_around = 0.0f;
|
||||||
|
|
||||||
// FIXME: clipping should be configurable for slower machines
|
// TODO: Put these values into a config file
|
||||||
const Track* track = RaceManager::getTrack();
|
m_position_speed = 8.0f;
|
||||||
#ifdef HAVE_IRRLICHT
|
m_target_speed = 10.0;
|
||||||
#else
|
|
||||||
if (track->useFog())
|
// TODO: Set fog distance and clipping planes
|
||||||
m_context -> setNearFar ( 0.05f, track->getFogEnd() ) ;
|
|
||||||
else
|
|
||||||
m_context -> setNearFar ( 0.05f, 1000.0f ) ;
|
|
||||||
#endif
|
|
||||||
setScreenPosition(camera_index);
|
setScreenPosition(camera_index);
|
||||||
} // Camera
|
} // Camera
|
||||||
|
|
||||||
@ -56,10 +52,6 @@ Camera::Camera(int camera_index, const Kart* kart)
|
|||||||
Camera::~Camera()
|
Camera::~Camera()
|
||||||
{
|
{
|
||||||
reset();
|
reset();
|
||||||
#ifdef HAVE_IRRLICHT
|
|
||||||
#else
|
|
||||||
if(m_context) delete m_context;
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// ----------------------------------------------------------------------------
|
// ----------------------------------------------------------------------------
|
||||||
@ -70,18 +62,12 @@ void Camera::setScreenPosition(int camera_index)
|
|||||||
|
|
||||||
if (num_players == 1)
|
if (num_players == 1)
|
||||||
{
|
{
|
||||||
#ifdef HAVE_IRRLICHT
|
// m_camera->setFOV( DEGREE_TO_RAD(75.0f) ) ;
|
||||||
#else
|
|
||||||
m_context -> setFOV ( 75.0f, 0.0f ) ;
|
|
||||||
#endif
|
|
||||||
m_x = 0.0f; m_y = 0.0f; m_w = 1.0f; m_h = 1.0f ;
|
m_x = 0.0f; m_y = 0.0f; m_w = 1.0f; m_h = 1.0f ;
|
||||||
}
|
}
|
||||||
else if (num_players == 2)
|
else if (num_players == 2)
|
||||||
{
|
{
|
||||||
#ifdef HAVE_IRRLICHT
|
// m_context -> setFOV ( 85.0f, 85.0f*3.0f/8.0f ) ;
|
||||||
#else
|
|
||||||
m_context -> setFOV ( 85.0f, 85.0f*3.0f/8.0f ) ;
|
|
||||||
#endif
|
|
||||||
switch ( camera_index )
|
switch ( camera_index )
|
||||||
{
|
{
|
||||||
case 0 : m_x = 0.0f; m_y = 0.5f; m_w = 1.0f; m_h = 0.5f; break;
|
case 0 : m_x = 0.0f; m_y = 0.5f; m_w = 1.0f; m_h = 0.5f; break;
|
||||||
@ -90,28 +76,21 @@ void Camera::setScreenPosition(int camera_index)
|
|||||||
}
|
}
|
||||||
else if (num_players == 3)
|
else if (num_players == 3)
|
||||||
{
|
{
|
||||||
#ifdef HAVE_IRRLICHT
|
// m_context -> setFOV ( 50.0f, 0.0f );
|
||||||
#else
|
|
||||||
m_context -> setFOV ( 50.0f, 0.0f );
|
|
||||||
#endif
|
|
||||||
switch ( camera_index )
|
switch ( camera_index )
|
||||||
{
|
{
|
||||||
case 0 : m_x = 0.0f; m_y = 0.5f; m_w = 0.5f; m_h = 0.5f; break;
|
case 0 : m_x = 0.0f; m_y = 0.5f; m_w = 0.5f; m_h = 0.5f; break;
|
||||||
case 1 : m_x = 0.5f; m_y = 0.5f; m_w = 0.5f; m_h = 0.5f; break;
|
case 1 : m_x = 0.5f; m_y = 0.5f; m_w = 0.5f; m_h = 0.5f; break;
|
||||||
case 2 : m_x = 0.0f; m_y = 0.0f; m_w = 1.0f; m_h = 0.5f;
|
case 2 : m_x = 0.0f; m_y = 0.0f; m_w = 1.0f; m_h = 0.5f;
|
||||||
#ifdef HAVE_IRRLICHT
|
// m_context -> setFOV ( 85.0f, 85.0f*3.0f/8.0f );
|
||||||
#else
|
|
||||||
m_context -> setFOV ( 85.0f, 85.0f*3.0f/8.0f );
|
|
||||||
#endif
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (num_players == 4)
|
else if (num_players == 4)
|
||||||
{
|
{
|
||||||
#ifdef HAVE_IRRLICHT
|
// m_context -> setFOV ( 50.0f, 0.0f );
|
||||||
#else
|
|
||||||
m_context -> setFOV ( 50.0f, 0.0f );
|
|
||||||
#endif
|
|
||||||
switch ( camera_index )
|
switch ( camera_index )
|
||||||
{
|
{
|
||||||
case 0 : m_x = 0.0f; m_y = 0.5f; m_w = 0.5f; m_h = 0.5f; break;
|
case 0 : m_x = 0.0f; m_y = 0.5f; m_w = 0.5f; m_h = 0.5f; break;
|
||||||
@ -120,40 +99,12 @@ void Camera::setScreenPosition(int camera_index)
|
|||||||
case 3 : m_x = 0.5f; m_y = 0.0f; m_w = 0.5f; m_h = 0.5f; break;
|
case 3 : m_x = 0.5f; m_y = 0.0f; m_w = 0.5f; m_h = 0.5f; break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
m_last_pitch = 0.0f;
|
|
||||||
} // setScreenPosition
|
} // setScreenPosition
|
||||||
|
|
||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
void Camera::setMode(Mode mode)
|
void Camera::setMode(Mode mode)
|
||||||
{
|
{
|
||||||
if(mode==CM_FINAL)
|
|
||||||
{
|
|
||||||
const Track* track=RaceManager::getTrack();
|
|
||||||
// If the track doesn't have a final position, ignore this mode
|
|
||||||
if(!track->hasFinalCamera()) return;
|
|
||||||
m_velocity = (track->getCameraPosition()-m_xyz)
|
|
||||||
/ stk_config->m_final_camera_time;
|
|
||||||
m_angular_velocity = (track->getCameraHPR()-m_hpr)
|
|
||||||
/ stk_config->m_final_camera_time;
|
|
||||||
m_final_time = 0.0f;
|
|
||||||
}
|
|
||||||
m_mode = mode;
|
m_mode = mode;
|
||||||
m_last_pitch = 0.0f;
|
|
||||||
if(m_mode==CM_CLOSEUP)
|
|
||||||
m_distance = 2.5f;
|
|
||||||
else
|
|
||||||
{
|
|
||||||
m_distance = m_kart->getKartProperties()->getCameraDistance();
|
|
||||||
|
|
||||||
// In splitscreen mode we have a different FOVs and rotations so we use
|
|
||||||
// 1.333 or 1.5 times the normal distance to compensate and make the
|
|
||||||
// kart visible
|
|
||||||
const int num_players = race_manager->getNumPlayers();
|
|
||||||
if(num_players==2 || (num_players==3 && m_index==3) )
|
|
||||||
m_distance *= 1.5f;
|
|
||||||
else if(num_players>=3)
|
|
||||||
m_distance *= 1.3333333f;
|
|
||||||
}
|
|
||||||
} // setMode
|
} // setMode
|
||||||
|
|
||||||
// ----------------------------------------------------------------------------
|
// ----------------------------------------------------------------------------
|
||||||
@ -169,7 +120,7 @@ Camera::Mode Camera::getMode()
|
|||||||
void Camera::reset()
|
void Camera::reset()
|
||||||
{
|
{
|
||||||
setMode(CM_NORMAL);
|
setMode(CM_NORMAL);
|
||||||
// m_xyz etc are set when the worlds has computed the right starting
|
// 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.
|
// position of all karts and calls setInitialTransform for each camera.
|
||||||
|
|
||||||
} // reset
|
} // reset
|
||||||
@ -180,132 +131,79 @@ void Camera::reset()
|
|||||||
*/
|
*/
|
||||||
void Camera::setInitialTransform()
|
void Camera::setInitialTransform()
|
||||||
{
|
{
|
||||||
btTransform t = m_kart->getBody()->getCenterOfMassTransform();
|
m_position = Vec3(0,0,0);
|
||||||
m_xyz = t.getOrigin();
|
m_target = m_kart->getXYZ();
|
||||||
Coord c(t);
|
m_temp_position = m_position;
|
||||||
m_hpr = c.getHPR();
|
m_temp_target = m_target;
|
||||||
m_last_pitch = m_hpr.getPitch();
|
|
||||||
sound_manager->positionListener(m_xyz, m_xyz);
|
|
||||||
} // updateKartPosition
|
} // updateKartPosition
|
||||||
|
|
||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
void Camera::update(float dt)
|
void Camera::update(float dt)
|
||||||
{
|
{
|
||||||
if(m_mode==CM_FINAL) return finalCamera(dt);
|
// 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.
|
||||||
Vec3 kart_xyz, kart_hpr;
|
switch(m_mode)
|
||||||
const Kart *kart;
|
|
||||||
|
|
||||||
// First define the position of the kart
|
|
||||||
if(m_mode==CM_LEADER_MODE)
|
|
||||||
{
|
{
|
||||||
kart = RaceManager::getKart(0);
|
case CM_NORMAL:
|
||||||
kart_hpr = kart->getHPR();
|
m_target = m_kart->getXYZ();
|
||||||
|
m_angle_around = m_kart->getHPR().getX();
|
||||||
|
m_angle_up = m_kart->getHPR().getY() - DEGREE_TO_RAD(30.0f);
|
||||||
|
|
||||||
|
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_CLOSEUP: // Lower to the ground and closer to the kart
|
||||||
|
m_target = m_kart->getXYZ();
|
||||||
|
m_angle_around = m_kart->getHPR().getX();
|
||||||
|
m_angle_up = m_kart->getHPR().getY() - DEGREE_TO_RAD(20.0f);
|
||||||
|
|
||||||
|
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_target = RaceManager::getKart(0)->getXYZ();
|
||||||
|
m_angle_around = RaceManager::getKart(0)->getHPR().getX();
|
||||||
|
m_angle_up = RaceManager::getKart(0)->getHPR().getY() + DEGREE_TO_RAD(40.0f);
|
||||||
|
|
||||||
|
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:
|
||||||
|
// TODO: Implement
|
||||||
|
break;
|
||||||
|
case CM_SIMPLE_REPLAY:
|
||||||
|
// TODO: Implement
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
else
|
|
||||||
{
|
|
||||||
kart = m_kart;
|
|
||||||
kart_hpr = kart->getHPR();
|
|
||||||
// Use the terrain pitch to avoid the camera following a wheelie the kart is doing
|
|
||||||
kart_hpr.setPitch( m_kart->getTerrainPitch(kart_hpr.getHeading()) );
|
|
||||||
kart_hpr.setRoll(0.0f);
|
|
||||||
// Only adjust the pitch if it's not the race start, otherwise
|
|
||||||
// the camera will change pitch during ready-set-go.
|
|
||||||
if(RaceManager::getWorld()->isRacePhase())
|
|
||||||
{
|
|
||||||
// If the terrain pitch is 'significantly' different from the camera angle,
|
|
||||||
// start adjusting the camera. This helps with steep declines, where
|
|
||||||
// otherwise the track is not visible anymore.
|
|
||||||
if(fabsf(kart_hpr.getPitch()-m_last_pitch)>M_PI/180.0f) {
|
|
||||||
m_last_pitch = m_last_pitch + (kart_hpr.getPitch()-m_last_pitch)*2.0f*dt;
|
|
||||||
}
|
|
||||||
kart_hpr.setPitch(m_last_pitch);
|
|
||||||
} // dt>0.0
|
|
||||||
} // m_mode!=CM_LEADER_MODE
|
|
||||||
kart_xyz = kart->getXYZ();
|
|
||||||
if(m_mode==CM_SIMPLE_REPLAY) kart_hpr.setHeading(0.0f);
|
|
||||||
|
|
||||||
// Set the camera position relative to the kart
|
// Smoothly interpolate towards the position and target
|
||||||
// --------------------------------------------
|
m_temp_target += ((m_target - m_temp_target) * m_target_speed) * dt;
|
||||||
// The reverse mode and the cam used in follow the leader mode (when a
|
m_temp_position += ((m_position - m_temp_position) * m_position_speed) * dt;
|
||||||
// kart has been eliminated) are facing backwards:
|
|
||||||
bool reverse = m_kart->getControls().m_look_back || m_mode==CM_LEADER_MODE;
|
|
||||||
Vec3 cam_rel_pos(0.f, reverse ? m_distance : -m_distance, 1.5f);
|
|
||||||
|
|
||||||
// Set the camera rotation
|
m_camera->setPosition(m_temp_position.toIrrVector());
|
||||||
// -----------------------
|
m_camera->setTarget(m_temp_target.toIrrVector());
|
||||||
float sign = reverse ? 1.0f : -1.0f;
|
|
||||||
float pitch;
|
|
||||||
if(m_mode!=CM_CLOSEUP)
|
|
||||||
pitch = race_manager->getNumLocalPlayers()>1 ? sign * DEGREE_TO_RAD(10.0f)
|
|
||||||
: sign * DEGREE_TO_RAD(15.0f);
|
|
||||||
else
|
|
||||||
pitch = sign * DEGREE_TO_RAD(25.0f);
|
|
||||||
|
|
||||||
btQuaternion cam_rot(0.0f, -pitch, reverse ? M_PI : 0.0f);
|
|
||||||
// Camera position relative to the kart
|
|
||||||
btTransform relative_to_kart(cam_rot, cam_rel_pos);
|
|
||||||
|
|
||||||
btMatrix3x3 rotation;
|
|
||||||
rotation.setEulerZYX(kart_hpr.getPitch(), kart_hpr.getRoll(), kart_hpr.getHeading());
|
|
||||||
btTransform result = btTransform(rotation, kart_xyz) * relative_to_kart;
|
|
||||||
|
|
||||||
// Convert transform to coordinate and pass on to plib
|
|
||||||
Coord c(result);
|
|
||||||
m_xyz = c.getXYZ();
|
|
||||||
m_hpr = c.getHPR();
|
|
||||||
m_camera->setPosition(m_xyz.toIrrVector());
|
|
||||||
m_camera->setTarget(kart_xyz.toIrrVector());
|
|
||||||
if(race_manager->getNumLocalPlayers() < 2)
|
if(race_manager->getNumLocalPlayers() < 2)
|
||||||
sound_manager->positionListener(m_xyz, kart_xyz - m_xyz);
|
sound_manager->positionListener(m_temp_position, m_temp_target - m_temp_position);
|
||||||
|
|
||||||
} // update
|
} // update
|
||||||
|
|
||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
void Camera::finalCamera(float dt)
|
|
||||||
{
|
|
||||||
// Turn/move the camera for 1 second only
|
|
||||||
m_final_time += dt;
|
|
||||||
if( m_final_time<stk_config->m_final_camera_time )
|
|
||||||
{
|
|
||||||
m_xyz += m_velocity*dt;
|
|
||||||
m_hpr += m_angular_velocity*dt;
|
|
||||||
m_camera->setPosition(m_xyz.toIrrVector());
|
|
||||||
// FIXME: target position needs to be computed
|
|
||||||
// m_camera->setTarget(target_xyz.toIrrVector());
|
|
||||||
}
|
|
||||||
#undef TEST_END_CAMERA_POSITION
|
|
||||||
#ifdef TEST_END_CAMERA_POSITION
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// This code is helpful when tweaking the final camera position:
|
|
||||||
// Just set a breakpoint here, change the values for x,y,z,h,p,r,
|
|
||||||
// and then keep on running, and you can see what the final position
|
|
||||||
// looks like. When happy, just put these value as
|
|
||||||
// camera-final-position and camera-final-hpr in the .track file.
|
|
||||||
static float x=5,y=20,z=3,h=180,p=-10,r=0.0f;
|
|
||||||
Vec3 xyz(x,y,z);
|
|
||||||
Vec3 hpr(DEGREE_TO_RAD(h),DEGREE_TO_RAD(p),DEGREE_TO_RAD(r));
|
|
||||||
Coord coord(xyz, hpr);
|
|
||||||
m_context->setCamera(&coord.toSgCoord());
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
} // finalCamera
|
|
||||||
|
|
||||||
//-----------------------------------------------------------------------------
|
|
||||||
|
|
||||||
void Camera::apply ()
|
void Camera::apply ()
|
||||||
{
|
{
|
||||||
int width = user_config->m_width ;
|
|
||||||
int height = user_config->m_height;
|
|
||||||
|
|
||||||
#ifdef HAVE_IRRLICHT
|
|
||||||
#else
|
|
||||||
glViewport ( (int)((float)width * m_x),
|
|
||||||
(int)((float)height * m_y),
|
|
||||||
(int)((float)width * m_w),
|
|
||||||
(int)((float)height * m_h) ) ;
|
|
||||||
m_context -> makeCurrent () ;
|
|
||||||
#endif
|
|
||||||
} // apply
|
} // apply
|
||||||
|
|
||||||
|
@ -37,33 +37,35 @@ public:
|
|||||||
enum Mode {
|
enum Mode {
|
||||||
CM_NORMAL, // Normal camera mode
|
CM_NORMAL, // Normal camera mode
|
||||||
CM_CLOSEUP, // Normal camera, closer to kart
|
CM_CLOSEUP, // Normal camera, closer to kart
|
||||||
CM_DRIFTING, // FIXME: drifting behind when accelerating = not yet implemented
|
|
||||||
CM_LEADER_MODE, // for deleted player karts in follow the leader
|
CM_LEADER_MODE, // for deleted player karts in follow the leader
|
||||||
CM_FINAL, // Final camera to show the end of the race
|
CM_FINAL, // Final camera to show the end of the race
|
||||||
CM_SIMPLE_REPLAY
|
CM_SIMPLE_REPLAY
|
||||||
};
|
};
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
#ifdef HAVE_IRRLICHT
|
#ifdef HAVE_IRRLICHT
|
||||||
scene::ICameraSceneNode
|
scene::ICameraSceneNode
|
||||||
*m_camera;
|
*m_camera;
|
||||||
#else
|
|
||||||
ssgContext *m_context;
|
|
||||||
#endif
|
#endif
|
||||||
Vec3 m_xyz; // current position of camera
|
Mode m_mode; // Camera's mode
|
||||||
Vec3 m_hpr; // heading, pitch, roll of camera
|
Vec3 m_position; // The ultimate position which the camera wants to obtain
|
||||||
const Kart *m_kart; // the kart the camera is attached to
|
Vec3 m_temp_position; // The position the camera currently has
|
||||||
Mode m_mode; // CM_ value, see above
|
Vec3 m_target; // The ultimate target which the camera wants to obtain
|
||||||
int m_index; /**<Index of camera. */
|
Vec3 m_temp_target; // The target the camera currently has
|
||||||
float m_x, m_y, m_w, m_h; // window to us
|
|
||||||
float m_current_speed; // current speed of camera
|
int m_index;
|
||||||
float m_last_pitch; // for tiling the camera when going downhill
|
|
||||||
float m_distance; // distance between camera and kart
|
float m_distance; // Distance between the camera and the kart
|
||||||
Vec3 m_velocity; // camera velocity for final mode
|
float m_angle_up; // Angle between the ground and the camera (with the kart as the vertex of the angle)
|
||||||
Vec3 m_angular_velocity; // camera angular velocity for final mode
|
float m_angle_around; // Angle around the kart (should actually match the rotation of the kart)
|
||||||
float m_final_time; // time when final camera mode started
|
float m_position_speed; // The speed at which the camera changes position
|
||||||
|
float m_target_speed; // The speed at which the camera changes targets
|
||||||
|
|
||||||
|
float m_x, m_y, m_w, m_h;
|
||||||
|
|
||||||
|
const Kart *m_kart; // The kart that the camera follows
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void finalCamera (float dt); // handle the final camera
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
Camera (int camera_index, const Kart* kart);
|
Camera (int camera_index, const Kart* kart);
|
||||||
|
Loading…
Reference in New Issue
Block a user