在openGL中使用箭头键旋转参考系

Posted

技术标签:

【中文标题】在openGL中使用箭头键旋转参考系【英文标题】:Use arrow keys to rotate refrence system in openGL 【发布时间】:2013-07-23 13:06:24 【问题描述】:

这是写在openGL SuperBible一书中的代码,用于在屏幕上创建一个弹簧状的点路径:

#include "stdafx.h"
#include <Windows.h>
#include <gl\glut.h>
#include <gl\GLU.h>
#include <gl\GL.h>
#include <math.h>


// Define a constant for the value of PI
#define GL_PI 3.1415f



void ChangeSize(GLsizei , GLsizei );  
void SetupRC();
void RenderScene(void);


int main(int argc, CHAR* argv[])

    glutInit(&argc, argv);
    glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB);
    glutCreateWindow("Points Example");
    glutDisplayFunc(RenderScene);
    glutReshapeFunc(ChangeSize);
    SetupRC();
    glutMainLoop();
    return 0;


// Change viewing volume and viewport. Called when window is resized
void ChangeSize(GLsizei w, GLsizei h)

   GLfloat nRange = 100.0f;
   // Prevent a divide by zero
   if(h == 0)
       h = 1;
   // Set Viewport to window dimensions
   glViewport(0, 0, w, h);
   // Reset projection matrix stack
   glMatrixMode(GL_PROJECTION);
   glLoadIdentity();
   // Establish clipping volume (left, right, bottom, top, near, far)
   if (w <= h)
       glOrtho (-nRange, nRange, -nRange*h/w, nRange*h/w, -nRange, nRange);
   else
       glOrtho (-nRange*w/h, nRange*w/h, -nRange, nRange, -nRange, nRange);
   // Reset Model view matrix stack
   glMatrixMode(GL_MODELVIEW);
   glLoadIdentity();


// This function does any needed initialization on the rendering context
void SetupRC()

    // Black background
    glClearColor(0.0f, 0.0f, 0.0f, 1.0f );
   // Set drawing color to green
   glColor3f(0.0f, 1.0f, 0.0f);


// Called to draw scene
void RenderScene(void)

   GLfloat x,y,z,angle;
   int xRot,yRot; // Storage for coordinates and angles
   xRot = 45;
   yRot = 45;
   // Clear the window with current clearing color
   glClear(GL_COLOR_BUFFER_BIT);
   // Save matrix state and do the rotation
   glPushMatrix();
   glRotatef(xRot, 1.0f, 0.0f, 0.0f);
   glRotatef(yRot, 0.0f, 1.0f, 0.0f);
   // Call only once for all remaining points
   glBegin(GL_POINTS);
   z = -50.0f;
   for(angle = 0.0f; angle <= (2.0f*GL_PI)*3.0f; angle += 0.1f)
   
       x = 50.0f*sin(angle);
       y = 50.0f*cos(angle);
      // Specify the point and move the Z value up a little
      glVertex3f(x, y, z);
      z += 0.5f;
    
   // Done drawing points
   glEnd();
   // Restore transformations
   glPopMatrix();
   // Flush drawing commands
   glutSwapBuffers();
  

其实通过设置xRot=yRot=45度,我已经达到了这个形状。 但是书里说:当这个程序运行时,你看到的只是一个圆圈 点数,因为您最初是直接向下看 z 轴。要查看效果,请使用 箭头键围绕 x 轴和 y 轴旋转绘图。 这意味着我们应该有一些代码使用箭头键来增加和减少 xRot 和 yRot 的值。我为此付出了一些努力。

1-编写函数:

void _cdecl keyboard(int key ,int xRot,int yRot)

    switch (key)
    
    case GLUT_KEY_PAGE_UP:
        yRot++;
    case GLUT_KEY_PAGE_DOWN:
        yRot--;
    case GLUT_KEY_HOME:
        xRot--;
    case GLUT_KEY_END:
        xRot++;
    
  

2-代码顶部的原型:

void _cdecl keyboard(int,int,int);  

3-将这两行代码添加到函数RenderScene的主体中:

GLint key = GLUT_KEY_PAGE_UP;  
glutSpecialFunc(keyboard(key,xRot,yRot));  

但我不确定它是否会起作用。代码得到错误:

error C2664: 'glutSpecialFunc' : cannot convert parameter 1 from 'void' to 'void (__cdecl *)(int,int,int)'  

而且我不知道如何将xRotyRot 的更改值返回给调用者函数,因为编译器不允许我定义Pass by referrence 参数并且glutSpecialFunc 的参数是指向空函数的指针!

我的问题的编辑部分 正如 jblocksom 建议的那样,我将代码更改为以下内容: 1-在 main 开始之前定义和初始化全局变量:

int xRot = 0;
int yRot = 0;  

2- 在 main 的某处调用 glutSpecialFunc

glutSpecialFunc(keyboard);
glutDisplayFunc(RenderScene);
glutReshapeFunc(ChangeSize);  

3-修改键盘功能中的代码

void keyboard(int keyParam ,int mx,int my)

    switch (keyParam)
    
    case GLUT_KEY_PAGE_UP:
        my++;
    case GLUT_KEY_PAGE_DOWN:
        my--;
    case GLUT_KEY_HOME:
        mx--;
    case GLUT_KEY_END:
        mx++;
    
    glutPostRedisplay();
  

没有编译和运行时错误。但它不起作用。我认为这是因为当我调用glutSpecialFunc(keyboard) 时,该函数使用鼠标和按键的坐标作为输入参数,因此任何增量或减量都应用于鼠标坐标而不是xRotyRot,这将在@987654339 中使用@ 或 glRotatef(yRot, 0.0f, 1.0f, 0.0f) 所以当调用后两者时,xRotyRot 仍然等于零,不会有旋转。我需要将 xRotyRot 传递给函数 @987654345 @ 但是怎么做??? 甚至把函数写成:

void keyboard(int keyParam ,int mx,int my)

    switch (keyParam)
    
    case GLUT_KEY_PAGE_UP:
        yRot++;
    case GLUT_KEY_PAGE_DOWN:
        yRot--;
    case GLUT_KEY_HOME:
        xRot--;
    case GLUT_KEY_END:
        xRot++;
    
    glutPostRedisplay();
  

并以glutSpecialFunc(keyboard) 的形式调用它不会有任何区别!!!

【问题讨论】:

【参考方案1】:

glutSpecialFunc 向 GLUT 注册一个回调,当用户点击其中一个箭头键时调用该回调;你给它的功能,keyboard,不是你自称的东西。这就是为什么你不能从中返回任何东西。要从回调中获取数据,您需要设置一个全局变量。

您需要在设置了其他 GLUT 回调的main 中的某个位置调用glutSpecialFunc(例如glutRenderFunc)。为了克服编译错误,你可以这样称呼它:

glutSpecialFunc(keyboard);

告诉 GLUT 使用键和鼠标位置调用 keyboard()

RenderScene 中引用的xRotyRot 变量设为全局变量。

keyboard 的函数签名更改为不使用xRotyRot 作为变量名,以便引用全局变量名:

void _cdecl keyboard(int key, int mx, int my)

您可能还需要在keyboard 末尾调用glutPostRedisplay(),这将告诉GLUT 重绘场景。

希望之后它应该可以工作,祝你好运!

【讨论】:

感谢@jblocksom,但请参阅我的问题的已编辑部分。我希望你能帮助我。

以上是关于在openGL中使用箭头键旋转参考系的主要内容,如果未能解决你的问题,请参考以下文章

OpenGL在2个键上旋转相机

在 OpenGL 中使用箭头键移动一些形状 - 它缩小而不是移动

OpenGL / GLFW 显得透明

旋转后的OpenGL python和pygame翻译不适用于mouselook和移动

Opengl隐藏部分屏幕

Python之OpenGL笔记(22):箭头控制平面直角坐标系中的圆圈移动