【问题标题】:Converting perspective projection to orthogonal projection将透视投影转换为正交投影
【发布时间】:2014-07-06 08:02:05
【问题描述】:

我创建了这个程序,用户单击鼠标右键,他会得到一个菜单,他可以在其中选择在透视投影中绘制立方体或球体

我希望他能够将透视投影更改为正交投影。我希望通过正交投影将形状放置在同一个位置。

我希望他能够通过单击键盘上的“O”来执行此操作,并通过单击“p”返回透视。

如何在这段代码中混合正交投影?

#include <windows.h>
#include <stdio.h>
#include<math.h>

 #include <gl\glut.h>  // glut.h must come before gl.h and glu.h
#include <gl\gl.h>
#include <gl\glu.h> 

void menu(int value);
static int win;
static int menid;
static int submenid;
static int  left_click = GLUT_UP;
static int  right_click = GLUT_UP;
static int  xold;
static int  yold;
static int  width;
static int  height;
static float    rotate_x = 30;
static float    rotate_y = 15;
static float    alpha = 0;
static float    beta = 0;
static int primitive = 0;
 static int orth =0;
static int flag =0;

void        sphere (void)
{
  glBegin (GL_LINES);
  glColor3f (1, 0, 0); glVertex3f (-1, -1, -1); glVertex3f ( 1, -1, -1);
  glColor3f (0, 1, 0); glVertex3f (-1, -1, -1); glVertex3f (-1,  1, -1);
  glColor3f (0, 0, 1); glVertex3f (-1, -1, -1); glVertex3f (-1, -1,  1);

  glEnd ();
  glRotatef (beta, 1, 0, 0);
  glRotatef (alpha, 0, 1, 0);
  glColor3f (0, 1, 0);
  glutWireSphere(1.0, 20, 16);  
}

void        cube (void)
{
  glBegin (GL_LINES);
  glColor3f (1, 0, 0); glVertex3f (-1, -1, -1); glVertex3f ( 1, -1, -1);
  glColor3f (0, 1, 0); glVertex3f (-1, -1, -1); glVertex3f (-1,  1, -1);
  glColor3f (0, 0, 1); glVertex3f (-1, -1, -1); glVertex3f (-1, -1,  1);

  glEnd ();
  glRotatef (beta, 1, 0, 0);
  glRotatef (alpha, 0, 1, 0);
  glColor3f (1, 0, 0);
 glutWireCube(1);

}

void        KeyboardFunc (unsigned char key, int x, int y)
{
  xold = x; /* Has no effect: just to avoid a warning */
  yold = y;
  if ('q' == key || 'Q' == key || 27 == key)
      exit (0);
  if(key=='O' || key =='o')
 //does something to change the perspective to orthogonal...  
  // you would want to redraw now
  glutPostRedisplay();

}
void createMenu(void){

  // MENU //

  submenid = glutCreateMenu(menu);

  glutAddMenuEntry("cube", 2);
  glutAddMenuEntry("sphere", 3);

  menid = glutCreateMenu(menu);

  // Create an entry
  glutAddMenuEntry("Clear", 1);

  glutAddSubMenu("Draw", submenid);

  glutAddMenuEntry("Quit", 0);

  glutAttachMenu(GLUT_RIGHT_BUTTON);


}

void menu(int value)
{
  if(value == 0)
  {
    glutDestroyWindow(win);
    exit(0);
  }
  else{
    primitive=value;
  }
  glutPostRedisplay();
}

void        DisplayFunc (void)
{
  const float a = height / (float) width;
  const float b = width / (float) height;

  glClear (GL_COLOR_BUFFER_BIT);

    glMatrixMode(GL_PROJECTION);

 /* Perspective projection */
     glLoadIdentity();
    gluPerspective (20 * sqrt (1 + a * a), b, 8, 12);
    glMatrixMode(GL_MODELVIEW);
    glLoadIdentity();


/* Perspective view */
 glViewport (0, 0, width , height);
 glPushMatrix ();
glTranslatef (0, 0, -10);
glRotatef (rotate_y, 1, 0, 0);
glRotatef (rotate_x, 0, 1, 0);


  switch(primitive)
  {

case 2:
    cube();
    break;

case 3:
    sphere();
    break;
  }

  glPopMatrix ();

  glFlush ();
  glutSwapBuffers ();
}

void        ReshapeFunc (int new_width, int new_height)
{
  width = new_width;
  height = new_height;
  glutPostRedisplay();
}


void        MouseFunc (int button, int state, int x, int y)
{
  if (GLUT_LEFT_BUTTON == button)
    left_click = state;
  if (GLUT_RIGHT_BUTTON == button)
    right_click = state;
  xold = x;
  yold = y;
}

void        MotionFunc (int x, int y)
{
  if (GLUT_DOWN == left_click)
    {
      rotate_y = rotate_y + (y - yold) / 5.f;
      rotate_x = rotate_x + (x - xold) / 5.f;
      if (rotate_y > 90)
    rotate_y = 90;
      if (rotate_y < -90)
    rotate_y = -90;
      glutPostRedisplay ();
    }
  if (GLUT_DOWN == right_click)
    {
      beta = beta + (y - yold) / 2.f;
      alpha = alpha + (x - xold) / 2.f;
      glutPostRedisplay ();
    }
  xold = x;
  yold = y;
}


int     main (int argc, char **argv)
{
  /* Creation of the window */
  glutInit (&argc, argv);
  glutInitDisplayMode (GLUT_RGB | GLUT_DOUBLE);
  glutInitWindowSize (500, 500);
  glutCreateWindow ("perspective");

  /* OpenGL settings */
  glClearColor (0, 0, 0, 0);
  glEnable (GL_CULL_FACE);
  glCullFace (GL_BACK);
  glEnable (GL_BLEND);
  glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);

  /* Declaration of the callbacks */
  glutDisplayFunc (&DisplayFunc);
  glutReshapeFunc (&ReshapeFunc);
  glutKeyboardFunc (&KeyboardFunc);
  glutMouseFunc (&MouseFunc);
  glutMotionFunc (&MotionFunc);

    // put all the menu functions in one nice procedure
  createMenu();

  /* Loop */
  glutMainLoop ();
  return 0;
}

【问题讨论】:

  • 当用户点击O并重新渲染时改变投影变换。
  • 这正是我想要做的......但我不确定在哪里以及如何......
  • glMatrixMode(GL_PROJECTION); glLoadIdentity(); glOrtho(...); glMatrixMode(GL_MODELVIEW);。完成。
  • 我需要向 gloOrth 发送哪些参数才能获得对象的相同位置?

标签: opengl glut projection


【解决方案1】:

当然,使用正交投影,您无法获得与使用透视投影相同的图像。但是,您可以定义一个平面(我们称其为焦平面),该平面在两个变换中都投影到相同的位置。

您的垂直视野为20 * sqrt (1 + a * a)(顺便说一句,我怀疑这是一个合理的计算;fovy 应该以度为单位)。为了计算正交的边缘,我们需要半角。那么:

float halfY = 20 * sqrt (1 + a * a) / 2.0f * 3.1415926f / 180.0f;
float top = focus_plane * tan(halfY); //focus_plane is the distance from the camera
float right = top * aspectRatio;
glOrtho(-right, right, -top, top, 8, 12);

您可以将focus_plane 设置为zNearzFar 之间的中间值,在本例中设置为10

【讨论】:

  • 谢谢。我会尽快看看,让你知道它是否适合我:-)
  • 顺便说一句.. aspectRatio 应该是多少?
  • 对于透视投影,你通过了b。通常,这是window_width / window_height
  • 这一行float right = focus_plane * tan(halfY * aspectRatio);应该是float right = focus_plane * tan(halfY) * aspectRatio;
  • @AlexeyS。你是对的,谢谢你的发现;已编辑。
猜你喜欢
  • 2013-11-26
  • 2018-06-14
  • 1970-01-01
  • 2016-02-11
  • 1970-01-01
  • 2021-12-24
  • 1970-01-01
  • 1970-01-01
  • 2015-08-25
相关资源
最近更新 更多