一、跨平台环境基本配置
1、环境搭建
1)linux OpenGL环境搭建参考:ubuntu18.04 OpenGL开发(显示YUV)_ubuntu opengl-CSDN博客
https://blog.51cto.com/cerana/6433535
2)windows下环境搭建
OpenGL+Visual Studio2022+GLFW+glad详细配置教程_给vs配置glfw和glad-CSDN博客
2、创建cmake
这里测试使用的图形界面使用QT。其中路径后面讲解。
主要有几个注意事项:
1)linux下需要添加
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wno-error=register")
2)windows下需要设置vitual studio
set(LIBRARY_GLFW_PATH "${PROJECT_SOURCE_DIR}/lib-vc2022")
cmake_minimum_required(VERSION 3.5)
SET(TARGET "QTGL")
project(${TARGET} VERSION 0.1 LANGUAGES CXX)
set(CMAKE_INCLUDE_CURRENT_DIR ON)
set(CMAKE_AUTOUIC ON)
set(CMAKE_AUTOMOC ON)
set(CMAKE_AUTORCC ON)
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
if(WIN32)
else()
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wno-error=register")
endif()
set(QTGL_GLAPI_PATH "${PROJECT_SOURCE_DIR}/GLAPI")
set(GLAD_FOLDER_INCLUDE_PATH "${PROJECT_SOURCE_DIR}/glad/include")
set(GLAD_FOLDER_SOURCE_PATH "${PROJECT_SOURCE_DIR}/glad/src")
set(GLM_FOLDER_INCLUDE_PATH "${PROJECT_SOURCE_DIR}/glm")
set(GLFW_FOLDER_INCLUDE_PATH "${QTGL_GLAPI_PATH}/glfw")
if(WIN32)
set(LIBRARY_GLFW_PATH "${PROJECT_SOURCE_DIR}/lib-vc2022")
LINK_DIRECTORIES("${LIBRARY_GLFW_PATH}")
endif()
include_directories(${QTGL_GLAPI_PATH})
include_directories(${GLAD_FOLDER_INCLUDE_PATH})
include_directories(${GLM_FOLDER_INCLUDE_PATH})
include_directories(${GLFW_FOLDER_INCLUDE_PATH})
file(GLOB GLAPI_HEADERS "${QTGL_GLAPI_PATH}/*.h")
source_group("GLAPI/include" FILES ${GLAPI_HEADERS})
file(GLOB GLAPI_SOURCES "${QTGL_GLAPI_PATH}/*.cpp")
source_group("GLAPI/source" FILES ${GLAPI_SOURCES})
file(GLOB_RECURSE GLAD_INCLUDE "${GLAD_FOLDER_INCLUDE_PATH}/*.*")
source_group("glad/include" FILES ${GLAD_INCLUDE})
file(GLOB GLAD_SOURCE "${GLAD_FOLDER_SOURCE_PATH}/*.*")
source_group("glad/src" FILES ${GLAD_SOURCE})
SET(QTUI_PATH "${PROJECT_SOURCE_DIR}/QTUI")
file(GLOB_RECURSE QTUI_FILES "${QTUI_PATH}/*.*")
source_group("QTUI" FILES ${QTUI_FILES})
set(ALL_SOURCES
${GLAPI_HEADERS}
${GLAPI_SOURCES}
${GLAD_INCLUDE}
${GLAD_SOURCE}
${QTUI_FILES}
)
ADD_EXECUTABLE(${TARGET} WIN32 ${ALL_SOURCES})
find_package(QT NAMES Qt6 Qt5 REQUIRED COMPONENTS Widgets)
find_package(Qt${QT_VERSION_MAJOR} REQUIRED COMPONENTS Widgets)
target_link_libraries(${TARGET} PRIVATE Qt${QT_VERSION_MAJOR}::Widgets)
if(WIN32)
target_link_libraries(${TARGET} PRIVATE debug "${LIBRARY_GLFW_PATH}/glfw3.lib" optimized "${LIBRARY_GLFW_PATH}/glfw3.lib")
target_link_libraries(${TARGET} PRIVATE debug "${LIBRARY_GLFW_PATH}/glfw3_mt.lib" optimized "${LIBRARY_GLFW_PATH}/glfw3_mt.lib")
target_link_libraries(${TARGET} PRIVATE debug "${LIBRARY_GLFW_PATH}/glfw3dll.lib" optimized "${LIBRARY_GLFW_PATH}/glfw3dll.lib")
else()
target_link_libraries(${TARGET} PRIVATE glfw3)
target_link_libraries(${TARGET} PRIVATE GL)
target_link_libraries(${TARGET} PRIVATE X11)
target_link_libraries(${TARGET} PRIVATE m)
target_link_libraries(${TARGET} PRIVATE pthread)
target_link_libraries(${TARGET} PRIVATE dl)
endif()
3、第三方库文件
1)glad和glm
glad下载:https://glad.dav1d.de/,下载后得到glad.zip
把glad整个文件夹放置到工程目录下,然后,把src下的glad.c改为glad.cpp。
把glm整个文件夹放置到工程目录下,不需要额外的修改。
2)glfw
glfw下载,Download | GLFW
windows下,需要将编译好的glfw库放置到工程下。如图:
3)整体工程结构如图:
4、QT界面文件QTUI
创建一个QDialog或者QMainWindow,带有.ui文件,可以使用uic指令将其转换为.h文件。
二、OPENGL 简单示例
1、初始化工程
1)初始化glfw,具体解释看:OpenGL学习(一) 绘制一个三角形 - 简书
int DrawApi::initialGlfw()
{
glfwInit();
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
// glad: load all OpenGL function pointers
return 0;
}
2)创建窗口:
int DrawApi::createWindow(string windowName, OUT GLFWwindow*& window)
{
// glfw window creation
// --------------------
window = glfwCreateWindow(SCR_WIDTH, SCR_HEIGHT, windowName.c_str(), NULL, NULL);
if (window == NULL)
{
glfwTerminate();
return -1;
}
glfwMakeContextCurrent(window);
// ---------------------------------------
if (!gladLoadGLLoader((GLADloadproc)glfwGetProcAddress))
{
cout << "Failed to initialize GLAD" << endl;
return -1;
}
glViewport(0, 0, 800, 800);
glfwSetFramebufferSizeCallback(window, framebuffer_size_callback); // 窗体能够根据拉动变化
return 0;
}
3)顶点着色器
int DrawApi::createVertexShader(OUT GLuint& vertexShader, const char* vertexShaderSource)
{
//1.初始化着色器
//创建一个着色器类型
vertexShader = glCreateShader(GL_VERTEX_SHADER);
//把代码复制进着色器中
glShaderSource(vertexShader, 1, &vertexShaderSource, NULL);
//编译顶点着色器
glCompileShader(vertexShader);
int success;
char infoLog[512];
glGetShaderiv(vertexShader, GL_COMPILE_STATUS, &success);
//判断是否编译成功
if (!success) {
glGetShaderInfoLog(vertexShader, 512, NULL, infoLog);
cout << "error when vertex compile:" << infoLog << endl;
return -1;
}
return 0;
}
4)片元着色器
int DrawApi::createFragmentShader(OUT GLuint& fragmentShader, const char* fragmentShaderSource)
{
fragmentShader = glCreateShader(GL_FRAGMENT_SHADER);
glShaderSource(fragmentShader, 1, &fragmentShaderSource, NULL);
glCompileShader(fragmentShader);
int success;
char infoLog[512];
glGetShaderiv(fragmentShader, GL_COMPILE_STATUS, &success);
//判断是否编译成功
if (!success) {
glGetShaderInfoLog(fragmentShader, 512, NULL, infoLog);
cout << "error when fragment compile:" << infoLog << endl;
return -1;
}
return 0;
}
5)编译程序
int DrawApi::createProgram(GLuint& vertexShader, GLuint& fragmentShader, OUT GLuint& shaderProgram)
{
//链接,创建一个程序
shaderProgram = glCreateProgram();
//链接上共享库
glAttachShader(shaderProgram, vertexShader);
glAttachShader(shaderProgram, fragmentShader);
//链接
glLinkProgram(shaderProgram);
int success;
char infoLog[512];
glGetProgramiv(shaderProgram, GL_LINK_STATUS, &success);
if (!success) {
glGetProgramInfoLog(shaderProgram, 512, NULL, infoLog);
cout << "error when link compile:" << infoLog << endl;
return -1;
}
glDeleteShader(vertexShader);
glDeleteShader(fragmentShader);
return 0;
}
6)绘制三角形
int DrawApi::drawTriangles(const vector<vector<float>>& triangelValues)
{
//1.会先绑定顶点
//2.绑定缓冲区
//3.接着把顶点输入到顶点缓冲去中
//4.把缓冲区的数据传送到着色器中
//5.输出到屏幕。
if (initialGlfw() < 0)
return -1;
GLFWwindow* window = nullptr;
if (createWindow("learnOpenGL", window) < 0)
return -2;
GLuint vertexShader;
if (createVertexShader(vertexShader, VERTEX_SHADER) < 0)
return -3;
GLuint fragmentShader;
if (createFragmentShader(fragmentShader, FRAGMENT_SHADER) < 0)
return -4;
GLuint shaderProgram;
if (createProgram(vertexShader, fragmentShader, shaderProgram) < 0)
return -5;
if (triangelValues.size() == 0)
return -6;
if (triangelValues.size() > 1256)
return -7;
float vertices[4096] = {0};
for (int i = 0; i < triangelValues.size(); i++)
{
for (int j = 0; j < 3; j++)
{
vertices[3 * i + j] = triangelValues[i][j];
}
}
GLuint VAO;
// 生成分配VAO
glGenVertexArrays(1, &VAO);
// 绑定VAO,注意在core模式,没有绑定VAO,opengl拒绝绘制任何东西
glBindVertexArray(VAO);
GLuint VBO;
// 生成一个VBO缓存对象
glGenBuffers(1, &VBO);
// 绑定VBO
glBindBuffer(GL_ARRAY_BUFFER, VBO);
// 类型为GL_ARRAY_BUFFER 第二第三参数说明要放入缓存的多少,GL_STATIC_DRAW当画面不动的时候推荐使用
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void*)0);
glEnableVertexAttribArray(0);
glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindVertexArray(0);
// render loop
// -----------
while (!glfwWindowShouldClose(window))
{
// input
processInput(window);
// render
glClearColor(0.2f, 0.3f, 0.3f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT);
glUseProgram(shaderProgram);
//绑定数据
glBindVertexArray(VAO);
//绘制一个三角形
//从0开始,3个
glDrawArrays(GL_TRIANGLES, 0, triangelValues.size() * 3);
glBindVertexArray(0);
// glfw: swap buffers and poll IO events (keys pressed/released, mouse moved etc.)
// -------------------------------------------------------------------------------
glfwSwapBuffers(window);
glfwPollEvents();
}
glDeleteVertexArrays(1, &VAO);
glDeleteBuffers(1, &VBO);
// glfw: terminate, clearing all previously allocated GLFW resources.
// ------------------------------------------------------------------
glfwTerminate();
return 0;
}