Ok.
I've got yaw and roll to work by using an empty parent node to control the position and yaw and the main player node to control roll.
I then added a grandparent empty node to control pitch.
This doesn't work unfortunately.
Here's the code:
Code: Select all
// set up previous rotation state
float old_yaw=0, old_pitch=0, old_roll=0;
while(device->run())
if (device->isWindowActive())
{
if (quit)
{
device->closeDevice();
}
// Get delta time
irr::u32 now = timer->getTime();
delta_time = (now - then) / 1000.f;
then = now;
get_input();
player1.x+=sin(player1.dir*core::DEGTORAD)*(player1.speed*delta_time);
player1.z+=cos(player1.dir*core::DEGTORAD)*(player1.speed*delta_time);
// position fighter
float yaw=player1.dir;
float fighter_z=player1.z;
float fighter_x=player1.x;
float fighter_h=terrain->getHeight(fighter_x,fighter_z);
fighter_grandparent->setPosition(core::vector3df(player1.x,fighter_h+80,player1.z));
fighter->setPosition(core::vector3df(0,0,0));
// get heights at wing tips
float l = 80.0f; // length of ship/2
float w = 40.0f; // width of ship/2
float bx_yaw=yaw+90;
if (bx_yaw>359) bx_yaw-=360;
float bx1_x=fighter_x+sin((bx_yaw)*core::DEGTORAD)*w;
float bx1_z=fighter_z+cos((bx_yaw)*core::DEGTORAD)*w;
float bx2_x=fighter_x+sin((bx_yaw)*core::DEGTORAD)*-w;
float bx2_z=fighter_z+cos((bx_yaw)*core::DEGTORAD)*-w;
float z1 = terrain->getHeight(bx1_x,bx1_z);
float z2 = terrain->getHeight(bx2_x,bx2_z);
// get heights at nose/tail
float bx3_x=fighter_x+sin((yaw)*core::DEGTORAD)*l;
float bx3_z=fighter_z+cos((yaw)*core::DEGTORAD)*l;
float bx4_x=fighter_x+sin((yaw)*core::DEGTORAD)*-l;
float bx4_z=fighter_z+cos((yaw)*core::DEGTORAD)*-l;
float x1 = terrain->getHeight(bx3_x,bx3_z);
float x2 = terrain->getHeight(bx4_x,bx4_z);
// calc roll and pitch values
float roll = atan(z1/40-z2/40)*core::RADTODEG; // the division is to compensate for scaling
float pitch = atan(x2/40-x1/40)*core::RADTODEG;
// get relative rotations
float yaw_offset=yaw-old_yaw;
float pitch_offset=pitch-old_pitch;
float roll_offset=roll-old_roll;
turn_ship(fighter_parent,yaw_offset);
roll_ship(fighter,roll_offset);
pitch_ship(fighter_grandparent,pitch_offset);
old_yaw=yaw;
old_roll=roll;
old_pitch=pitch;
// position camera
float cam_x=player1.x+(sin(player1.dir*core::DEGTORAD)*-600);
float cam_z=player1.z+(cos(player1.dir*core::DEGTORAD)*-600);
float cam_y=terrain->getHeight(cam_x,cam_z);
float cam_diff=fighter_h-cam_y;
float cam_target_x=sin(player1.dir*core::DEGTORAD)*(450+cam_diff);
float cam_target_z=cos(player1.dir*core::DEGTORAD)*(450+cam_diff);
camera->setPosition(core::vector3df(cam_x,cam_y+400,cam_z));
camera->setTarget(core::vector3df(player1.x+(cam_target_x),cam_y+50,player1.z+(cam_target_z)));
camera->updateAbsolutePosition();
driver->beginScene(true, true, 0 );
smgr->drawAll();
env->drawAll();
driver->endScene();
// display frames per second in window title
int fps = driver->getFPS();
if (lastFPS != fps)
{
core::stringw str = L"Advanced Tactical Fighter - Demo [";
str += driver->getName();
str += "] FPS:";
str += fps;
str += " ";
device->setWindowCaption(str.c_str());
lastFPS = fps;
}
}
device->drop();
return 0;
}
// Act on input
bool get_input()
{
if (keys[irr::KEY_KEY_W] || keys[irr::KEY_UP])
{
player1.speed+=400*delta_time;
if (player1.speed>1000) player1.speed=1000;
}
if (keys[irr::KEY_KEY_S] || keys[irr::KEY_DOWN])
{
player1.speed-=400*delta_time;
if (player1.speed<-1000) player1.speed=-1000;
}
if (keys[irr::KEY_KEY_A] || keys[irr::KEY_LEFT])
{
player1.dir-=player1.turn_rate*delta_time;
if (player1.dir<0) player1.dir+=360;
}
if (keys[irr::KEY_KEY_D] || keys[irr::KEY_RIGHT])
{
player1.dir+=player1.turn_rate*delta_time;
if (player1.dir>359) player1.dir-=360;
}
return false;
}
void init_player()
{
player1.x=2942;
player1.y=0;
player1.z=4143;
player1.dir=0;
player1.speed=0;
player1.turn_rate=30;
}
//--- rotate node relative to its current rotation -used in turn,pitch,roll ---
void rotate(irr::scene::ISceneNode *node, irr::core::vector3df rot)
{
irr::core::matrix4 m;
m.setRotationDegrees(node->getRotation());
irr::core::matrix4 n;
n.setRotationDegrees(rot);
m *= n;
node->setRotation( m.getRotationDegrees() );
node->updateAbsolutePosition();
}
//--- turn ship left or right ---
void turn_ship(irr::scene::ISceneNode *node, irr::f32 rot)
{
rotate(node, irr::core::vector3df(0.0f, rot, 0.0f) );
}
//--- pitch ship up or down ---
void pitch_ship(irr::scene::ISceneNode *node, irr::f32 rot)
{
rotate(node, irr::core::vector3df(rot, 0.0f, 0.0f) );
}
//--- roll ship left or right ---
void roll_ship(irr::scene::ISceneNode *node, irr::f32 rot)
{
rotate(node, irr::core::vector3df(0.0f, 0.0f, rot) );
}
Anyone any ideas? I think I need to use quaternions but my 3D math is rubbish and I've barely understood 3D vectors.
This is probably really obvious and I just need a pointer in the right direction.
Here is a video of it running with yaw and roll:
http://www.youtube.com/watch?v=5EFzUC5PcpE