在QT环境下用OpenGL绘制一个边长为5的立方体,并为立方体贴上自定义纹理。写出实现该功能的具体

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了在QT环境下用OpenGL绘制一个边长为5的立方体,并为立方体贴上自定义纹理。写出实现该功能的具体相关的知识,希望对你有一定的参考价值。

void MyGLWidget::loadGLTexture()

QImage image(":/dog.jpg");
image = image.convertToFormat(QImage::Format_RGB888);
image = image.mirrored();
glGenTextures(1, &mTexture[0]);

glBindTexture(GL_TEXTURE_2D,mTexture[0]);

glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB,
image.width(), image.height(), 0,
GL_RGB, GL_UNSIGNED_BYTE,
image.bits());
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);


void MyGLWidget::paintGL()

glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // 清除屏幕和深度缓存
glLoadIdentity(); // 重置当前的模型观察矩阵
glTranslatef(0.0f,0.0f,-5.0f); // 移入屏幕 5 个单位
//下面三行使立方体绕X、Y、Z轴旋转。旋转多少依赖于变量 xrot , yrot 和 zrot 的值。
glRotatef(mXRotate,1.0f,0.0f,0.0f); // X轴旋转
glRotatef(mYRotate,0.0f,1.0f,0.0f); // Y轴旋转
glRotatef(mZRotate,0.0f,0.0f,1.0f); // Z轴旋转

//下一行代码选择我们使用的纹理。
//如果您在您的场景中使用多个纹理,您应该使用来 glBindTexture(GL_TEXTURE_2D, texture[ 所使用纹理对应的数字 ]) 选择要绑定的
//纹理。当您想改变纹理时,应该绑定新的纹理。有一点值得指出的是,您不能在 glBegin() 和 glEnd() 之间绑定纹理,必须在 glBegin()
//之前或 glEnd() 之后绑定。注意我们在后面是如何使用 glBindTexture 来指定和绑定纹理的。
glBindTexture(GL_TEXTURE_2D, mTexture[0]); // 选择纹理
//为了将纹理正确的映射到四边形上,您必须将纹理的右上角映射到四边形的右上角,纹理的左上角映射到四边形的左上角,
//纹理的右下角映射到四边形的右下角,纹理的左下角映射到四边形的左下角。
//如果映射错误的话,图像显示时可能上下颠倒,侧向一边或者什么都不是。
//glTexCoord2f 的第一个参数是X坐标。 0.0f 是纹理的左侧。 0.5f 是纹理的中点, 1.0f 是纹理的右侧。
//glTexCoord2f 的第二个参数是Y坐标。 0.0f 是纹理的底部。 0.5f 是纹理的中点, 1.0f 是纹理的顶部。
//所以纹理的左上坐标是 X:0.0f,Y:1.0f ,四边形的左上顶点是 X: -1.0f,Y:1.0f 。其余三点依此类推。
//试着玩玩 glTexCoord2f X, Y坐标参数。把 1.0f 改为 0.5f 将只显示纹理的左半部分,把 0.0f 改为 0.5f 将只显示纹理的右半部分。
glBegin(GL_QUADS);
// 前面
glTexCoord2f(0.0f, 0.0f); glVertex3f(-1.0f, -1.0f, 1.0f); // 纹理和四边形的左下
glTexCoord2f(1.0f, 0.0f); glVertex3f( 1.0f, -1.0f, 1.0f); // 纹理和四边形的右下
glTexCoord2f(1.0f, 1.0f); glVertex3f( 1.0f, 1.0f, 1.0f); // 纹理和四边形的右上
glTexCoord2f(0.0f, 1.0f); glVertex3f(-1.0f, 1.0f, 1.0f); // 纹理和四边形的左上
// 后面
glTexCoord2f(1.0f, 0.0f); glVertex3f(-1.0f, -1.0f, -1.0f); // 纹理和四边形的右下
glTexCoord2f(1.0f, 1.0f); glVertex3f(-1.0f, 1.0f, -1.0f); // 纹理和四边形的右上
glTexCoord2f(0.0f, 1.0f); glVertex3f( 1.0f, 1.0f, -1.0f); // 纹理和四边形的左上
glTexCoord2f(0.0f, 0.0f); glVertex3f( 1.0f, -1.0f, -1.0f); // 纹理和四边形的左下
// 顶面
glTexCoord2f(0.0f, 1.0f); glVertex3f(-1.0f, 1.0f, -1.0f); // 纹理和四边形的左上
glTexCoord2f(0.0f, 0.0f); glVertex3f(-1.0f, 1.0f, 1.0f); // 纹理和四边形的左下
glTexCoord2f(1.0f, 0.0f); glVertex3f( 1.0f, 1.0f, 1.0f); // 纹理和四边形的右下
glTexCoord2f(1.0f, 1.0f); glVertex3f( 1.0f, 1.0f, -1.0f); // 纹理和四边形的右上
// 底面
glTexCoord2f(1.0f, 1.0f); glVertex3f(-1.0f, -1.0f, -1.0f); // 纹理和四边形的右上
glTexCoord2f(0.0f, 1.0f); glVertex3f( 1.0f, -1.0f, -1.0f); // 纹理和四边形的左上
glTexCoord2f(0.0f, 0.0f); glVertex3f( 1.0f, -1.0f, 1.0f); // 纹理和四边形的左下
glTexCoord2f(1.0f, 0.0f); glVertex3f(-1.0f, -1.0f, 1.0f); // 纹理和四边形的右下

// 右面
glTexCoord2f(1.0f, 0.0f); glVertex3f( 1.0f, -1.0f, -1.0f); // 纹理和四边形的右下
glTexCoord2f(1.0f, 1.0f); glVertex3f( 1.0f, 1.0f, -1.0f); // 纹理和四边形的右上
glTexCoord2f(0.0f, 1.0f); glVertex3f( 1.0f, 1.0f, 1.0f); // 纹理和四边形的左上
glTexCoord2f(0.0f, 0.0f); glVertex3f( 1.0f, -1.0f, 1.0f); // 纹理和四边形的左下

// 左面
glTexCoord2f(0.0f, 0.0f); glVertex3f(-1.0f, -1.0f, -1.0f); // 纹理和四边形的左下
glTexCoord2f(1.0f, 0.0f); glVertex3f(-1.0f, -1.0f, 1.0f); // 纹理和四边形的右下
glTexCoord2f(1.0f, 1.0f); glVertex3f(-1.0f, 1.0f, 1.0f); // 纹理和四边形的右上
glTexCoord2f(0.0f, 1.0f); glVertex3f(-1.0f, 1.0f, -1.0f); // 纹理和四边形的左上
glEnd();



void MyGLWidget::timerEvent(QTimerEvent *event)

//现在增加 xrot , yrot 和 zrot 的值。尝试变化每次各变量的改变值来调节立方体的旋转速度,或改变+/-号来调节立方体的旋转方向。
mXRotate += 0.3f; // X 轴旋转
mYRotate += 0.2f; // Y 轴旋转
mZRotate += 0.4f; // Z 轴旋转

updateGL();

QGLWidget::timerEvent(event);


void MyGLWidget::keyPressEvent(QKeyEvent *event)

switch (event->key())
case Qt::Key_F2:

mFullScreen = !mFullScreen;
if(mFullScreen)
showFullScreen();

else
showNormal();

updateGL();
break;

case Qt::Key_Escape:

qApp->exit();
break;




#include "myglwidget.h"
#include <QApplication>

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

QApplication a(argc, argv);
MyGLWidget w;
w.show();

return a.exec();

————————————————
版权声
参考技术A #include void display() glClear(GL_COLOR_BUFFER_BIT); glMatrixMode(GL_MODELVIEW); glLoadIdentity(); gluLookAt(1.0,1.0,1.0,0.0,0.0,0.0,0.0,1.0,0.0); glutWireCube(0.5); glutSwapBuffers(); void reshape(int w,int h) glViewport(0,0,w,h); glMatrixMode(GL_PROJECTION); glLoadIdentity(); glOrtho(-4.0,4.0,-4.0,4.0,-4.0,4.0); void init() glClearColor(1.0,1.0,1.0,1.0); glColor3f(0.0,0.0,0.0); int main(int argc,char** argv) glutInit(&argc,argv); glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB); glutInitWindowSize(500,500); glutInitWindowPosition(0,0); glutCreateWindow("cube"); glutReshapeFunc(reshape); glutDisplayFunc(display); init(); glutMainLoop();

当涉及旋转时,将鼠标坐标转换为 OpenGL 中的模型坐标

【中文标题】当涉及旋转时,将鼠标坐标转换为 OpenGL 中的模型坐标【英文标题】:Translating mouse coordinates to model coordinates in OpenGL when rotations are involved 【发布时间】:2014-11-07 13:56:01 【问题描述】:

在 Qt 论坛中我找到了this question 并激发了我的好奇心。

我在 Qt 中找到了一个非常简单的示例来显示一个立方体,并修改了立方体逻辑以创建一个边长为 1 个单位的立方体。

然后我尝试点击模型并显示我点击区域的坐标。

当不涉及轮换时,似乎采摘工作正常。但!如果我取消注释 paintGL 中的旋转(或其中之一),我最终会得到“错误”的值。

例如:

没有旋转,几乎点击了立方体的最左边框:gluUnProject 方法说我点击了点 -0.49075, 0.234, 0.5 ,这似乎没问题。

启用旋转并几乎单击立方体的最左侧边框:我收到 -0.501456, 0.157555, -0.482942 点,这似乎是错误的。 x 坐标超出了 -0.5, 0.5 的范围。

我觉得坐标变换没问题。我一直在通过谷歌进行研究,人们总是使用相同的代码。而且,像素的颜色信息和我点击的脸的颜色相匹配。

那么,谁能告诉我为什么在涉及旋转时我得到错误的坐标?我认为我在一些基本的 3D 理解方面失败了,但我无法意识到它在哪里。

代码如下:

ma​​in.cpp:

#include <QApplication>
#include "GLCube.h"

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

    QApplication a(argc, argv);

    GLCube w;
    w.resize(800,600);
    w.show();

    return a.exec();

GLCube.h

#ifndef GLCUBE_H
#define GLCUBE_H

#include <QtOpenGL>
#include <QGLWidget>

class GLCube : public QGLWidget
  Q_OBJECT // must include this if you use Qt signals/slots
public:
    GLCube(QWidget *parent = NULL)
        : QGLWidget(parent) 
    
protected:
    // Set up the rendering context, define display lists etc.:
   void initializeGL();
   // draw the scene:
   void paintGL();
   // setup viewport, projection etc.:
   void resizeGL (int width, int height);
   virtual void mousePressEvent(QMouseEvent *pme);
;

#endif

GLCube.cpp:

#include "GLCube.h"

#include <cmath>
#include <iostream>
#include <iomanip>

#include "GL/glu.h"

namespace 
    float ver[8][3] =
    
         0.5, -0.5, 0.5 ,
         -0.5, -0.5, 0.5 ,
         -0.5, -0.5, -0.5 ,
         0.5, -0.5, -0.5 ,
         0.5, 0.5, 0.5 ,
         -0.5, 0.5, 0.5 ,
         -0.5, 0.5, -0.5 ,
         +0.5, 0.5, -0.5 
    ;
    GLfloat color[8][4] =
    
        0.0,0.0,0.0, 1.0,
        1.0,0.0,0.0, 1.0 ,
        1.0,1.0,0.0, 1.0 ,
        0.0,1.0,0.0, 1.0 ,
        0.0,0.0,1.0, 1.0 ,
        1.0,0.0,1.0, 1.0 ,
        1.0,1.0,1.0, 1.0 ,
        0.0,1.0,1.0, 1.0 ,
    ;

    void quad(int a,int b,int c,int d, int col)
    
        glPointSize( 5 );
        glBegin(GL_POINTS);
            glColor4fv(color[1]);
            glVertex3fv(ver[a]);

            glColor4fv(color[2]);
            glVertex3fv(ver[b]);

            glColor4fv(color[3]);
            glVertex3fv(ver[c]);

            glColor4fv(color[4]);
            glVertex3fv(ver[d]);
        glEnd();

        glBegin(GL_LINES);
            glColor4fv(color[1]);
            glVertex3fv(ver[a]);
            glVertex3fv(ver[b]);

            glColor4fv(color[1]);
            glVertex3fv(ver[b]);
            glVertex3fv(ver[c]);

            glColor4fv(color[1]);
            glVertex3fv(ver[c]);
            glVertex3fv(ver[d]);

            glColor4fv(color[1]);
            glVertex3fv(ver[d]);
            glVertex3fv(ver[a]);
        glEnd();

        glBegin(GL_QUADS);
        glColor4fv(/*color[a]*/ color[col] );
        glVertex3fv(ver[a]);

    //    glColor3fv(color[b]);
        glVertex3fv(ver[b]);

    //    glColor3fv(color[c]);
        glVertex3fv(ver[c]);

    //    glColor3fv(color[d]);
        glVertex3fv(ver[d]);
        glEnd();
    

    void colorcube()
    
//        glPolygonMode(GL_FRONT_AND_BACK,GL_LINE);
        quad( 3, 2, 1, 0, 1 ); // bottom
        quad( 7, 6, 5, 4, 2); // top
        quad( 6, 2, 1, 5, 3 ); // front
        quad( 7, 3, 0, 4, 5 ); // back
        quad( 7, 6, 2, 3, 6 ); // left
        quad( 4, 5, 1, 0, 7); // right
    

/*
 * Sets up the OpenGL rendering context, defines display lists, etc.
 * Gets called once before the first time resizeGL() or paintGL() is called.
 */
void GLCube::initializeGL()
    //activate the depth buffer
    glEnable(GL_DEPTH_TEST);
    qglClearColor(Qt::black);
    glEnable(GL_CULL_FACE);



/*
 *  Sets up the OpenGL viewport, projection, etc. Gets called whenever the widget has been resized
 *  (and also when it is shown for the first time because all newly created widgets get a resize event automatically).
 */
void GLCube::resizeGL (int width, int height)
    glViewport( 0, 0, (GLint)width, (GLint)height );
    /* create viewing cone with near and far clipping planes */
    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    glFrustum( -1.0, 1.0, -1.0, 1.0, 15.0, 30.0);

    glMatrixMode( GL_MODELVIEW );


/*
 * Renders the OpenGL scene. Gets called whenever the widget needs to be updated.
 */
void GLCube::paintGL()

    //delete color and depth buffer
    glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);

    glMatrixMode(GL_MODELVIEW);
        glLoadIdentity();
        glTranslatef(0.0f,0.0f,-20.0f); //move along z-axis
        glRotatef(30.0,0.0,1.0,0.0); //rotate 30 degress around y-axis
        glRotatef(15.0,1.0,0.0,0.0); //rotate 15 degress around x-axis

    colorcube();
//    originalcube();


void GLCube::mousePressEvent(QMouseEvent *pme) 
    GLint viewport[4];
    GLdouble modelview[16];
    GLdouble projection[16];
    glGetDoublev( GL_MODELVIEW_MATRIX, modelview );
    glGetDoublev( GL_PROJECTION_MATRIX, projection );
    glGetIntegerv( GL_VIEWPORT, viewport );

    const int x = pme->x();
    const int y = viewport[3] - pme->y();

    qDebug() << "HERE: " << x << y;

    GLfloat color[4];
    glReadPixels( x, y, 1, 1, GL_RGBA, GL_FLOAT, color);
    GLenum error = glGetError();
    std::cout << "RETRIEVED COLOR:" << color[0] << ", " << color[1] << ", " << color[2] << ", " << color[3] << std::endl;
    printf( "\tERROR: %s (Code: %u)\n", gluErrorString(error), error );
    if(GL_NO_ERROR != error) throw;

    GLdouble depthScale;
    glGetDoublev( GL_DEPTH_SCALE, &depthScale );
    std::cout << "DEPTH SCALE: " << depthScale << std::endl;
    GLfloat z;
    glReadPixels( x, y, 1, 1, GL_DEPTH_COMPONENT, GL_FLOAT, &z );
    error = glGetError();
    std::cout << "X: " << x << ", Y: " << y  << ", RETRIEVED Z: " << z << std::endl;
    printf( "\tERROR: %s (Code: %u)\n", gluErrorString(error), error );
    if(GL_NO_ERROR != error) throw;
    std::cout << std::endl << std::endl;

    GLdouble posX, posY, posZ;
    GLint result;
    result = gluUnProject( x, y, z, modelview, projection, viewport, &posX, &posY, &posZ);
    error = glGetError();
    std::cout << "3D point with POS: " << posX << " " << posY << " " << posZ << std::endl;
    printf( "\tERROR: %s (Code: %u)\n", gluErrorString(error), error );
    std::cout << "\tglUnProject: " << (( GL_FALSE == result ) ? "FALSE" : "TRUE") << std::endl;
    if(GL_NO_ERROR != error) throw;

注意:

我在 Windows 8.1 64 位、Qt 4.8 和 MinGW 中运行它。

另外,glReadPixelsgluUnProject 都可以正常退出(错误代码 = GL_NO_ERROR

并且glut 不可用。仅提供 OpenGLQtOpenGL 和/或 glu 提供的内容。

【问题讨论】:

【参考方案1】:

这并没有错,您正在读取深度缓冲区以计算用于反向投影的窗口空间 Z 值。

问题在于深度缓冲区中可用的精度有限,这会带来一些不准确。实际上,您不能期望未投影值的范围是完美的 [-0.5,0.5]。您将不得不在此处引入一个小 epsilon,因此您的有效范围将类似于 [-0.5015,0.5015]。

您可以通过提高深度缓冲区的精度和/或减小近端和远端剪辑平面之间的范围来减轻影响。默认情况下,深度缓冲区通常为 24 位定点,但 32 位定点或浮点深度缓冲区可能会稍微改善您的情况。但是,您永远不会完全消除此问题。

【讨论】:

哦!谢谢!我从没想过不准确。我会试试你的建议! 另外,我注意到当单击模型的边缘时,我得到了合理的值(使用 epsilon,正如您所解释的那样)。但是,如果我在边缘附近点击,但在外面,在黑色的背景中,我会得到类似4.66933, -1.30734, -8.8131 的东西。有没有办法“禁用”它,还是我必须检查返回的点,看看它是否有合理的界限? @AdriC.S.:发生的情况是您正在读取深度缓冲区的已清除部分。默认清除深度为 1.0。由于您不太可能点击深度正好等于 1.0 的东西(这将是位于远剪切平面上的东西正好),您可以可能只是假设如果您回读 1.0 的深度,则光标下没有任何内容。 我明白了。非常感谢!!

以上是关于在QT环境下用OpenGL绘制一个边长为5的立方体,并为立方体贴上自定义纹理。写出实现该功能的具体的主要内容,如果未能解决你的问题,请参考以下文章

几个opengl立方体绘制案例

基于Qt的OpenGL可编程管线学习- 绘制一个三角形

OpenGL ES绘制魔方

在opengl es android中的随机位置绘制多个立方体

在 OpenGL 中绘制一个实心立方体

游戏环境中的 OpenGL VBO/DisplayList