简体   繁体   English

在第一人称视角和第三人称视角(OpenGL)之间切换

[英]Switching Between First and Third Person Views (OpenGL)

I'm trying to implement a simple 3D environment that a robot can walk around. 我正在尝试实现一个机器人可以走动的简单3D环境。 I want the user to be able to switch between first and third person views for the robot. 我希望用户能够在机器人的第一人称视角和第三人称视角之间切换。

I have implemented the robot, and a simple area with a few other objects. 我已经实现了机器人以及一个带有其他一些对象的简单区域。 Currently, the view is 3rd person. 当前,该视图是第三人称。 I've been using the gluPerspective function to try to implement a first person that turns when the head turns (head turn already implemented), but it seems like no matter the parameters I use, I can't get the toggling to work. 我一直在使用gluPerspective函数尝试实现人头转动时已经转过头的第一人(已经实现了头转弯),但是无论我使用什么参数,似乎都无法进行切换。 It always stays the same. 它始终保持不变。 Is there a simpler way to achieve this effect than what I've tried so far? 有没有比我到目前为止尝试过的方法更简单的方法来达到这种效果? Is what I'm doing not working because of my approach? 是因为我的方法而没有做的工作吗?

The following code suffices to set the perspective to first person, however it does not follow the head of the figure as I expect. 下面的代码足以将透视图设置为第一人称视角,但是它并不符合我的期望。 I can initialize it on top of him, but I'm not sure how to make the robot move with the camera, as the landscape effectively moves around him. 我可以在他上面初始化它,但是我不确定如何使机器人随相机移动,因为风景有效地围绕着他移动。 I was thinking I could sort of 'fake' this by removing the robot while in first person. 我当时想我可以通过在第一人称视角时移开机器人来“假装”这种东西。 Thoughts? 有什么想法吗? :

glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
double atx = xPos + cos(lookAngle);
double atz = zPos + sin(lookAngle);
double atHeight = eyeHeight + eyeIncline;
gluLookAt(xPos, eyeHeight, zPos, atx, atHeight, atz, 0.0, 1.0, 0.0);

I have tried calling a switch statement in a keyboard function to switch to 3rd person. 我尝试在键盘功能中调用switch语句以切换到第三人称。 Keyboard call looks something like this: 键盘调用如下所示:

void key(unsigned char k, int x, int y)
{
if ( k == 27 ) /* Escape */
  exit(0);
else if ( k == 86 ) { /* 'v' for view change */
   glMatrixMode(GL_MODELVIEW);
   glLoadIdentity();
   gluLookAt(0, 0, -20, 0, 0, -1, 0, 1, 0); //Look down z-axis

}
glutPostRedisplay();
}

But it doesn't work. 但这是行不通的。 No toggling is done. 没有切换。

Code below: 代码如下:

#define GLUT_DISABLE_ATEXIT_HACK

#include <GL/glut.h>
#include <GL/gl.h>
#include <math.h>

#define TORSO_HEIGHT 5.0
#define UPPER_ARM_HEIGHT 3.0
#define LOWER_ARM_HEIGHT 2.0
#define UPPER_LEG_RADIUS  0.5
#define LOWER_LEG_RADIUS  0.5
#define LOWER_LEG_HEIGHT 2.0
#define UPPER_LEG_HEIGHT 3.0
#define UPPER_LEG_RADIUS  0.5
#define TORSO_RADIUS 1.0
#define UPPER_ARM_RADIUS  0.5
#define LOWER_ARM_RADIUS  0.5
#define HEAD_HEIGHT 1.5
#define HEAD_RADIUS 1.0

double cubeX[] = { 5.0, 5.0, 5.0 };
double cubeY[] = { 3.0, 3.0, 3.0 };
double cubeZ[] = { 7.0, 5.0, 3.0 };
double cubeR[] = { 1.0, 0.0, 0.0 };
double cubeG[] = { 0.0, 1.0, 0.0 };
double cubeB[] = { 0.0, 0.0, 1.0 };

double xPos = 2.0, zPos = 5.0;
double eyeHeight = 4.5;
double eyeIncline = -0.5;
double lookAngle = 0.0; //In rads

double posIncr = 0.25;
double thetaIncr = 0.1;

typedef float point[3];

static GLfloat theta[11] = {0.0,0.0,0.0,0.0,0.0,0.0,0.0,
        180.0,0.0,180.0,0.0}; /* initial joint angles */
static GLint angle = 2;

GLUquadricObj *t, *h, *lua, *lla, *rua, *rla, *lll, *rll, *rul, *lul, *lf1, *lf2;

double size=1.0;

void torso()
{
glPushMatrix();
glRotatef(-90.0, 1.0, 0.0, 0.0);
gluCylinder(t,TORSO_RADIUS, TORSO_RADIUS, TORSO_HEIGHT,10,10);
glPopMatrix();
}

void head()
{
glPushMatrix();
glTranslatef(0.0, 0.5*HEAD_HEIGHT,0.0);
glScalef(HEAD_RADIUS, HEAD_HEIGHT, HEAD_RADIUS);
gluSphere(h,1.0,10,10);
glPopMatrix();
}

void left_upper_arm()
{
glPushMatrix();
glRotatef(-90.0, 1.0, 0.0, 0.0);
gluCylinder(lua,UPPER_ARM_RADIUS, UPPER_ARM_RADIUS, UPPER_ARM_HEIGHT,10,10);
glPopMatrix();
}

void left_lower_arm()
{
glPushMatrix();
glRotatef(-90.0, 1.0, 0.0, 0.0);
gluCylinder(lla,LOWER_ARM_RADIUS, LOWER_ARM_RADIUS, LOWER_ARM_HEIGHT,10,10);
glPopMatrix();
}

void left_finger1()
{
glPushMatrix();
glRotatef(-90.0, 1.0, 0.0, 0.0);
gluCylinder(lf1,FINGER_1_RADIUS, FINGER_1_RADIUS, FINGER_1_HEIGHT,10,10);
glPopMatrix();
}

void left_finger2()
{
glPushMatrix();
glRotatef(-90.0, 1.0, 0.0, 0.0);
gluCylinder(lla,LOWER_ARM_RADIUS, LOWER_ARM_RADIUS, LOWER_ARM_HEIGHT,10,10);
glPopMatrix();
} 

void right_upper_arm()
{
glPushMatrix();
glRotatef(-90.0, 1.0, 0.0, 0.0);
gluCylinder(rua,UPPER_ARM_RADIUS, UPPER_ARM_RADIUS, UPPER_ARM_HEIGHT,10,10);
glPopMatrix();
}

void right_lower_arm()
{
glPushMatrix();
glRotatef(-90.0, 1.0, 0.0, 0.0);
gluCylinder(rla,LOWER_ARM_RADIUS, LOWER_ARM_RADIUS, LOWER_ARM_HEIGHT,10,10);
glPopMatrix();
}

void left_upper_leg()
{
glPushMatrix();
glRotatef(-90.0, 1.0, 0.0, 0.0);
gluCylinder(lul,UPPER_LEG_RADIUS, UPPER_LEG_RADIUS, UPPER_LEG_HEIGHT,10,10);
glPopMatrix();
}

void left_lower_leg()
{
glPushMatrix();
glRotatef(-90.0, 1.0, 0.0, 0.0);
gluCylinder(lll,LOWER_LEG_RADIUS, LOWER_LEG_RADIUS, LOWER_LEG_HEIGHT,10,10);
glPopMatrix();
}

void right_upper_leg()
{
glPushMatrix();
glRotatef(-90.0, 1.0, 0.0, 0.0);
gluCylinder(rul,UPPER_LEG_RADIUS, UPPER_LEG_RADIUS, UPPER_LEG_HEIGHT,10,10);
glPopMatrix();
}

void right_lower_leg()
{
glPushMatrix();
glRotatef(-90.0, 1.0, 0.0, 0.0);
gluCylinder(rll,LOWER_LEG_RADIUS, LOWER_LEG_RADIUS, LOWER_LEG_HEIGHT,10,10);
glPopMatrix();
}

void drawCube( int i )
{
double x = cubeX[i];
double y = cubeY[i];
double z = cubeZ[i];

glColor3i(1, 0, 0); //Red cube
glPushMatrix();
glTranslatef(x,y,z);
glutSolidCube(1);
glPopMatrix();

glColor3i(0, 1, 0); //Green Cube
glPushMatrix();
glTranslatef(x,y,z);
glutSolidCube(1);
glPopMatrix();

glColor3i(0, 0, 1); //Blue Cube
glPushMatrix();
glTranslatef(x,y,z);
glutSolidCube(1);
glPopMatrix();

glColor3i(0, 1, 1);
glPushMatrix();
glTranslatef(x,y,z);
glutSolidCube(1);
glPopMatrix();

}

void drawCubes(void)
{

glLoadName(1);
drawCube(0);

glLoadName(2);
drawCube(1);

glLoadName(3);
drawCube(2);

/* Set name back to '0' to indicate background. */
glLoadName(0);
}

void drawFloor(void)
{
GLfloat mat_diffuse[] = { 0.5, 0.5, 0.5, 1.0 };
glMaterialfv(GL_FRONT, GL_DIFFUSE, mat_diffuse);
glBegin(GL_POLYGON);
  glNormal3f(0.0, 1.0, 0.0);
  glVertex3f(-10.0, 0.0, -10.0);
  glVertex3f(10.0, 0.0, -10.0);
  glVertex3f(10.0, 0.0,  10.0);
  glVertex3f(-10.0, 0.0,  10.0);
glEnd();
}

void doDrawing(void)
{

drawCubes();

drawFloor();

/* Everything else is a lighter shade of grey. */
GLfloat mat_diffuse[] = { 0.8, 0.8, 0.8, 1.0 };
glMaterialfv(GL_FRONT, GL_DIFFUSE, mat_diffuse);
}

void drawEnviro(void)
{
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
double atx = xPos + cos(lookAngle);
double atz = zPos + sin(lookAngle);
double atHeight = eyeHeight + eyeIncline;
gluLookAt(xPos, eyeHeight, zPos, atx, atHeight, atz, 0.0, 1.0, 0.0);

glPushMatrix();
doDrawing();
glPopMatrix();
}

void display(void)
{
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
drawEnviro();
glLoadIdentity();
gluLookAt(0, 0, -20, 0, 0, -1, 0, 1, 0);
glColor3f(0.0, 0.0, 0.0);

glRotatef(theta[0], 0.0, 1.0, 0.0);
torso();
glPushMatrix();

glTranslatef(0.0, TORSO_HEIGHT+0.5*HEAD_HEIGHT, 0.0);
glRotatef(theta[1], 1.0, 0.0, 0.0);
glRotatef(theta[2], 0.0, 1.0, 0.0);
glTranslatef(0.0, -0.5*HEAD_HEIGHT, 0.0);
head();

glPopMatrix();
glPushMatrix();
glTranslatef(-(TORSO_RADIUS + UPPER_ARM_RADIUS), 0.9 * TORSO_HEIGHT, 0.0);
glRotatef(theta[3], 1.0, 0.0, 0.0);
left_upper_arm();

glTranslatef(0.0, UPPER_ARM_HEIGHT, 0.0);
glRotatef(theta[4], 1.0, 0.0, 0.0);
left_lower_arm();

glTranslatef(0.0, LOWER_ARM_HEIGHT, 0.0);
glRotatef(theta[11], 1.0, 0.0, 0.0);
left_finger1();

glPopMatrix();
glPushMatrix();
glTranslatef(TORSO_RADIUS+UPPER_ARM_RADIUS, 0.9*TORSO_HEIGHT, 0.0);
glRotatef(theta[5], 1.0, 0.0, 0.0);
right_upper_arm();

glTranslatef(0.0, UPPER_ARM_HEIGHT, 0.0);
glRotatef(theta[6], 1.0, 0.0, 0.0);
right_lower_arm();

glPopMatrix();
glPushMatrix();
glTranslatef(-(TORSO_RADIUS+UPPER_LEG_RADIUS), 0.1*UPPER_LEG_HEIGHT, 0.0);
glRotatef(theta[7], 1.0, 0.0, 0.0);
left_upper_leg();

glTranslatef(0.0, UPPER_LEG_HEIGHT, 0.0);
glRotatef(theta[8], 1.0, 0.0, 0.0);
left_lower_leg();

glPopMatrix();
glPushMatrix();
glTranslatef(TORSO_RADIUS+UPPER_LEG_RADIUS, 0.1*UPPER_LEG_HEIGHT, 0.0);
glRotatef(theta[9], 1.0, 0.0, 0.0);
right_upper_leg();

glTranslatef(0.0, UPPER_LEG_HEIGHT, 0.0);
glRotatef(theta[10], 1.0, 0.0, 0.0);
right_lower_leg();

glPopMatrix();

glFlush();
glutSwapBuffers();
}

void setProjection(void)
{
gluPerspective(60.0, 1.0, 0.1, 100.0);
}

void mouse(int btn, int state, int x, int y)
{
  if(btn==GLUT_LEFT_BUTTON && state == GLUT_DOWN)
    {
    theta[angle] += 5.0;
    if( theta[angle] > 360.0 ) theta[angle] -= 360.0;
    }
  if(btn==GLUT_RIGHT_BUTTON && state == GLUT_DOWN)
    {
    theta[angle] -= 5.0;
    if( theta[angle] < 360.0 ) theta[angle] += 360.0;
    }
    display();
 }

void menu(int id)
{
if (id < 11 ) angle = id;
if (id == 11 ) exit(0);
}

void specialKey(int k, int x, int y)
{
/* Accept commands to move the viewpoint. */
switch (k) {
  case GLUT_KEY_UP:
     xPos += posIncr * cos(lookAngle);
     zPos += posIncr * sin(lookAngle);
     break;
  case GLUT_KEY_DOWN:
     xPos -= posIncr * cos(lookAngle);
     zPos -= posIncr * sin(lookAngle);
     break;
  case GLUT_KEY_LEFT:
     lookAngle -= thetaIncr;
     break;
  case GLUT_KEY_RIGHT:
     lookAngle += thetaIncr;
     break;
  case GLUT_KEY_PAGE_UP:
     eyeIncline += 0.5;
     break;
  case GLUT_KEY_PAGE_DOWN:
     eyeIncline -= 0.5;
     break;
  case GLUT_KEY_HOME:
     eyeHeight += 0.5;
     break;
  case GLUT_KEY_END:
     eyeHeight -= 0.5;
     break;
  default:
     return;
  }
  glutPostRedisplay();
 }

void reshape(int w, int h) 
{
glViewport(0, 0, w, h);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluPerspective (65.0, w/h, 1, 1000.0);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
}

void init()
{
    GLfloat mat_specular[]={1.0, 1.0, 1.0, 1.0};
    GLfloat mat_diffuse[]={1.0, 1.0, 1.0, 1.0};
    GLfloat mat_ambient[]={1.0, 1.0, 1.0, 1.0};
    GLfloat mat_shininess={100.0};
    GLfloat light_ambient[]={0.0, 0.0, 0.0, 1.0};
    GLfloat light_diffuse[]={1.0, 1.0, 1.0, 1.0};
    GLfloat light_specular[]={1.0, 1.0, 1.0, 1.0};
    GLfloat light_position[]={10.0, 10.0, 10.0, 0.0};

    glLightfv(GL_LIGHT0, GL_POSITION, light_position);
    glLightfv(GL_LIGHT0, GL_AMBIENT, light_ambient);
    glLightfv(GL_LIGHT0, GL_DIFFUSE, light_diffuse);
    glLightfv(GL_LIGHT0, GL_SPECULAR, light_specular);

    glMaterialfv(GL_FRONT, GL_SPECULAR, mat_specular);
    glMaterialfv(GL_FRONT, GL_AMBIENT, mat_ambient);
    glMaterialfv(GL_FRONT, GL_DIFFUSE, mat_diffuse);
    glMaterialf(GL_FRONT, GL_SHININESS, mat_shininess);

    glShadeModel(GL_SMOOTH);
    glEnable(GL_LIGHTING);
    glEnable(GL_LIGHT0);
    glDepthFunc(GL_LEQUAL);
    glEnable(GL_DEPTH_TEST);

    glClearColor(0.0, 0.0, 0.0, 0.0);
    glMatrixMode(GL_PROJECTION);

    glLoadIdentity();
    setProjection();

    //Fill the body parts of the robot
    h=gluNewQuadric();
    gluQuadricDrawStyle(h, GLU_FILL);
    t=gluNewQuadric();
    gluQuadricDrawStyle(t, GLU_FILL);
    lua=gluNewQuadric();
    gluQuadricDrawStyle(lua, GLU_FILL);
    lla=gluNewQuadric();
    gluQuadricDrawStyle(lla, GLU_FILL);
    rua=gluNewQuadric();
    gluQuadricDrawStyle(rua, GLU_FILL);
    rla=gluNewQuadric();
    gluQuadricDrawStyle(rla, GLU_FILL);
    lul=gluNewQuadric();
    gluQuadricDrawStyle(lul, GLU_FILL);
    lll=gluNewQuadric();
    gluQuadricDrawStyle(lll, GLU_FILL);
    rul=gluNewQuadric();
    gluQuadricDrawStyle(rul, GLU_FILL);
    rll=gluNewQuadric();
    gluQuadricDrawStyle(rll, GLU_FILL);
    lf1=gluNewQuadric();
    gluQuadricDrawStyle(lf1, GLU_FILL);

 }

int main(int argc, char **argv)
{
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH);
glutInitWindowSize(500, 500);
glutCreateWindow("robot");
init();
glutReshapeFunc(reshape);
glutDisplayFunc(display);
glutMouseFunc(mouse);
glutSpecialFunc(specialKey);

glutCreateMenu(menu);
glutAddMenuEntry("torso", 0);
glutAddMenuEntry("head1", 1);
glutAddMenuEntry("head2", 2);
glutAddMenuEntry("right_upper_arm", 3);
glutAddMenuEntry("right_lower_arm", 4);
glutAddMenuEntry("left_upper_arm", 5);
glutAddMenuEntry("left_lower_arm", 6);
glutAddMenuEntry("right_upper_leg", 7);
glutAddMenuEntry("right_lower_leg", 8);
glutAddMenuEntry("left_upper_leg", 9);
glutAddMenuEntry("left_lower_leg", 10);
glutAddMenuEntry("quit", 11);
glutAttachMenu(GLUT_MIDDLE_BUTTON);

glutMainLoop();

return 0;
}

Like everything that's related to draw stuff, setting the projection matrix (together with setting the viewport and the modelview matrix) belongs into the drawing code path, in your case display . 就像所有与绘图相关的东西一样,在您的案例display ,设置投影矩阵(以及设置视口和模型视图矩阵)都属于绘图代码路径。 Do not place it in reshape . 不要将其reshape And init is completely wrong for doing this. init是完全错误的。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM