1

我想使用 QGLWidget 显示图像,它没有以正确的方式显示,问题之一是原始坐标位于小部件的左下角。我想知道如何使原始坐标位于左上角并翻转 y 轴。

在此处输入图像描述

这是我的代码:

标题

#ifndef _GLImageDisplay_H_
#define _GLImageDisplay_H_

#include "stdafx.h"

class GLImageDisplay : public QGLWidget
{
    Q_OBJECT

public:
    GLImageDisplay(QWidget *parent = 0);

    void DisplayImage(QString img);

protected:
    void initializeGL();
    void resizeGL(int w, int h);
    void paintGL();

private:
    QImage svgImage;
    GLubyte* gluImage;
};

#endif

cpp

#include "stdafx.h"
#include "GLImageDisplay.h"

GLImageDisplay::GLImageDisplay(QWidget *parent) : QGLWidget (parent) 
{
}

void GLImageDisplay::DisplayImage(QString img)
{
    svgImage.load(img);
    resize(svgImage.size());

    gluImage = new GLubyte[svgImage.height() * svgImage.width() * 3];
    for (int a = 0; a < svgImage.width(); ++a)  
    {
        for (int b = 0; b < svgImage.height(); ++b) 
        {
            QColor color = svgImage.pixel(a, b);
            gluImage[3 * (a + b * svgImage.width()) + 0] = (GLubyte) color.red();
            gluImage[3 * (a + b * svgImage.width()) + 1] = (GLubyte) color.green();
            gluImage[3 * (a + b * svgImage.width()) + 2] = (GLubyte) color.blue();
        }
    }

    this->setMinimumWidth(svgImage.width());
    this->setMinimumHeight(svgImage.height());
}

void GLImageDisplay::initializeGL() 
{
    glClearColor(0.5, 0.5, 0.5, 1.0);
    glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
}

void GLImageDisplay::resizeGL(int w, int h) 
{
    glViewport(0, 0, svgImage.width(), svgImage.height());

    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    glOrtho(0, svgImage.width(), 0, svgImage.height(), 0, 1);   
    glMatrixMode(GL_MODELVIEW);
    glLoadIdentity();
}

void GLImageDisplay::paintGL() 
{
    glClear(GL_COLOR_BUFFER_BIT);
    glRasterPos2i(0, 0);
    glDrawPixels(svgImage.width(), svgImage.height(), GL_RGB, GL_UNSIGNED_BYTE, gluImage);
}
4

2 回答 2

3

OpenGL 坐标从底部开始。要解决此问题,您可以在投影矩阵的 y 轴上进行 -1 缩放。偏移量是相关的。

要解决此问题,请在通话后更改您的通话glOrtho或应用缩放 + 平移。

顺便提一句。您也可以在真正需要 GL 的任何地方使用QPainter和使用。将已经使用 GL 本身并且性能非常好。beginNativePainting()QPainter

glDrawPixels是将图像绘制到屏幕上的一种非常低效的方式。您应该将其加载到纹理中并用它绘制一个四边形。(同样,QPainter也可以更轻松地为您做到这一点。)

于 2013-07-19T23:38:57.843 回答
2

谢谢ypnos

最后我翻转投影矩阵 gluOrtho2D(0, width, height, 0); 并翻转文本坐标。

这是我的代码:

#include "stdafx.h"
#include "GLImageDisplay.h"

GLImageDisplay::GLImageDisplay(QWidget *parent) : QGLWidget (parent) 
{
}

void GLImageDisplay::DisplayImage(QString img)
{
    myImage.load(img);

    // calculating power-of-two (pow) size
    int xpow = (int) std::pow(2.0, std::ceil(  std::log10((double)myImage.width())/std::log10(2.0)  )   );
    int ypow = (int) std::pow(2.0, std::ceil(  std::log10((double)myImage.height())/std::log10(2.0)  )   );

    // the texture should be square too
    xpow = std::max(xpow, ypow);
    ypow = xpow;

    // shrink if the size is too big
    if(xpow > 1024) 
    {
        xpow = 1024;
        ypow = 1024;
    }

    // transform the image to square pow size
    scaledImage = myImage.scaled(xpow, ypow, Qt::IgnoreAspectRatio);
    glImage = QGLWidget::convertToGLFormat(scaledImage);

    this->setMinimumWidth(myImage.width());
    this->setMinimumHeight(myImage.height());

    glEnable(GL_TEXTURE_2D);
    glGenTextures(1, &imageID);
    glBindTexture( GL_TEXTURE_2D, imageID );
    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, scaledImage.width(), scaledImage.height(), 0, GL_RGBA, GL_UNSIGNED_BYTE, glImage.bits());
    glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR);
    glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR);
    glDisable(GL_TEXTURE_2D);
}

void GLImageDisplay::initializeGL() 
{
    glClearColor(0.5, 0.5, 0.5, 1.0);
}

void GLImageDisplay::resizeGL(int width, int height) 
{   
    glViewport(0, 0, width, height);
    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    gluOrtho2D(0, width, height, 0);    // flip the y axis
    glMatrixMode(GL_MODELVIEW);
    glLoadIdentity();
}

void GLImageDisplay::paintGL() 
{
    int width = myImage.width();
    int height = myImage.height();

    glClear(GL_COLOR_BUFFER_BIT);

    glColor3f(1,0,0);
    glBegin(GL_POLYGON);
    glVertex2f(10,10);
    glVertex2f(10,600);
    glVertex2f(300,10);
    glEnd();

    glEnable(GL_TEXTURE_2D);
    glColor3f(1,1,1);
    glBindTexture( GL_TEXTURE_2D, imageID );
    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, glImage.width(), glImage.height(), 0, GL_RGBA, GL_UNSIGNED_BYTE, glImage.bits());

    glBegin(GL_QUADS);

    // text coord is flipped
    glTexCoord2d(0,1); glVertex3d(0,     0,      0);
    glTexCoord2d(1,1); glVertex3d(width, 0,      0);
    glTexCoord2d(1,0); glVertex3d(width, height, 0);
    glTexCoord2d(0,0); glVertex3d(0,     height, 0);

    glEnd();
    glDisable(GL_TEXTURE_2D);
}

但是当我尝试显示小部件底部被切割并显示黑色区域的大图像时,我遇到了另一个问题。似乎小部件最多只能呈现我的 LCD 屏幕的高度(?)我想知道 QGLWidget 不能轻易放入 QScrollArea (?)。这是一个不同的问题。

在此处输入图像描述

于 2013-07-20T10:07:18.310 回答