Opengl 透视投影到正交投影的转换

Opengl 透视投影到正交投影的转换,opengl,glut,projection,Opengl,Glut,Projection,我创建了这个程序,用户点击鼠标右键,他会得到一个菜单,可以选择在透视投影中绘制立方体或球体 我希望他能够将透视投影改为正交投影。我想把形状放在同一个点上,只是用正交投影 我希望他能够通过点击键盘上的“O”来完成,然后点击“p”返回透视图 如何在这段代码中混合正交投影 #include <windows.h> #include <stdio.h> #include<math.h> #include <gl\glut.h> // glut.h m

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

我希望他能够将透视投影改为正交投影。我想把形状放在同一个点上,只是用正交投影

我希望他能够通过点击键盘上的“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;
}
#包括
#包括
#包括
#include//glut.h必须位于gl.h和glu.h之前
#包括
#包括
无效菜单(int值);
静态int-win;
静态int-menid;
静态int子菜单;
静态int左键单击=过量向上;
静态int右键单击=GLUT向上;
静态int-xold;
静态int-yold;
静态整数宽度;
静态内高度;
静态浮动旋转_x=30;
静态浮动旋转_y=15;
静态浮点α=0;
静态浮动β=0;
静态int基元=0;
静态int-orth=0;
静态int标志=0;
空心球(空心球)
{
glBegin(GL_行);
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);
格伦德();
glRotatef(β,1,0,0);
glRotatef(α,0,1,0);
gl3f(0,1,0);
(1.0,20,16);
}
空心立方体(空心)
{
glBegin(GL_行);
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);
格伦德();
glRotatef(β,1,0,0);
glRotatef(α,0,1,0);
gl3f(1,0,0);
立方体(1);
}
void KeyboardFunc(无符号字符键,整数x,整数y)
{
xold=x;/*没有效果:只是为了避免警告*/
yold=y;
如果('q'==键| |'q'==键| | 27==键)
出口(0);
如果(键=='O'| |键=='O')
//将透视图更改为正交。。。
//你现在就想重画
再发现();
}
void创建菜单(void){
//菜单//
子菜单=创建菜单(菜单);
戊二醛(“立方体”,2);
戊二醛(“球体”,3);
menid=创建菜单(菜单);
//创建一个条目
戊二醛(“透明”,1);
子菜单(“绘制”,子菜单);
戊二醛(“退出”,0);
谷胱甘肽功能表(GLUT_右键);
}
无效菜单(int值)
{
如果(值==0)
{
窗口(win);
出口(0);
}
否则{
原语=值;
}
再发现();
}
void DisplayFunc(void)
{
常量浮动a=高度/(浮动)宽度;
常量浮动b=宽度/(浮动)高度;
glClear(GLU颜色缓冲位);
glMatrixMode(GL_投影);
/*透视投影*/
glLoadIdentity();
(20*sqrt(1+a*a)、b、8、12);
glMatrixMode(GLU模型视图);
glLoadIdentity();
/*透视图*/
glViewport(0,0,宽度,高度);
glPushMatrix();
glTranslatef(0,0,-10);
glRotatef(旋转y,1,0,0);
glRotatef(rotate_x,0,1,0);
开关(原语)
{
案例2:
立方体();
打破
案例3:
球体();
打破
}
glPopMatrix();
glFlush();
glutSwapBuffers();
}
空心形状(整型新宽度,整型新高度)
{
宽度=新宽度;
高度=新高度;
再发现();
}
void MouseFunc(int按钮、int状态、int x、int y)
{
if(GLUT\U左按钮==按钮)
左键单击=状态;
if(GLUT\U RIGHT\U按钮==按钮)
右击=状态;
xold=x;
yold=y;
}
void MotionFunc(整数x,整数y)
{
如果(GLUT\U DOWN==左键单击)
{
rotate_y=rotate_y+(y-yold)/5.f;
rotate_x=rotate_x+(x-xold)/5.f;
如果(旋转y>90)
旋转y=90;
如果(旋转y<-90)
旋转y=-90;
再发现();
}
如果(GLUT\U DOWN==右键单击)
{
β=β+(y-yold)/2.f;
α=α+(x-xold)/2.f;
再发现();
}
xold=x;
yold=y;
}
int main(int argc,字符**argv)
{
/*窗口的创建*/
glutInit(&argc,argv);
glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE);
glutInitWindowSize(500500);
创建窗口(“透视图”);
/*OpenGL设置*/
glClearColor(0,0,0,0);
glEnable(GL_CULL_面);
正面(背面);
glEnable(GL_混合物);
glBlendFunc(GL_SRC_ALPHA,GL_ONE_减去GL_SRC_ALPHA);
/*撤回声明*/
glutDisplayFunc(&DisplayFunc);
GLUTREFORUNC(和REFORFORUNC);
glutKeyboardFunc(&KeyboardFunc);
glutMouseFunc(&MouseFunc);
glutMotionFunc(&MotionFunc);
//将所有菜单功能放在一个漂亮的程序中
createMenu();
/*环路*/
glutMainLoop();
返回0;
}

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

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

float halfY=20*sqrt(1+a*a)/2.0f*3.1415926f/180.0f;
浮顶=焦点平面*棕褐色(半色调)//focus_plane是距摄影机的距离
右浮动=顶部*aspectRatio;
格洛托(-right,right,-top,top,8,12);

您可以将
focus\u plane
设置在
zNear
zFar
之间的中间,在这种情况下,使用正交投影将
10
,当然,您无法获得与透视投影相同的图像。但是,可以定义在两个变换中投影到同一位置的平面(我们称之为焦点平面)

尤哈