在 OpenGL 中移动 3d 形状

Posted

技术标签:

【中文标题】在 OpenGL 中移动 3d 形状【英文标题】:Moving 3d Shape in OpenGL 【发布时间】:2015-10-17 21:20:47 【问题描述】:

我正在用 OpenGL/C++ 编写一个程序,该程序会创建许多球体,然后将它们移动到靠近屏幕的位置,直到它们消失为止。 我了解如何创建球体,但我似乎无法弄清楚在创建球体后如何移动它们。有谁知道我如何有效地更改 move() 函数,以便每次调用它时将 z 增加 1?或者如果有更好的方法来做到这一点,请告诉我。谢谢!

 class Sphere 

public:
    double x, y, z;
    void create(double newx, double newy, double r, double g, double b) 
        x = newx;
        y = newy;
        z = -175; // start at back of projection matrix
        glPushMatrix();
        glTranslatef(x, y, z);
        glColor3f(r, g, b);
        glScalef(1.0, 1.0, 1.0);
        glutSolidSphere(1, 50, 50);
        glPopMatrix();
    
    void move() 
        glPushMatrix();
        //if z is at front, move to start over in the back
        if (z >= 0) 
            z = -176;
            x = rand() % 100;
            y = rand() % 100;
            x = x - 50;
            y = y - 50;
        
        x = x;
        y = y;
        glPushMatrix();
        z++;
        glTranslatef(x, y, z);
        glPopMatrix();
    
;

【问题讨论】:

【参考方案1】:

为了改变球体的位置,不必在 move() 函数中调用 glPushMatrix() 和 glPopMatrix() 函数。您可以将 move() 函数简化为:

    void Move() 
        //if z is at front, move to start over in the back
        if (z >= 0) 
            z = -176;
        
        z++;
    

此外,就像用户 datenwolf 所说,您没有创建,而是“绘制”或“渲染”一个球体(或您希望 OpenGL 显示的任何 3D 对象)。给您举个例子,让我们使用 Render。

你想要的是创建一个 Render() 函数并将代码从你的 create() 函数移动到它。因为您想稍后移动球体的位置,所以将 x、y 和 z 坐标移动到球体的构造函数并初始化它们。

例子:

 class Sphere 
  public:
    double x,y,z;

    // We also set the color values of the sphere inside the sphere's
    // constructor for simplicity sake.
    double r,g,b;

   Sphere(double _x, double _y, double _z) 
        x = _x;
        y = _y;
        z = _z;

        r = 1.0;
        g = 0.0;
        b = 0.0;

    
    void Render() 
        glPushMatrix();
        glTranslatef(x, y, z);
        glColor3f(r, g, b);
        glScalef(1.0, 1.0, 1.0);
        glutSolidSphere(1, 50, 50);
        glPopMatrix();
    

;

OpenGL 使用称为 glutDisplayFunc() 的回调函数。您将一个函数传递给此 glutDisplayFunc() 以呈现您想要在屏幕上显示的所有内容。我将调用要传递的函数“void Render3DEnvironment()”。您需要找到您的 glutDisplayFunc() 和传递给它的函数,并在那里调用球体的 Render() 函数。

这是一个例子:

#include "Sphere.h"

Sphere* sphere;

void Render3DEnvironment()

    sphere->Render();
    sphere->Move();


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


    glutInit(&argc, argv);
    glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE | GLUT_DEPTH);

    sphere = new Sphere(50,50,50);

    glutDisplayFunc(Render3DEnvironment);

    glutMainLoop();

    return 0;


glutDisplayFunc() 函数将不断调用已传递给它的函数,在本例中为 Render3DEnvironment() 函数。如您所见,在 Render3DEnviroment() 函数中也调用了 Move() 函数。这意味着您的球体也在 z 轴上(快速)移动并在 z 达到等于 0 或大于 0 的值时跳回 -176。

提示:使用 GLfloat 而不是 double 作为 x,y,z 和 r,g,b 变量的数据类型,因为相关 OpenGL 函数使用 GLfloat 变量。为您节省一些编译器警告。

【讨论】:

【参考方案2】:

在 OpenGL 中没有创建“模型”。实际上,在 OpenGL 中甚至没有“模型”。只有一个数字画布,称为帧缓冲区,以及 OpenGL 提供的用于绘制点、线和三角形的绘图工具,一次一个。当你用 OpenGL 画东西的那一刻,它就已经忘记了。

因此,将函数命名为“create”的整个概念是错误的。取而代之的是“绘图”功能。

所以你要做的很简单:重绘场景,但你的几何体在不同的位置。

【讨论】:

既然 OpenGL 忘记了它创建的形状,要删除形状并重新绘制它们,我是否需要使用 glClear(GL_COLOR_BUFFER_BIT) 清除整个屏幕然后重新绘制? @Sarah:这是一般的想法是的。请记住:OpenGL 不知道“场景”是什么。帧缓冲区中只有点、线、三角形和像素。记住这一点,与 OpenGL 相关的一切都会变得非常容易。在编写 OpenGL 时,将事物视为屏幕空间中的像素是很有意义的;处理图像做事是完全有条理的。

以上是关于在 OpenGL 中移动 3d 形状的主要内容,如果未能解决你的问题,请参考以下文章

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

在使用 C++ 在 OpenGL 中移动形状时按时间自动旋转形状

使用 C++ 在 OpenGL 中移动自动旋转的 3d 多边形

如何在OpenGL中实现形状的原位旋转和旋转状态下的移动?

3D Computer Grapihcs Using OpenGL - 18 相机移动

opengl 绘制和移动原始形状