四元数FPS相机

时间:2014-10-07 09:11:03

标签: opengl camera glut frame-rate quaternions

我正在尝试用GLUT和OpenGL创建一个FPS风格的相机。我被引导到我试图遵循的这个特定教程http://www.gamedev.net/page/resources/_/technical/math-and-physics/a-simple-quaternion-based-camera-r1997

对作者的代码进行了一些小改动(我有一个不同的四元数类,处理函数的方式略有不同),这是我的代码:

void RotateCamera(double Angle, double x, double y, double z)
{
  //quaternions in the form of w,x,y,z
  quaternion temp(cos(Angle/2), x*sin(Angle/2), y * sin(Angle/2),z * sin(Angle/2) );
  quaternion quat_view(0, view.x, view.y, view.z);
  quaternion result = operator*(operator*(temp, quat_view), temp.conjugate());
  view = result.vector();
}


void SetViewByMouse(int MouseX, int MouseY)
{

  // the middle of the screen in the x direction
  int MiddleX = G308_WIN_WIDTH/2;

  // the middle of the screen in the y direction
  int MiddleY = G308_WIN_HEIGHT/2;

  // vector that describes mouseposition - center
  G308_Point mouse_direction;
  mouse_direction.x = 0.0f;
  mouse_direction.y = 0.0f;
  mouse_direction.z = 0.0f;

  // static variable to store the rotation about the x-axis, since
  // we want to limit how far up or down we can look.
  // We don't need to cap the rotation about the y-axis as we
  // want to be able to turn around 360 degrees
  static double CurrentRotationX = 0.0;

  // The maximum angle we can look up or down, in radians
  double maxAngle = 1;


  // if the mouse hasn't moved, return without doing
  // anything to our view
  if((MouseX == MiddleX) && (MouseY == MiddleY))
    return;

  // otherwise move the mouse back to the middle of the screen
  glutWarpPointer(MiddleX, MiddleY);

  // get the distance and direction the mouse moved in x (in
  // pixels). We can't use the actual number of pixels in radians,
  // as only six pixels  would cause a full 360 degree rotation.
  // So we use a mousesensitivity variable that can be changed to
  // vary how many radians we want to turn in the x-direction for
  // a given mouse movement distance

  // We have to remember that positive rotation is counter-clockwise.
  // Moving the mouse down is a negative rotation about the x axis
  // Moving the mouse right is a negative rotation about the y axis
  mouse_direction.x = float((MiddleX - MouseX)/mouse_sensitivity);
  mouse_direction.y = float((MiddleY - MouseY)/mouse_sensitivity);

  CurrentRotationX += mouse_direction.y;

  // We don't want to rotate up more than one radian, so we cap it.
  if(CurrentRotationX > 1)
  {
    CurrentRotationX = 1;
    return;
  }
  // We don't want to rotate down more than one radian, so we cap it.
  if(CurrentRotationX < -1)
  {
    CurrentRotationX = -1;
    return;
  }
  else
  {
    // get the axis to rotate around the x-axis.
    G308_Point Axis = crossProduct(subtract(view,position), up);
    // To be able to use the quaternion conjugate, the axis to
    // rotate around must be normalized.
    Axis = normalise(Axis);

    // Rotate around the y axis
    RotateCamera(mouse_direction.y, Axis.x, Axis.y, Axis.z);
    // Rotate around the x axis
    RotateCamera(mouse_direction.x, 0, 1, 0);
  }

  glutPostRedisplay();
}

我已经制作了crossProduct,减去并规范了应该正常工作的函数。

问题

运行程序后,它会按预期显示场景,但是当我移动鼠标时,它会立即变黑。没有什么可以继续对不起......如果有帮助,我的鼠标灵敏度设置为0.1。

1 个答案:

答案 0 :(得分:0)

不确定这是否是您正在寻找的内容,但让我向您展示我的某个项目的一些片段

它在我正在使用它的项目的上下文中工作但是当我提取片段时可能会出现一些错误

// a function to build a quaternion from axis angle
inline Quat rotationAroundAxis(double r,Vec3 a){
    a=normalize(a);
    a*=sin(r/2);
    return Quat(a(0),a(1),a(2),cos(r/2));
}

// read the mouse movement, the important part is to get int dx,dy,dz somehow
int mx,my,mz;
glfwGetMousePos(&mx,&my);
mz=glfwGetMouseWheel();
int dmx=mx-oldMx;
int dmy=my-oldMy;
int dmz=mz-oldMz;
oldMx=mx;
oldMy=my;
oldMz=mz;

// get the current rotation
Quat r=cameraTransform()->getRotation();
//create a vector that encodes these
float sr=time_since_last_frame*100.0f;//sensitivity constant
Vec3 rv(-dmy*0.001*sr,-dmx*0.001*sr,dmz*0.1);
//rotate around the axis formed by the vector -rv with 
//the magnitude of the vectors normal norm(rv) 
Quat rot=normalize(rotationAroundAxis(norm(rv),-rv)*r);
//save the new rotation and update rotation matrix
cameraTransform()->setRotation(rot);

inline Matrix4x4 Transform::setRotation(Quat r){
    rotationQuat=r;//save rotation so we can get it later
    //convert to a rotation matrix and store it
    double x=r.i,y=r.j,z=r.k,w=r.r;
    rotation=matrix(1-2*y*y-2*z*z,2*x*y-2*z*w,2*x*z+2*y*w,0,
                    2*x*y+2*z*w,1-2*x*x-2*z*z,2*y*z-2*x*w,0,
                    2*x*z-2*y*w,2*y*z+2*x*w,1-2*x*x-2*y*y,0,
                    0,0,0,1);
}

// the rotation is later used to compute the transform of the camera to 
//its position in the scene
transform=scale*rotation*translate;

// invert it
worldToEye=transform.inverse();

//setup rendering
glMatrixMode(GL_MODELVIEW);
glPushMatrix();
glLoadIdentity();
glMultMatrixf((float*)&worldToEye);


// DRAW all objects here