当前位置: 首页 > 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.lqws.cn/news/551017.html

相关文章:

  • 深入学习MySQL的页分裂(Page Split)
  • 策略模式与工厂模式的黄金组合:从设计到实战
  • yaml 导致的原型污染 -- GPN CTF 2025 Secure by Default
  • 《高等数学》(同济大学·第7版)第九章 多元函数微分法及其应用第五节多元函数微分学的几何应用
  • Redis 单线程的“天花板”与集群的必要性
  • 三、java项目自动部署流水线搭建
  • oracle内存参数调整
  • 【C++】string的模拟实现
  • 关于css的height:100%
  • 助力高考,利用python获取本专科专业选考科目要求
  • 开疆智能CCLinkIE转ModbusTCP网关连接组态王配置案例
  • 开源 java android app 开发(十三)绘图定义控件、摇杆控件的制作
  • Ollama+Gemma3模型+Open WebUI,无公网IP如何内网穿透远程访问?
  • 【Linux 设备模型框架 kobject 和 kset】
  • Java 大视界 -- Java 大数据在智能安防视频监控系统中的目标轨迹预测与防范策略制定(325)
  • 【k近邻】 K-Nearest Neighbors算法原理及流程
  • 机器学习3——参数估计之极大似然估计
  • C++并发编程-4.unique_lock,共享锁和递归锁
  • 详解HashMap底层原理
  • 电脑远程控制另一台电脑无法连接怎么办
  • PostgreSQL 容器化分布式技术方案
  • 基于51单片机-蜂鸣器演奏《飞雪玉花》
  • 什么是故障注入测试
  • 强化联邦学习的车联网 DDoS 攻击检测
  • 【图像处理入门】12. 综合项目与进阶:超分辨率、医学分割与工业检测
  • FLUX.1 Kontext(Dev 版)训练lora基础教程
  • TiDB AUTO_RANDOM 超大主键前端精度丢失排查:JavaScript Number 限制与解决方案
  • 内测开启!看海量化回测系统V2.0版本更新,基于miniQMT的回测系统问世!
  • Threejs开发指南(第七篇 利用AI进行threejs开发)
  • 封装nuxt3的SSR请求和CSR请求方法