首先说明利用qt内置qopenglwidget窗口在64位下会出现显卡的一个dll报错,换成32位就没事,因此探索出下面的这种配置方式。
显卡DLL报错可以解决,在自己电脑上将opengl渲染改成独显,总之支持就行。
采用Qwindow类以及qt封装好的opengl上下文,渲染到窗口上,然后将这个窗口作为子窗口显示到mainwindow上。
渲染类://来自于网上一个OpenGL框架,但是其中的qt自带的shader类需要使用Qt的矩阵结构没法用glm了,我这里就自己写了个。
// "myrenderer.h"
#pragma once
class IconRender : public QObject
{
Q_OBJECT
public:
IconRender(QSurfaceFormat & format, IconRender * share = 0, QScreen * screen = 0);
QSurfaceFormat format() const { return m_format; }
void changequad( QUADS x);
//缓存对象
QOpenGLFunctions_3_3_Compatibility * m_fun;
public slots:
void Render(QSurface * surface, const QColor & color, const QSize & size);
private:
unsigned int VBO2, VAO2;
void Initialize();
void Init_QUAD_VBO();
void Draw_QUAD();
void CompileShader(unsigned int *id, const char* vertexPath, const char* fragmentPath, const char* geometryPath = NULL);
private:
//着色器程序ID
unsigned int ID;
bool m_bInitialized;
QSurfaceFormat m_format;
QOpenGLContext * m_context;
QVector<QVector3D> m_quad_vertices;
GLuint m_quad_vbo;
GLuint m_MODEL_MATRIX_LOC;
GLuint m_VIEW_MATRIX_LOC;
GLuint m_PROJECTION_MATRIX_LOC;
QMatrix4x4 m_model_matrix;
QMatrix4x4 m_view_matrix;
QMatrix4x4 m_projection_matrix;
QSize m_viewSize;
};
myRenderer.cpp//vbo绑定记得改
#include<IconRender.h>
#define W 180
#define H 150
IconRender::IconRender(QSurfaceFormat &format, IconRender *share, QScreen *screen)
:m_bInitialized(false)
, m_format(format)
, m_context(0)
, m_fun(0)
{
m_context = new QOpenGLContext(this);
if (screen)
{
m_context->setScreen(screen);
}
m_context->setFormat(format);
if (share)
{
m_context->setShareContext(share->m_context);
}
m_context->create();
}
void IconRender::Render(QSurface * surface, const QColor & color, const QSize & viewSize)
{
m_viewSize = surface->size();
if (m_context == NULL)
{
return;
}
if (m_context->makeCurrent(surface) != true)
{
return;
}
if (m_bInitialized == false)
{
m_bInitialized = true;
Initialize();
}
//resizeopengl
_matProj = glm::perspective(glm::radians(45.0f), float(W) / float(H), 0.1f, 1000.0f);//使用glm数学库 根据公式计算得到投影矩阵 这公式可以推倒出来
m_fun->glViewport(0, 0, surface->size().width(), surface->size().height());
Draw_QUAD();
m_context->swapBuffers(surface);
}
void IconRender::changequad( QUADS x)
{
m_fun->glBindBuffer(GL_ARRAY_BUFFER, VBO2);
m_fun->glBufferData(GL_ARRAY_BUFFER, x.g_cubeVertices.size() * sizeof(float) * 6, &(x.g_cubeVertices[0].x), GL_DYNAMIC_DRAW);
}
void IconRender::Initialize()
{
m_fun = m_context->versionFunctions<QOpenGLFunctions_3_3_Compatibility>();
m_fun->initializeOpenGLFunctions();//初始化函数
Init_QUAD_VBO();
}
void IconRender::Init_QUAD_VBO()
{
m_fun->glEnable(GL_DEPTH_TEST);
CompileShader(&ID, "texture.vs", "texture.fs");
m_fun->glGenVertexArrays(1, &VAO2);
m_fun->glGenBuffers(1, &VBO2);
m_fun->glBindVertexArray(VAO2);
m_fun->glBindBuffer(GL_ARRAY_BUFFER, VBO2);
m_fun->glBufferData(GL_ARRAY_BUFFER, icon.g_cubeVertices.size() * sizeof(float) * 6, &(icon.g_cubeVertices[0].x), GL_DYNAMIC_DRAW);
// 位置属性
m_fun->glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(float), (void*)0);
m_fun->glEnableVertexAttribArray(0);
// 颜色属性
m_fun->glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(float), (void*)(3 * sizeof(float)));
m_fun->glEnableVertexAttribArray(1);
//解除绑定VBO2
m_fun->glBindBuffer(GL_ARRAY_BUFFER, 0);
//解除绑定VAO2
m_fun->glBindVertexArray(0);
}
void IconRender::Draw_QUAD()
{
m_fun->glEnable(GL_DEPTH_TEST);
m_fun->glEnableClientState(GL_VERTEX_ARRAY);
m_fun->glEnableClientState(GL_TEXTURE_COORD_ARRAY);
m_fun->glClearColor(1, 1, 1, 1.0f);
m_fun->glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);
//激活着色器
m_fun->glUseProgram(ID);
glm::vec3 _iconeye(60, 60, 60);
glm::vec3 _iconlookAt(-1, -1, -1);
targetPo = _iconeye + _iconlookAt;
_matView = glm::lookAt(_iconeye, targetPo, _up); //使用glm数学库 根据公式计算得到视图矩阵 这公式可以推倒出来
glm::mat4 model = glm::mat4(1.0);
glm::mat4 trans = glm::mat4(1.0f);//创建单位矩阵
trans = glm::translate(trans, glm::vec3(-50.0, -50.0, -50.0));//先平移后旋转再缩放
trans = _matView * trans;
GLuint Uniform1 = m_fun->glGetUniformLocation(ID, "model");
GLuint Uniform2 = m_fun->glGetUniformLocation(ID, "view");
GLuint Uniform3 = m_fun->glGetUniformLocation(ID, "project");
m_fun->glUniformMatrix4fv(Uniform1, 1, GL_FALSE, glm::value_ptr(model));
m_fun->glUniformMatrix4fv(Uniform2, 1, GL_FALSE, glm::value_ptr(trans));
m_fun->glUniformMatrix4fv(Uniform3, 1, GL_FALSE, glm::value_ptr(_matProj));
m_fun->glMatrixMode(GL_TEXTURE);
m_fun->glLoadIdentity();
//绑定顶点缓存对象
m_fun->glBindVertexArray(VAO2);
//开始绘制
m_fun->glUseProgram(ID);
m_fun->glDrawArrays(GL_QUADS, 0, 24);
//解除绑定
m_fun->glBindVertexArray(0);
}
//加载着色器程序
void IconRender::CompileShader(unsigned int *id, const char* vertexPath, const char* fragmentPath, const char* geometryPath)
{
std::string vertexCode;
std::string fragmentCode;
std::string geometryCode;
std::ifstream vShaderFile;
std::ifstream fShaderFile;
std::ifstream gShaderFile;
// 打开文件
vShaderFile.open(vertexPath);
fShaderFile.open(fragmentPath);
std::stringstream vShaderStream, fShaderStream;
// 读取文件的缓冲内容到数据流中
vShaderStream << vShaderFile.rdbuf();
fShaderStream << fShaderFile.rdbuf();
// 关闭文件处理器
vShaderFile.close();
fShaderFile.close();
// 转换数据流到string
vertexCode = vShaderStream.str();
fragmentCode = fShaderStream.str();
if (geometryPath != NULL)
{
gShaderFile.open(geometryPath);
std::stringstream gShaderStream;
gShaderStream << gShaderFile.rdbuf();
gShaderFile.close();
geometryCode = gShaderStream.str();
}
const char* vShaderCode = vertexCode.c_str();
const char* fShaderCode = fragmentCode.c_str();
// 2. 编译着色器
unsigned int vertex, fragment;
int success;
char infoLog[512];
// 顶点着色器
vertex = m_fun->glCreateShader(GL_VERTEX_SHADER);
m_fun->glShaderSource(vertex, 1, &vShaderCode, NULL);
//编译着色器
m_fun->glCompileShader(vertex);
//检测编译时错误
m_fun->glGetShaderiv(vertex, GL_COMPILE_STATUS, &success);
//如果编译错误进入语句
if (!success)
{
//获取错误信息
m_fun->glGetShaderInfoLog(vertex, 512, NULL, infoLog);
//打印错误
std::cout << "ERROR::SHADER::VERTEX::COMPILATION_FAILED\n" << infoLog << std::endl;
}
//片元着色器
fragment = m_fun->glCreateShader(GL_FRAGMENT_SHADER);
m_fun->glShaderSource(fragment, 1, &fShaderCode, NULL);
m_fun->glCompileShader(fragment);
//检测错误
m_fun->glGetShaderiv(fragment, GL_COMPILE_STATUS, &success);
if (!success)
{
//获取错误原因
m_fun->glGetShaderInfoLog(fragment, 512, NULL, infoLog);
//打印
std::cout << "ERROR::SHADER::FRAGMENT::COMPILATION_FAILED\n" << infoLog << std::endl;
}
//几何着色器
unsigned int geometry;
if (geometryPath != nullptr)
{
const char * gShaderCode = geometryCode.c_str();
geometry = m_fun->glCreateShader(GL_GEOMETRY_SHADER);
m_fun->glShaderSource(geometry, 1, &gShaderCode, NULL);
m_fun->glCompileShader(geometry);
}
// 着色器程序
*id = m_fun->glCreateProgram();
m_fun->glAttachShader(*id, vertex);
m_fun->glAttachShader(*id, fragment);
if (geometryPath != nullptr)
m_fun->glAttachShader(*id, geometry);
m_fun->glLinkProgram(*id);
//检测错误
m_fun->glGetProgramiv(*id, GL_LINK_STATUS, &success);
if (!success)
{
//获取错误信息
m_fun->glGetProgramInfoLog(ID, 512, NULL, infoLog);
std::cout << "ERROR::SHADER::PROGRAM::LINKING_FAILED\n" << infoLog << std::endl;
}
// 删除着色器,它们已经链接到我们的程序中了,已经不再需要了
m_fun->glDeleteShader(vertex);
m_fun->glDeleteShader(fragment);
if (geometryPath != nullptr)
m_fun->glDeleteShader(geometry);
}
``//窗口类IconFram。h
#include <QWindow>
#include <QMouseEvent>
#include <QKeyEvent>
class IconFrame : public QWindow
{
Q_OBJECT
public:
IconFrame(const QSharedPointer<IconRender> & renderer);
QSharedPointer<IconRender> m_iconRenderer;
void exposeEvent(QExposeEvent *);
void Render();
protected:
void timerEvent(QTimerEvent *);
signals:
void NeedRender(QSurface * surface, const QColor & color, const QSize & viewSize);
};
//窗口cpp
#include " IconFram.h"
IconFrame::IconFrame(const QSharedPointer<IconRender> & renderer)
:m_iconRenderer(renderer)
{
setSurfaceType(QWindow::OpenGLSurface);
setFormat(renderer->format());
setGeometry(1500,80, 180,150);
connect(this, SIGNAL(NeedRender(QSurface*, QColor, QSize)),
renderer.data(), SLOT(Render(QSurface*, QColor, QSize)));
startTimer(50);
}
void IconFrame::Render()
{
if (isExposed())
emit NeedRender(this, QColor(0.0f, 0.0f, 0.0f, 1.0f), size());
}
void IconFrame::exposeEvent(QExposeEvent *)
{
Render();
}
void IconFrame::timerEvent(QTimerEvent *)
{
Render();
}
main文件加
MainWindow w1;
w1.show(); //qDebug() << "proc 1 window handle:" << w1.winId();
QScreen * screen = QGuiApplication::primaryScreen();
QSurfaceFormat format;
format.setDepthBufferSize(16);
format.setSamples(4);
QSharedPointer<MyRenderer>renderer(new MyRenderer(format, 0, screen));
IconFram w(renderer);
//w1.wp = &w;
WId proc1Window_HWND = WId(w1.winId()); //记下进程1的窗口句柄
//TODO: 创建一个进程1的窗口代理
QWindow* proc1Widow = QWindow::fromWinId(proc1Window_HWND);
//TODO: 告诉w它的本地父窗口是proc1Window_HWND,这步务必要做不然w上的一些控件会出问题,比如qcombobox的下拉框可能会错位
w.setProperty("_q_embedded_native_parent_handle", QVariant(proc1Window_HWND));
iconwindow_1.setProperty("_q_embedded_native_parent_handle", QVariant(proc1Window_HWND))
//TODO: 将进程1的窗口设置为w的父窗口(w嵌入到proc1的窗口中)
w.winId();
w.setParent(proc1Widow);
//w.windowHandle()->setParent(proc1Widow);
w.resize(1500,800);
w.setPosition(0,130);
w.show();