当前位置: 首页 > news >正文

openGL学习(基本窗口)

学习路线 

学习 OpenGL 需要掌握一系列基础知识和技能,这些内容涵盖了计算机图形学的基本概念、编程语言、数学知识以及 OpenGL 的具体 API 使用。以下是学习 OpenGL 所需的主要知识点:

1. 计算机图形学基础

  • 图形学概念:了解图形学的基本概念,如像素、分辨率、颜色模型(RGB、RGBA)、光栅化、光栅图形等。

  • 图形管线:理解图形渲染管线的工作原理,包括顶点处理、光栅化、片段处理等阶段。

  • 图形对象:熟悉常见的图形对象,如点、线、多边形、纹理、光照等。

2. 数学基础

  • 线性代数

    • 向量:向量的基本运算(加法、减法、点积、叉积)。

    • 矩阵:矩阵的基本运算(乘法、逆矩阵、转置)。

    • 变换:平移、旋转、缩放等变换的矩阵表示。

  • 几何知识

    • 坐标系:理解世界坐标系、物体坐标系、视图坐标系、屏幕坐标系等。

    • 投影:正交投影和透视投影的概念及实现。

  • 光栅化算法

    • 直线绘制算法:如 Bresenham 算法。

    • 多边形填充算法:如扫描线填充算法。

3. 编程语言

  • C/C++:OpenGL 主要使用 C/C++ 进行编程,因此需要熟练掌握 C/C++ 的基本语法和编程技巧。

  • GLSL(OpenGL Shading Language):用于编写着色器程序,包括顶点着色器、片段着色器等。

4. OpenGL API

  • OpenGL 基础

    • 初始化:创建窗口、初始化 OpenGL 上下文(可以使用 GLFW 等库)。

    • 状态管理:了解 OpenGL 的状态机模型,如何设置和查询状态。

    • 缓冲区对象:如顶点缓冲区对象(VBO)、顶点数组对象(VAO)、帧缓冲区对象(FBO)等。

  • 着色器编程

    • 着色器类型:顶点着色器、片段着色器、几何着色器等。

    • 着色器程序:编写、编译、链接着色器程序。

    • 变量传递:如何将数据从 CPU 传递到 GPU(如 uniform 变量、attribute 变量)。

  • 渲染技术

    • 基本渲染:绘制点、线、三角形等基本图形。

    • 纹理映射:加载和应用纹理,理解纹理坐标、纹理过滤、纹理环绕等概念。

    • 光照:理解光照模型(如 Phong 照明模型),实现平行光、点光源、环境光等。

    • 阴影:实现阴影映射等高级光照效果。

  • 高级技术

    • 曲面细分:使用曲面细分着色器生成更平滑的曲面。

    • 计算着色器:用于通用计算任务。

    • 多视口渲染:在多个视口同时渲染不同的场景。

    • 后处理效果:如模糊、HDR、抗锯齿等。

5. 辅助工具和库

  • GLFW:用于创建窗口和处理输入。

  • GLAD:用于加载 OpenGL 函数指针。

  • GLM(OpenGL Mathematics):用于处理数学运算,如向量和矩阵运算。

  • FreeGLUT:用于创建窗口和处理输入(与 GLFW 类似)。

  • Assimp:用于加载 3D 模型文件。

  • SOIL:用于加载纹理文件。

6. 调试和优化

  • 调试工具:使用调试工具(如 RenderDoc、gDEBugger)来调试 OpenGL 程序。

  • 性能优化:了解常见的性能瓶颈(如 CPU/GPU 瓶颈、内存带宽瓶颈)和优化方法。

7. 实践项目

  • 小型项目:从简单的项目开始,如绘制一个旋转的立方体。

  • 复杂项目:逐步实现更复杂的场景,如加载 3D 模型、实现简单的游戏引擎等。

学习资源推荐

  • 书籍

    • 《OpenGL SuperBible》:适合初学者和进阶学习者。

    • 《OpenGL Programming Guide》(红宝书):经典教材。

  • 在线教程

    • LearnOpenGL:非常详细的 OpenGL 教程,适合初学者。

    • OpenGL Tutorial:包含丰富的示例和代码。

  • 视频教程

    • YouTube 上有许多 OpenGL 教程,如 The Cherno 的 OpenGL 系列。

初试OpenGL

1.首先需要编译glfw-3.4的动态库,和glad库,使用vs2021进行程序编写。

#include <iostream>
//#include "thrirdParty/include/GLFW/glfw3.h"
#include "glad/glad.h"   //需要先引用glad的头文件。
#include "GLFW/glfw3.h"using namespace std;
/*
* 创建glfw的窗体系统
*/
int main(int argc,char**argv)
{cout << "===================================" << endl;//1. 初始化GLFW基本环境glfwInit();glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 4);glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 6);//启用核心模式(非立即渲染模式)glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);// 2. 创建窗体对象GLFWwindow* win = glfwCreateWindow(800, 600, "OpenGlStudy", NULL, NULL);//设置窗体对象为Opengl的绘制舞台glfwMakeContextCurrent(win);// // 3. 执行窗体循环// while (!glfwWindowShouldClose(win)){//接受并且分发窗体消息//检查消息队列是否有需要处理的鼠标,键盘等信息//如果有的话就将消息批量处理,清空队列。glfwPollEvents();}// 4. 退出程序前做相关清理glfwTerminate();cout << "===================================" << endl;return 0;
}

 CMakeLists.txt

cmake_minimum_required(VERSION 3.12)project(OpenGL_Lecture)set(CMAKE_CXX_STANDARD 11)include_directories(SYSTEM ${CMAKE_CURRENT_SOURCE_DIR}/thrirdParty/include
)
link_directories(SYSTEM ${CMAKE_CURRENT_SOURCE_DIR}/thrirdParty/lib)
add_executable(openglStudy "main.cpp" "glad.c")target_link_libraries(openglStudy glfw3.lib)

 事件响应

#include <iostream>
//#include "thrirdParty/include/GLFW/glfw3.h"
#include "glad/glad.h"   //需要先引用glad的头文件。
#include "GLFW/glfw3.h"using namespace std;
/*
* 创建glfw的窗体系统
* 加入窗体变化的事件回调
*/void frameBufferSizeCallback(GLFWwindow* win, int width, int height)
{std::cout << "窗体的最新大小为:" << width << "高度为:" << height << std::endl;}void keyCallback(GLFWwindow* window, int key, int scancode, int action, int mods){// key 字母按键码 // scancode 物理按键码		 // action:0抬起1按下2长按// mods:是否有shift(1)或ctrl(2) cout << "key = " << key << " scancode = " << scancode << " action = " << action << " mods = " << mods << endl;if (key == GLFW_KEY_W){//按下了w}else if (action == GLFW_PRESS){//按下了}else if (action == GLFW_RELEASE){//抬起}}int main(int argc,char**argv)
{cout << "===================================" << endl;//1. 初始化GLFW基本环境glfwInit();glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 4);glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 6);//启用核心模式(非立即渲染模式)glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);// 2. 创建窗体对象GLFWwindow* win = glfwCreateWindow(800, 600, "OpenGlStudy", NULL, NULL);//设置窗体对象为Opengl的绘制舞台glfwMakeContextCurrent(win);//设置监听帧缓冲窗口大小回调函数。glfwSetFramebufferSizeCallback(win, frameBufferSizeCallback);glfwSetKeyCallback(win, keyCallback);// // 3. 执行窗体循环// while (!glfwWindowShouldClose(win)){//接受并且分发窗体消息//检查消息队列是否有需要处理的鼠标,键盘等信息//如果有的话就将消息批量处理,清空队列。glfwPollEvents();}// 4. 退出程序前做相关清理glfwTerminate();cout << "===================================" << endl;return 0;
}

函数加载

Opengl运行环境是一个巨大的状态机,每一个函数都会改变状态机的状态或者触发其执行某个行为。

OpenGL采用双缓冲机制 ,利用两个缓冲区进行交替展示。

#include <iostream>
//#include "thrirdParty/include/GLFW/glfw3.h"
#include "glad/glad.h"   //需要先引用glad的头文件。
#include "GLFW/glfw3.h"using namespace std;
/*
* 创建glfw的窗体系统
* 加入窗体变化的事件回调
*/void frameBufferSizeCallback(GLFWwindow* win, int width, int height)
{std::cout << "窗体的最新大小为:" << width << "高度为:" << height << std::endl;//更新窗体的大小glViewport(0, 0, width, height);}void keyCallback(GLFWwindow* window, int key, int scancode, int action, int mods){// key 字母按键码 // scancode 物理按键码		 // action:0抬起1按下2长按// mods:是否有shift(1)或ctrl(2) cout << "key = " << key << " scancode = " << scancode << " action = " << action << " mods = " << mods << endl;if (key == GLFW_KEY_W){//按下了w}else if (action == GLFW_PRESS){//按下了}else if (action == GLFW_RELEASE){//抬起}}int main(int argc,char**argv)
{cout << "===================================" << endl;//1. 初始化GLFW基本环境glfwInit();glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 4);glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 6);//启用核心模式(非立即渲染模式)glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);// 2. 创建窗体对象GLFWwindow* win = glfwCreateWindow(800, 600, "OpenGlStudy", NULL, NULL);//设置窗体对象为Opengl的绘制舞台glfwMakeContextCurrent(win);//设置监听帧缓冲窗口大小回调函数。glfwSetFramebufferSizeCallback(win, frameBufferSizeCallback);glfwSetKeyCallback(win, keyCallback);// 使用glad加载所有当前版本的OpenGL函数,加载后才能使用if (!gladLoadGLLoader((GLADloadproc)glfwGetProcAddress) ) {cout << "Failed to initialize glad " << endl;}//设置OpenGL视口以及清理颜色glViewport(0,0,800,600);glClearColor(0.2f,0.3f,0.3f,1.0f);// 3. 执行窗体循环// while (!glfwWindowShouldClose(win)){//接受并且分发窗体消息glfwPollEvents();glClear(GL_COLOR_BUFFER_BIT);//渲染操作// //切换双缓冲glfwSwapBuffers(win);}// 4. 退出程序前做相关清理glfwTerminate();cout << "===================================" << endl;return 0;
}

OpenGL函数错误处理

main.cpp

#include <iostream>
//#include "thrirdParty/include/GLFW/glfw3.h"
#include "glad/glad.h"   //需要先引用glad的头文件。
#include "GLFW/glfw3.h"
#include <assert.h>
#include "wrapper/checkerror.h"using namespace std;/*
* 创建glfw的窗体系统
* 加入窗体变化的事件回调
*/void frameBufferSizeCallback(GLFWwindow* win, int width, int height)
{std::cout << "窗体的最新大小为:" << width << "高度为:" << height << std::endl;//更新窗体的大小glViewport(0, 0, width, height);}void keyCallback(GLFWwindow* window, int key, int scancode, int action, int mods){// key 字母按键码 // scancode 物理按键码		 // action:0抬起1按下2长按// mods:是否有shift(1)或ctrl(2) cout << "key = " << key << " scancode = " << scancode << " action = " << action << " mods = " << mods << endl;if (key == GLFW_KEY_W){//按下了w}else if (action == GLFW_PRESS){//按下了}else if (action == GLFW_RELEASE){//抬起}}int main(int argc,char**argv)
{cout << "===================================" << endl;//1. 初始化GLFW基本环境glfwInit();glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 4);glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 6);//启用核心模式(非立即渲染模式)glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);// 2. 创建窗体对象GLFWwindow* win = glfwCreateWindow(800, 600, "OpenGlStudy", NULL, NULL);//设置窗体对象为Opengl的绘制舞台glfwMakeContextCurrent(win);//设置监听帧缓冲窗口大小回调函数。glfwSetFramebufferSizeCallback(win, frameBufferSizeCallback);glfwSetKeyCallback(win, keyCallback);// 使用glad加载所有当前版本的OpenGL函数,加载后才能使用if (!gladLoadGLLoader((GLADloadproc)glfwGetProcAddress) ) {cout << "Failed to initialize glad " << endl;}//设置OpenGL视口以及清理颜色glViewport(0,0,800,600);glClearColor(0.2f,0.3f,0.3f,1.0f);// 3. 执行窗体循环// while (!glfwWindowShouldClose(win)){//接受并且分发窗体消息glfwPollEvents();GL_CALL( glClear(GL_COLOR_BUFFER_BIT) );//glClear(-1);//设置错误颜色不会崩溃,会出现黑色//checkError();//GL_CALL(glClear(-1) ); //渲染操作// //切换双缓冲glfwSwapBuffers(win);}// 4. 退出程序前做相关清理glfwTerminate();cout << "===================================" << endl;return 0;
}

wrapper/checkerror.cpp

头文件checkerror.h就是void checkError();

#include "checkerror.h"
#include "glad/glad.h"
#include <string>
#include <iostream>
#include <assert.h>using namespace std;void checkError()
{GLenum errornum = glGetError();//cout << "errornum = " << errornum << endl; //错误码1281 GL_INVALID_VALUEstd::string errorstr = "";if (errornum != GL_NO_ERROR){cout << "GL有错误" << endl;switch (errornum){case GL_INVALID_ENUM:errorstr = "无效的枚举 GL_INVALID_ENUM"; break;case GL_INVALID_VALUE:errorstr = "无效的值 GL_INVALID_VALUE"; break;case GL_INVALID_OPERATION:errorstr = "无效的操作 GL_INVALID_OPERATION"; break;case GL_OUT_OF_MEMORY:errorstr = "无效的内存 GL_OUT_OF_MEMORY"; break;default:errorstr = "UNKNOWN";break;}cout << "errorstr = " << errorstr << endl;assert(false); //断言根据bool决定是否停止程序。}
}

./CMakeLists.txt

cmake_minimum_required(VERSION 3.12)project(OpenGL_Lecture)set(CMAKE_CXX_STANDARD 11)include_directories(SYSTEM ${CMAKE_CURRENT_SOURCE_DIR}/thrirdParty/include
)
link_directories(SYSTEM ${CMAKE_CURRENT_SOURCE_DIR}/thrirdParty/lib)add_subdirectory(wrapper)#在项目夹加入全局的预编译宏
add_definitions(-DCHECK_ERROR)add_executable(openglStudy "main.cpp" "glad.c" )target_link_libraries(openglStudy glfw3.lib wrapper)

wrapper/CMakeLists.txt

#递归将本文件夹下的所有cpp放到WRAPPER中file(GLOB_RECURSE WRAPPER ./ *.cpp)#将所有cpp文件链接到这个wrapper lib库中。 默认生成静态库,动态库编译不过去
add_library(wrapper    ${WRAPPER})

Application封装

 application.cpp

#include "application.h"
#include "application.h"
#include "application.h"#include "glad/glad.h"   //需要先引用glad的头文件。 用于加载 OpenGL 函数指针
#include "GLFW/glfw3.h" // 用于创建窗口和处理输入。	Application* Application::m_app = nullptr;
Application* Application::getInst()
{if (m_app == nullptr){m_app = new Application();}return m_app;
}int Application::init(const int width, const int height)
{cout << "Application::init" << endl;m_Width = width;m_Height = height;//1. 初始化GLFW基本环境glfwInit();glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 4);glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 6);//启用核心模式(非立即渲染模式)glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);// 2. 创建窗体对象m_Window = glfwCreateWindow(m_Width, m_Height, "OpenGlStudy", NULL, NULL);if (m_Window == NULL){return -1;}//设置窗体对象为Opengl的绘制舞台glfwMakeContextCurrent(m_Window);// 使用glad加载所有当前版本的OpenGL函数,加载后才能使用if (!gladLoadGLLoader((GLADloadproc)glfwGetProcAddress)){cout << "Failed to initialize glad " << endl;return -1;}//GLFW监听必须要使用static进行声明。//窗口大小改变的事件glfwSetFramebufferSizeCallback(m_Window, frameBufferSizeCallback);//键盘的事件glfwSetKeyCallback(m_Window, keyCallback);//this就是全局Application对象glfwSetWindowUserPointer(m_Window, this);//将this暂时存在窗体中。return 0;
}int Application::update()
{if (glfwWindowShouldClose(m_Window)){return -1;}//接受并且分发窗体消息glfwPollEvents();//切换双缓冲glfwSwapBuffers(m_Window);return 0;
}int Application::destroy()
{cout << "Application::destroy" << endl;// 4. 退出程序前做相关清理glfwTerminate();return 0;
}Application::Application()
{}void Application::frameBufferSizeCallback(GLFWwindow* win, int width, int height)
{//因为是静态函数,所以不能调用全局唯一实例。// 静态成员函数属于类本身,而不是类的某个具体对象。//它不依赖于任何对象实例,因此不能访问非静态成员变量//(因为非静态成员变量需要对象实例来存储其值)。cout << "frameBufferSizeCallback " << endl;//m_resizeCallBack();// //面试题:如何在静态成员函数中调用非静态函数?//if(Application::getInst()->m_resizeCallBack != nullptr)//	Application::getInst()->m_resizeCallBack(width,height);Application* self  = (Application*) glfwGetWindowUserPointer(win);if(self->m_resizeCallBack != nullptr)self->m_resizeCallBack(width, height);}void Application::keyCallback(GLFWwindow* window, int key, int scancode, int action, int mods)
{cout << "keyCallback " << endl;Application* self = (Application*)glfwGetWindowUserPointer(window);if (self->m_keyCallBack != nullptr)self->m_keyCallBack(window, key,scancode,action,mods);}Application::~Application()
{}

application.h

#pragma once#include <iostream>#define app Application::getInst()class GLFWwindow; //提前声明class,避免头文件重复定义的问题.using resizeCallBack = void(*)(int width,int height);
using keyCallBack = void(*)(GLFWwindow* window,int key, int scancode, int action, int mods);using namespace std;//单例类实现class Application
{
public:~Application();static Application* getInst();void test() { cout << "test" << endl; };uint32_t getWidth() const { return m_Width; }; //const含义:不改变类中的成员uint32_t getHeight() const { return m_Height; };int init(const int width = 800, const int height = 500);int update();int destroy(); void setResizeCallBack(resizeCallBack call) { m_resizeCallBack = call; };void setkeyCallBack(keyCallBack call) { m_keyCallBack = call; };private:Application();static Application* m_app;uint32_t m_Width{ 0 }; //列表初始化uint32_t m_Height{ 0 };GLFWwindow* m_Window{ nullptr };resizeCallBack m_resizeCallBack{nullptr};keyCallBack m_keyCallBack{ nullptr };private:static void frameBufferSizeCallback(GLFWwindow*win,int width,int height);static void keyCallback(GLFWwindow* window, int key, int scancode, int action, int mods);};

main.cpp

#include <iostream>
//#include "thrirdParty/include/GLFW/glfw3.h" 
#include "glad/glad.h"   //需要先引用glad的头文件。 用于加载 OpenGL 函数指针
#include "GLFW/glfw3.h" // 用于创建窗口和处理输入。	
#include <assert.h>
#include "wrapper/checkerror.h"
#include "application/application.h"using namespace std;/*
* 创建glfw的窗体系统
* 加入窗体变化的事件回调
*/void onResize(int width,int height)
{GL_CALL(glViewport(0, 0, width, height));cout << "onResize " << endl;
}void frameBufferSizeCallback(GLFWwindow* win, int width, int height)
{std::cout << "窗体的最新大小为:" << width << "高度为:" << height << std::endl;//更新窗体的大小glViewport(0, 0, width, height);}void keyCallback(GLFWwindow* window, int key, int scancode, int action, int mods){// key 字母按键码 // scancode 物理按键码		 // action:0抬起1按下2长按// mods:是否有shift(1)或ctrl(2) cout << "key = " << key << " scancode = " << scancode << " action = " << action << " mods = " << mods << endl;if (key == GLFW_KEY_W){//按下了w}else if (action == GLFW_PRESS){//按下了}else if (action == GLFW_RELEASE){//抬起}}int main(int argc,char**argv)
{cout << "===================================" << endl;if (app->init(800,600) == -1){return -1;}//设置监听帧缓冲窗口大小回调函数。//glfwSetFramebufferSizeCallback(win, frameBufferSizeCallback);//glfwSetKeyCallback(win, keyCallback);app->setResizeCallBack(onResize);app->setkeyCallBack(keyCallback);//设置OpenGL视口以及清理颜色glViewport(0,0,800,600);glClearColor(0.2f,0.3f,0.3f,1.0f);// 3. 执行窗体循环// while (app->update() == 0 ){GL_CALL( glClear(GL_COLOR_BUFFER_BIT) );//渲染操作}// 4. 退出程序前做相关清理app->destroy();cout << "===================================" << endl;return 0;
}

http://www.lryc.cn/news/576165.html

相关文章:

  • [ linux-系统 ] 磁盘与文件系统
  • 【论文阅读 | CVPR 2025 |MambaVision:一种混合 Mamba-Transformer 视觉骨干网络】
  • 2025.6.27总结
  • 机器人 URDF学习笔记
  • Windows 10 ARM64平台CAN程序开发
  • 飞凌A40i使用笔记
  • React中的ErrorBoundary
  • 【Yonghong 企业日常问题08 】永洪BI的Apache Tomcat版本升级指南
  • 【CV数据集介绍-40】Cityscapes 数据集:助力自动驾驶的语义分割神器
  • 攻防世界-MISC-Cephalopod
  • gemini-cli 踩坑实录
  • ARM64 linux系统的一般执行过程
  • C++ 函数特性详解:默认参数、重载、引用与指针区别
  • Flutter 网络请求指南, 从 iOS 到 Flutter 的 Dio + Retrofit 组合
  • 《聊一聊ZXDoc》之汽车服务导向SOME/IP
  • 【k近邻】 K-Nearest Neighbors算法原理及流程
  • 在shell中直接调用使用R
  • 远眺科技工业园区数字孪生方案,如何实现智能管理升级?
  • 告别堡垒机和VPN!Teleport:下一代基础设施统一访问入口
  • CTP IC失效现象和失效原理分析
  • 利用python实现NBA数据可视化
  • np.concatenate
  • 【C/C++】C++26新特性前瞻:全面解析未来编程
  • ​​Oracle表空间全景指南:从扩容监控到碎片回收的终极实践​
  • 车载诊断架构--- 车载诊断中的引导式诊断
  • 人工智能-基础篇-3-什么是深度学习?(DL,卷积神经网络CNN,循环神经网络RNN,Transformer等)
  • 第六章 STM32内存管理
  • 学习接口自动化框架pytest有哪些好处?
  • 小程序 API 开发手册:从入门到高级应用一网打尽
  • C++学习之STL学习:vector的模拟实现