三维物体不是说相对2维多什么,是使用矩阵变化,来营造不同的视角,从而达到3维效果,这就涉及到了比较重要的总共有5个不同的坐标系统:

  • 局部空间(Local Space,或者称为物体空间(Object Space))
  • 世界空间(World Space)
  • 观察空间(View Space,或者称为视觉空间(Eye Space))
  • 裁剪空间(Clip Space)
  • 屏幕空间(Screen Space)

将坐标从一个坐标系变换到另一个坐标系,我们需要用到几个变换矩阵,最重要的几个分别是模型(Model)、观察(View)、投影(Projection)三个矩阵。我们的顶点坐标起始于局部坐标(Local Coordinate),它在之后会变为世界坐标(World Coordinate),观察坐标(View Coordinate),裁剪坐标(Clip Coordinate),并最后以屏幕坐标(Screen Coordinate)的形式结束

为上面每一个步骤都创建了一个变换矩阵:模型矩阵、观察矩阵和投影矩阵。一个顶点坐标将会经过gl_Position = projection * view * model * vec4(aPos, 1.0);被变换到裁剪坐标,OpenGL将会自动进行透视除法和裁剪

3D绘图流程:

  • 首先创建一个模型矩阵model。这个模型矩阵包含了位移、缩放与旋转操作,它们会被应用到所有物体的顶点上,以变换它们到全局的世界空间
  • 再创建一个观察矩阵。我们想要在场景里面稍微往后移动,以使得物体变成可见的(当在世界空间时,我们位于原点(0,0,0))
  • 接着再创建一个投影矩阵。在场景中使用透视投影
  • 最后修改着色器并传入数据,调试程序

参考链接:
https://learnopengl-cn.github.io/01%20Getting%20started/08%20Coordinate%20Systems/

相关资料:
图形加载库stb_image.h:https://blog.csdn.net/y_dd6011/article/details/116703348?spm=1001.2014.3001.5501
着色器类的头文件shader.h:https://blog.csdn.net/y_dd6011/article/details/116701837?spm=1001.2014.3001.5501


渲染流程:

// 修改顶点着色器:添加变换矩阵
gl_Position = projection * view * model * vec4(aPos, 1.0);// 添加三维坐标,正方形6个面,一个面由2个三角形组成,共计36个点坐标
float vertices[] = {...};// 渲染循环之前,开启深度测试
glEnable(GL_DEPTH_TEST);// 渲染中:先清缓存,再做变化
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
ourShader.setMat4("model", model);

效果图:

源码:

// shader.vs
#version 330 core
layout(location = 0) in vec3 aPos;
layout(location = 1) in vec2 aTexCoord;out vec2 TexCoord;uniform mat4 model;
uniform mat4 view;
uniform mat4 projection;void main()
{gl_Position = projection * view * model * vec4(aPos, 1.0);TexCoord = aTexCoord;
}// shader.fs
#version 330 core
out vec4 FragColor;in vec2 TexCoord;
uniform sampler2D ourTexture0;
uniform sampler2D ourTexture1;void main()
{FragColor = mix(texture(ourTexture0, TexCoord), texture(ourTexture1, TexCoord), 0.4f);
}// main.cpp
#include <glad/glad.h>
#include <GLFW/glfw3.h>
#include <iostream>
#include "shader.h"
#include "stb_image.h"// 定义回调函数
void framebuffer_size_callback(GLFWwindow* window, int width, int height);
void processInput(GLFWwindow* window);// 宽高
const unsigned int SCR_WIDTH = 800;
const unsigned int SCR_HEIGHT = 600;int main()
{// 初始化和配置 glfwglfwInit();glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);// 创建glfw窗口GLFWwindow* window = glfwCreateWindow(SCR_WIDTH, SCR_HEIGHT, "Hello world", NULL, NULL);if (window == NULL){std::cout << "Failed to create GLFW window" << std::endl;glfwTerminate();return -1;}glfwMakeContextCurrent(window);// 使用glad加载OpenGL函数指针if (!gladLoadGLLoader((GLADloadproc)glfwGetProcAddress)){std::cout << "Failed to inittalize GLAD" << std::endl;return -1;}// 确定视口(Viewport)的大小glViewport(0, 0, SCR_WIDTH, SCR_HEIGHT);glfwSetFramebufferSizeCallback(window, framebuffer_size_callback);// 设置两个必须的着色器:顶点和片段着色器Shader ourShader("shader.vs", "shader.fs");// 定义正方形坐标float vertices[] = {-0.5f, -0.5f, -0.5f,  0.0f, 0.0f,0.5f, -0.5f, -0.5f,  1.0f, 0.0f,0.5f,  0.5f, -0.5f,  1.0f, 1.0f,0.5f,  0.5f, -0.5f,  1.0f, 1.0f,-0.5f,  0.5f, -0.5f,  0.0f, 1.0f,-0.5f, -0.5f, -0.5f,  0.0f, 0.0f,-0.5f, -0.5f,  0.5f,  0.0f, 0.0f,0.5f, -0.5f,  0.5f,  1.0f, 0.0f,0.5f,  0.5f,  0.5f,  1.0f, 1.0f,0.5f,  0.5f,  0.5f,  1.0f, 1.0f,-0.5f,  0.5f,  0.5f,  0.0f, 1.0f,-0.5f, -0.5f,  0.5f,  0.0f, 0.0f,-0.5f,  0.5f,  0.5f,  1.0f, 0.0f,-0.5f,  0.5f, -0.5f,  1.0f, 1.0f,-0.5f, -0.5f, -0.5f,  0.0f, 1.0f,-0.5f, -0.5f, -0.5f,  0.0f, 1.0f,-0.5f, -0.5f,  0.5f,  0.0f, 0.0f,-0.5f,  0.5f,  0.5f,  1.0f, 0.0f,0.5f,  0.5f,  0.5f,  1.0f, 0.0f,0.5f,  0.5f, -0.5f,  1.0f, 1.0f,0.5f, -0.5f, -0.5f,  0.0f, 1.0f,0.5f, -0.5f, -0.5f,  0.0f, 1.0f,0.5f, -0.5f,  0.5f,  0.0f, 0.0f,0.5f,  0.5f,  0.5f,  1.0f, 0.0f,-0.5f, -0.5f, -0.5f,  0.0f, 1.0f,0.5f, -0.5f, -0.5f,  1.0f, 1.0f,0.5f, -0.5f,  0.5f,  1.0f, 0.0f,0.5f, -0.5f,  0.5f,  1.0f, 0.0f,-0.5f, -0.5f,  0.5f,  0.0f, 0.0f,-0.5f, -0.5f, -0.5f,  0.0f, 1.0f,-0.5f,  0.5f, -0.5f,  0.0f, 1.0f,0.5f,  0.5f, -0.5f,  1.0f, 1.0f,0.5f,  0.5f,  0.5f,  1.0f, 0.0f,0.5f,  0.5f,  0.5f,  1.0f, 0.0f,-0.5f,  0.5f,  0.5f,  0.0f, 0.0f,-0.5f,  0.5f, -0.5f,  0.0f, 1.0f};// 设置顶点缓冲对象(Vertex Buffer Objects, VBO)管理内存(坐标点数据)与 VAOunsigned int VAO, VBO;glGenVertexArrays(1, &VAO);  // 使用glGenVertexArrays函数和一个缓冲ID生成一个VAO对象glGenBuffers(1, &VBO);       // 使用glGenBuffers函数和一个缓冲ID生成一个VBO对象// 绑定: 先VAO 再VBOglBindVertexArray(VAO);glBindBuffer(GL_ARRAY_BUFFER, VBO);glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);// 位置属性glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 5 * sizeof(float), (void*)0);glEnableVertexAttribArray(0);  // 使用glEnableVertexAttribArray,以顶点属性位置值作为参数,启用顶点属性,顶点属性默认是禁用的// 纹理属性glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 5 * sizeof(float), (void*)(3 * sizeof(float)));glEnableVertexAttribArray(1);// 生成纹理unsigned int texture0, texture1;stbi_set_flip_vertically_on_load(true); // 防止图片倒置// glGenTextures先输入要生成纹理的数量,然后把它们储存在第二个参数的`unsigned int`数组中glGenTextures(1, &texture0);// 绑定glBindTexture(GL_TEXTURE_2D, texture0);// 为当前绑定的纹理对象设置环绕、过滤方式glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);// 加载并生成纹理int width, height, nrChannels;unsigned char* data = stbi_load("wall.jpg", &width, &height, &nrChannels, 0);if (data){// 生成纹理glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, data);// 注:不需要手动更改我们在片段着色器定义的uniform sampler2D ourTexture,它会自动把纹理赋值给片段着色器的采样器ourTexture// 为当前绑定的纹理自动生成所有需要的多级渐远纹理glGenerateMipmap(GL_TEXTURE_2D);}else{std::cout << "Failed to load texture" << std::endl;}// 释放图像的内存stbi_image_free(data);glGenTextures(1, &texture1);// 绑定glBindTexture(GL_TEXTURE_2D, texture1);// 为当前绑定的纹理对象设置环绕、过滤方式glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);data = stbi_load("hh.png", &width, &height, &nrChannels, 0);if (data){glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, data);glGenerateMipmap(GL_TEXTURE_2D);}else{std::cout << "Failed to load texture" << std::endl;}// 释放图像的内存stbi_image_free(data);ourShader.use();// 我们还要通过使用glUniform1i设置每个采样器的方式告诉OpenGL每个着色器采样器属于哪个纹理单元。我们只需要设置一次即可,所以这个会放在渲染循环的前面:glUniform1i(glGetUniformLocation(ourShader.ID, "ourTexture0"), 0); // 手动设置ourShader.setInt("ourTexture1", 1); // 或者使用着色器类设置// 渲染循环之前,开启深度测试glEnable(GL_DEPTH_TEST);// 开启渲染循环(Render Loop)while (!glfwWindowShouldClose(window)){// 输入控制:processInput(window);// 渲染指令// 修改背景颜色glClearColor(0.2f, 0.3f, 0.3f, 1.0f);glClear(GL_COLOR_BUFFER_BIT);// 绘图ourShader.use();glActiveTexture(GL_TEXTURE0);            // 激活纹理单元glBindTexture(GL_TEXTURE_2D, texture0);  // 绑定纹理glActiveTexture(GL_TEXTURE1);            // 激活纹理单元glBindTexture(GL_TEXTURE_2D, texture1);  // 绑定纹理glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);  // 先清缓存// 创建矩阵glm::mat4 model = glm::mat4(1.0f);glm::mat4 view = glm::mat4(1.0f);glm::mat4 projection = glm::mat4(1.0f);model = glm::rotate(model, (float)glfwGetTime() * glm::radians(50.0f), glm::vec3(0.5f, 1.0f, 0.0f));view = glm::translate(view, glm::vec3(0.0f, 0.0f, -3.0f));projection = glm::perspective(glm::radians(45.0f), (float)SCR_WIDTH / (float)SCR_HEIGHT, 0.1f, 100.0f);// 将矩阵传入着色器ourShader.setMat4("model", model);ourShader.setMat4("view", view);ourShader.setMat4("projection", projection);glBindVertexArray(VAO);                 // 启动VAOglDrawArrays(GL_TRIANGLES, 0, 36);// 检查调用事件,并交换缓冲glfwPollEvents();glfwSwapBuffers(window);}// 回收资源glDeleteVertexArrays(1, &VAO);glDeleteBuffers(1, &VBO);glfwTerminate();return 0;
}// 窗口改变回调函数
void framebuffer_size_callback(GLFWwindow* window, int width, int height)
{glViewport(0, 0, width, height);
}
// 窗口按键输入
void processInput(GLFWwindow* window)
{// 按下esc按键,退出程序if (glfwGetKey(window, GLFW_KEY_ESCAPE) == GLFW_PRESS)glfwSetWindowShouldClose(window, true);
}

OpenGL 渲染正方体相关推荐

  1. 教你实现GPUImage【OpenGL渲染原理】

    原文出处: 袁峥Seemygo(@袁峥Seemygo)    一.前言 本篇主要讲解GPUImage底层是如何渲染的,GPUImage底层使用的是OPENGL,操控GPU来实现屏幕展示 由于网上Ope ...

  2. 【OpenGL】八、初始化 OpenGL 渲染环境 ( 导入 OpenGL 头文件 | 链接 OpenGL 库 | 将窗口设置为 OpenGL 窗口 | 设置像素格式描述符 | 渲染绘制 ) ★

    文章目录 一.导入 OpenGL 的两个头文件 二.链接 OpenGL 库 三.将 Windows 桌面窗口改成 OpenGL 窗口 四.获取窗口设备 五.设置像素格式描述符 六.设置像素格式 七.创 ...

  3. OpenGL渲染纹理和平面反射

    OpenGL渲染纹理和平面反射 先上图,再解答. 完整主要的源代码 源代码剖析 先上图,再解答. 完整主要的源代码 #include <stdio.h> #include "GL ...

  4. OpenGL渲染水water

    OpenGL渲染水water 先上图,再解答. 完整主要的源代码 源代码剖析 先上图,再解答. 完整主要的源代码 #include <stdio.h> #include <stdli ...

  5. C#中使用OpenGL(API)创建OpenGL渲染环境

    在C#中调用1.1版本的OpenGL函数,但是光有OpenGL函数还不能绘制图形,就像一个画家,他即使拥有绘画的技巧,还有画笔和颜料,如果没有画布,他也没有地方画画.有了画布,画家还需要画板把画布支起 ...

  6. [转贴]Cocos2d-x3.2与OpenGL渲染总结(一)Cocos2d-x3.2的渲染流程

    看了opengles有一段时间了,算是了解了一下下.然后,就在基本要决定还是回归cocos2dx 3.2的,看了这篇好文章,欣喜转之~ 推荐看原帖: Cocos2d-x3.2与OpenGL渲染总结(一 ...

  7. android 渲染yuv数据,Android opengl渲染yuv420例子

    [实例简介] Android下使用OpenGL渲染yuv420p图像并显示.例子中提供了两种类型,一种使用GLSurfaceView在onDrawframe中调用native方法绘制,另外一种使用EG ...

  8. 在Win32程序中创建OpenGL渲染环境

    在Win32程序中创建OpenGL渲染环境 创建opengl渲染环境步骤: 选定像素格式 //WinMain()HDC dc = GetDC(hwnd);PIXELFORMATDESCRIPTOR p ...

  9. 【OpenGL基础】|| OpenGL渲染过程介绍

    文章目录 1. 介绍 2. 顶点输入 3. 顶点着色器 4. 编译着色器 5. 片元着色器 6. 着色器程序 7. 链接顶点属性 8. 顶点数组对象 9. 索引缓冲对象 1. 介绍 在OpenGL中, ...

最新文章

  1. 分享Hadoop处理大数据工具及优势
  2. FIFO跨时钟域读写
  3. 配置Docker代理已实现外网访问
  4. SAP在Kubernetes上打造的Kyma到底是个什么东东
  5. 死循环线程php,QObject的派生类方法实现多线程死循环问题
  6. python怎么定义全局变量_python中如何定义全局变量
  7. android 开发中判断网络是否连接的代码
  8. 高级javascript---严格模式
  9. 从零基础入门Tensorflow2.0 ----八、39.4. gpu4
  10. 用Java Swing山寨QQ空间的魔法卡片游戏
  11. 使用iperf测试网络速度--windows
  12. IDEA - 官方定制主题,Dark Purple theme,Cyan Light Theme,Gray Theme
  13. 透彻理解高斯过程Gaussian Process (GP)
  14. android开发股票数据接口,股票数据接口-股票数据接口api
  15. osgEarth指北针
  16. 鱼和熊掌兼得——解密阿里云PCDN如何实现高质量低价格
  17. 计算机图形学:向量运算(OpenGL)
  18. vscode - 史上最优秀的 IDE ?
  19. 实验八 一阶常微分方程初值问题Matlab实现
  20. FITC-SNA,EBL;荧光素标记的黑接骨木凝集素(SNA,EBL)

热门文章

  1. 使用PS快速制作App logo图
  2. 用小程序组装App,小程序容器技术好比基建
  3. mc 手游无限挑战服务器,盘点mc中可无限获得的东西(无BUG无mod)[多图]
  4. linux系统日志及其管理
  5. 微信正式支持注册小号,但不是谁都可以
  6. 前端开发必备神级资源
  7. 重装系统Windows10纯净版操作步骤(微pe)
  8. 数据库:ER图↔关系模式
  9. 2020年节假日JSON,全年日期对应的上班日、周末、节假日
  10. 歌曲转调之后和弦如何转换