LearnOpenGL 网址:
https://learnopengl-cn.github.io/
LearnOpenGL : GLAD(提供opengl 库函数)+ GLFW(界面窗口)
以“立方体贴图”为例,移植到QT 平台,用GLEW 提供opengl 函数库
LearnOpenGL代码:
https://learnopengl-cn.github.io/04%20Advanced%20OpenGL/06%20Cubemaps/
https://learnopengl.com/code_viewer_gh.php?code=src/4.advanced_opengl/6.2.cubemaps_environment_mapping/cubemaps_environment_mapping.cpp
环境: Qt5.12.7
1、配置glew库lib,pro文件中添加如下:
LIBS += -L$$quote("D:\Works\code\opengl\QGLDemo\openGL\libs") -lglew32
2、SkyboxForm 继承QOpenGLExtraFunctions,便于直接试用opengl 函数,代码风格和learnopengl 一致
class SkyboxForm :public QOpenGLWidget ,public QOpenGLExtraFunctions
{
}
代码如下(示例):
GLenum err = glewInit();
if (err != GLEW_OK) {
std::cerr << "GLEW initialization failed" << std::endl;
fprintf(stderr, "Error: %s\n", glewGetErrorString(err));
return;
}
//初始化opengl 函数
initializeOpenGLFunctions();
glEnable(GL_DEPTH_TEST);
// ------------------------------------------------------------------
float cubeVertices[] = {
// positions // normals
-0.5f, -0.5f, -0.5f, 0.0f, 0.0f, -1.0f,
0.5f, -0.5f, -0.5f, 0.0f, 0.0f, -1.0f,
0.5f, 0.5f, -0.5f, 0.0f, 0.0f, -1.0f,
0.5f, 0.5f, -0.5f, 0.0f, 0.0f, -1.0f,
-0.5f, 0.5f, -0.5f, 0.0f, 0.0f, -1.0f,
-0.5f, -0.5f, -0.5f, 0.0f, 0.0f, -1.0f,
-0.5f, -0.5f, 0.5f, 0.0f, 0.0f, 1.0f,
0.5f, -0.5f, 0.5f, 0.0f, 0.0f, 1.0f,
0.5f, 0.5f, 0.5f, 0.0f, 0.0f, 1.0f,
0.5f, 0.5f, 0.5f, 0.0f, 0.0f, 1.0f,
-0.5f, 0.5f, 0.5f, 0.0f, 0.0f, 1.0f,
-0.5f, -0.5f, 0.5f, 0.0f, 0.0f, 1.0f,
-0.5f, 0.5f, 0.5f, -1.0f, 0.0f, 0.0f,
-0.5f, 0.5f, -0.5f, -1.0f, 0.0f, 0.0f,
-0.5f, -0.5f, -0.5f, -1.0f, 0.0f, 0.0f,
-0.5f, -0.5f, -0.5f, -1.0f, 0.0f, 0.0f,
-0.5f, -0.5f, 0.5f, -1.0f, 0.0f, 0.0f,
-0.5f, 0.5f, 0.5f, -1.0f, 0.0f, 0.0f,
0.5f, 0.5f, 0.5f, 1.0f, 0.0f, 0.0f,
0.5f, 0.5f, -0.5f, 1.0f, 0.0f, 0.0f,
0.5f, -0.5f, -0.5f, 1.0f, 0.0f, 0.0f,
0.5f, -0.5f, -0.5f, 1.0f, 0.0f, 0.0f,
0.5f, -0.5f, 0.5f, 1.0f, 0.0f, 0.0f,
0.5f, 0.5f, 0.5f, 1.0f, 0.0f, 0.0f,
-0.5f, -0.5f, -0.5f, 0.0f, -1.0f, 0.0f,
0.5f, -0.5f, -0.5f, 0.0f, -1.0f, 0.0f,
0.5f, -0.5f, 0.5f, 0.0f, -1.0f, 0.0f,
0.5f, -0.5f, 0.5f, 0.0f, -1.0f, 0.0f,
-0.5f, -0.5f, 0.5f, 0.0f, -1.0f, 0.0f,
-0.5f, -0.5f, -0.5f, 0.0f, -1.0f, 0.0f,
-0.5f, 0.5f, -0.5f, 0.0f, 1.0f, 0.0f,
0.5f, 0.5f, -0.5f, 0.0f, 1.0f, 0.0f,
0.5f, 0.5f, 0.5f, 0.0f, 1.0f, 0.0f,
0.5f, 0.5f, 0.5f, 0.0f, 1.0f, 0.0f,
-0.5f, 0.5f, 0.5f, 0.0f, 1.0f, 0.0f,
-0.5f, 0.5f, -0.5f, 0.0f, 1.0f, 0.0f
};
float skyboxVertices[] = {
// positions
-1.0f, 1.0f, -1.0f,
-1.0f, -1.0f, -1.0f,
1.0f, -1.0f, -1.0f,
1.0f, -1.0f, -1.0f,
1.0f, 1.0f, -1.0f,
-1.0f, 1.0f, -1.0f,
-1.0f, -1.0f, 1.0f,
-1.0f, -1.0f, -1.0f,
-1.0f, 1.0f, -1.0f,
-1.0f, 1.0f, -1.0f,
-1.0f, 1.0f, 1.0f,
-1.0f, -1.0f, 1.0f,
1.0f, -1.0f, -1.0f,
1.0f, -1.0f, 1.0f,
1.0f, 1.0f, 1.0f,
1.0f, 1.0f, 1.0f,
1.0f, 1.0f, -1.0f,
1.0f, -1.0f, -1.0f,
-1.0f, -1.0f, 1.0f,
-1.0f, 1.0f, 1.0f,
1.0f, 1.0f, 1.0f,
1.0f, 1.0f, 1.0f,
1.0f, -1.0f, 1.0f,
-1.0f, -1.0f, 1.0f,
-1.0f, 1.0f, -1.0f,
1.0f, 1.0f, -1.0f,
1.0f, 1.0f, 1.0f,
1.0f, 1.0f, 1.0f,
-1.0f, 1.0f, 1.0f,
-1.0f, 1.0f, -1.0f,
-1.0f, -1.0f, -1.0f,
-1.0f, -1.0f, 1.0f,
1.0f, -1.0f, -1.0f,
1.0f, -1.0f, -1.0f,
-1.0f, -1.0f, 1.0f,
1.0f, -1.0f, 1.0f
};
glGenVertexArrays(1,&VAO);
glGenBuffers(1,&VBO);
glBindVertexArray(VAO);
glBindBuffer(GL_ARRAY_BUFFER,VBO);
glBufferData(GL_ARRAY_BUFFER,sizeof (cubeVertices),cubeVertices,GL_STATIC_DRAW);
// 坐标数据
glEnableVertexAttribArray(0);
glVertexAttribPointer(0,3,GL_FLOAT,GL_FALSE,6 * sizeof(float), (void*)0);
//法线数据
glEnableVertexAttribArray(1);
glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(float), (void*)(3 * sizeof(float)));
// skybox VAO
glGenVertexArrays(1, &skyboxVAO);
glGenBuffers(1, &skyboxVBO);
glBindVertexArray(skyboxVAO);
glBindBuffer(GL_ARRAY_BUFFER, skyboxVBO);
glBufferData(GL_ARRAY_BUFFER, sizeof(skyboxVertices), &skyboxVertices, GL_STATIC_DRAW);
glEnableVertexAttribArray(0);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void*)0);
// cubeTexture = loadTexture(std::string("./skybox/container.jpg").c_str());
std::vector<std::string> vCubeFaces = {
"./skybox/right.jpg",
"./skybox/left.jpg",
"./skybox/top.jpg",
"./skybox/bottom.jpg",
"./skybox/front.jpg",
"./skybox/back.jpg"};
cubemapTexture = loadCubemap(vCubeFaces);
shader = new Shader("./skybox/cubemaps_vs.txt", "./skybox/cubemaps_fs.txt");
skyboxShader = new Shader("./skybox/skybox_vs.txt", "./skybox/skybox_fs.txt");
camera = new Camera(glm::vec3(0.0f, 0.0f, 3.0f));
shader->use();
shader->setInt("skybox", 0);
skyboxShader->use();
skyboxShader->setInt("skybox", 0);
代码如下(示例):
glClearColor(0.1f,0.1f,0.1f,0.1f);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
shader->use();
glm::mat4 model = glm::mat4(1.0f);
glm::mat4 view =camera->GetViewMatrix();
glm::mat4 projection = glm::perspective(glm::radians(camera->Zoom),(float)width()/height(),0.1f,100.0f);
shader->setMat4("model",model);
shader->setMat4("view",view);
shader->setMat4("projection",projection);
shader->setVec3("cameraPos",camera->Position);
//cube
glBindVertexArray(VAO);
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_CUBE_MAP,cubemapTexture);
glDrawArrays(GL_TRIANGLES,0,36);
glBindVertexArray(0);
//draw skybox
glDepthFunc(GL_LEQUAL);
skyboxShader->use();
view = glm::mat4(glm::mat3(camera->GetViewMatrix()));
skyboxShader->setMat4("view",view);
skyboxShader->setMat4("projection",projection);
glBindVertexArray(skyboxVAO);
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_CUBE_MAP, cubemapTexture);
glDrawArrays(GL_TRIANGLES, 0, 36);
glBindVertexArray(0);
glDepthFunc(GL_LESS); // set depth function back to default
代码如下(示例):
glViewport(0,0,w,h);
代码如下(示例):
static bool firstMouse = true;
static float lastX = (float)width() / 2.0;
static float lastY = (float)height() / 2.0;
float xpos = event->x();
float ypos = event->y();
if (firstMouse)
{
lastX = xpos;
lastY = ypos;
firstMouse = false;
}
float xoffset = xpos - lastX;
float yoffset = lastY - ypos; // reversed since y-coordinates go from bottom to top
lastX = xpos;
lastY = ypos;
camera->ProcessMouseMovement(xoffset, yoffset);
update();
event->ignore();
代码如下(示例):
QPoint numDegrees = event->angleDelta() / 20;
camera->ProcessMouseScroll(numDegrees.ry());
update();
event->ignore();
代码如下(示例):
class SkyboxForm :public QOpenGLWidget ,public QOpenGLExtraFunctions
{
Q_OBJECT
public:
explicit SkyboxForm(QWidget *parent = nullptr);
~SkyboxForm();
void paintGL() override;
void initializeGL() override;
void resizeGL(int w, int h) override;
unsigned int loadCubemap(std::vector<std::string> faces);
unsigned int loadTexture(char const * path);
void mouseMoveEvent(QMouseEvent *event);
void wheelEvent(QWheelEvent *event);
private:
Ui::SkyboxForm *ui;
unsigned int VAO ,VBO;
unsigned int skyboxVAO, skyboxVBO;
unsigned int cubemapTexture;
unsigned int cubeTexture;
Shader *shader;
Shader *skyboxShader;
Camera *camera;
};
Shader 、Camera 实现参照learnopengl ,
只用stb_image.h读取图像的时候在 #include 前 #define STB_IMAGE_IMPLEMENTATION,代码如下:
#define STB_IMAGE_IMPLEMENTATION
#include"stb_image.h"
运行效果: