我想使用 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);
}
OpenGL 坐标从底部开始。要解决此问题,您可以在投影矩阵的 y 轴上进行 -1 缩放。偏移量是相关的。
要解决此问题,请将您的呼叫更改为
glOrtho
或在呼叫后立即应用缩放 + 平移。
顺便说一句。您还可以使用
QPainter
并在真正需要 GL 的地方使用 beginNativePainting()
。 QPainter
已经使用 GL 本身并且执行得非常 好。
glDrawPixels
是一种在屏幕上绘制图像的非常低效的方法。您应该将其加载到纹理中并用它绘制一个四边形。 (再次强调,QPainter
也可以为您轻松做到这一点。)
谢谢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 中(?)。但这是另一个问题。
QImage 垂直镜像是为了说明 OpenGL 和 QImage 使用相反的 y 轴方向。修复它的简单方法:
QImage image(":/Resources/imageName.png");
QImage yAxisInvertedImage = image.mirrored();