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

时间:2013-07-23 13:06:25

标签: visual-studio-2010 visual-c++ opengl function-pointers glut

这是在书openGL SuperBible中编写的代码,用于在屏幕上创建一个Spring-Shaped Path of Points:

#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度,我已经达到了这个形状 enter image description here
但在书中告诉他们:
运行此程序时,您看到的只是一个圆圈 因为你最初直接沿着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是指向void函数的指针!

我的问题的编辑部分
正如jblocksom建议我将代码改为这样的:
1,在主要开始之前定义和初始化全局变量:

int xRot = 0;
int yRot = 0;  

2-在主要的

中调用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)时,该函数使用mouse和keypress的坐标作为输入参数,因此任何增量或减量都应用于鼠标坐标而不是xRotyRot将在glRotatef(xRot, 1.0f, 0.0f, 0.0f)glRotatef(yRot, 0.0f, 1.0f, 0.0f)中使用,因此在调用后者时,xRotyRot仍然等于零,并且不会轮换。我需要将xRotyRot传递给函数keyboard但是如何???
甚至将函数编写为:

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 个答案:

答案 0 :(得分:3)

当用户点击其中一个箭头键时,

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

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

glutSpecialFunc(keyboard);

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

制作xRot全球中提到的yRotRenderScene个变量。

keyboard的功能签名更改为不使用xRotyRot作为变量名称,以便它引用全局名称:

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

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

希望在那之后它应该有效,祝你好运!