OpenGL 渲染正方体
三维物体不是说相对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 渲染正方体相关推荐
- 教你实现GPUImage【OpenGL渲染原理】
原文出处: 袁峥Seemygo(@袁峥Seemygo) 一.前言 本篇主要讲解GPUImage底层是如何渲染的,GPUImage底层使用的是OPENGL,操控GPU来实现屏幕展示 由于网上Ope ...
- 【OpenGL】八、初始化 OpenGL 渲染环境 ( 导入 OpenGL 头文件 | 链接 OpenGL 库 | 将窗口设置为 OpenGL 窗口 | 设置像素格式描述符 | 渲染绘制 ) ★
文章目录 一.导入 OpenGL 的两个头文件 二.链接 OpenGL 库 三.将 Windows 桌面窗口改成 OpenGL 窗口 四.获取窗口设备 五.设置像素格式描述符 六.设置像素格式 七.创 ...
- OpenGL渲染纹理和平面反射
OpenGL渲染纹理和平面反射 先上图,再解答. 完整主要的源代码 源代码剖析 先上图,再解答. 完整主要的源代码 #include <stdio.h> #include "GL ...
- OpenGL渲染水water
OpenGL渲染水water 先上图,再解答. 完整主要的源代码 源代码剖析 先上图,再解答. 完整主要的源代码 #include <stdio.h> #include <stdli ...
- C#中使用OpenGL(API)创建OpenGL渲染环境
在C#中调用1.1版本的OpenGL函数,但是光有OpenGL函数还不能绘制图形,就像一个画家,他即使拥有绘画的技巧,还有画笔和颜料,如果没有画布,他也没有地方画画.有了画布,画家还需要画板把画布支起 ...
- [转贴]Cocos2d-x3.2与OpenGL渲染总结(一)Cocos2d-x3.2的渲染流程
看了opengles有一段时间了,算是了解了一下下.然后,就在基本要决定还是回归cocos2dx 3.2的,看了这篇好文章,欣喜转之~ 推荐看原帖: Cocos2d-x3.2与OpenGL渲染总结(一 ...
- android 渲染yuv数据,Android opengl渲染yuv420例子
[实例简介] Android下使用OpenGL渲染yuv420p图像并显示.例子中提供了两种类型,一种使用GLSurfaceView在onDrawframe中调用native方法绘制,另外一种使用EG ...
- 在Win32程序中创建OpenGL渲染环境
在Win32程序中创建OpenGL渲染环境 创建opengl渲染环境步骤: 选定像素格式 //WinMain()HDC dc = GetDC(hwnd);PIXELFORMATDESCRIPTOR p ...
- 【OpenGL基础】|| OpenGL渲染过程介绍
文章目录 1. 介绍 2. 顶点输入 3. 顶点着色器 4. 编译着色器 5. 片元着色器 6. 着色器程序 7. 链接顶点属性 8. 顶点数组对象 9. 索引缓冲对象 1. 介绍 在OpenGL中, ...
最新文章
- 分享Hadoop处理大数据工具及优势
- FIFO跨时钟域读写
- 配置Docker代理已实现外网访问
- SAP在Kubernetes上打造的Kyma到底是个什么东东
- 死循环线程php,QObject的派生类方法实现多线程死循环问题
- python怎么定义全局变量_python中如何定义全局变量
- android 开发中判断网络是否连接的代码
- 高级javascript---严格模式
- 从零基础入门Tensorflow2.0 ----八、39.4. gpu4
- 用Java Swing山寨QQ空间的魔法卡片游戏
- 使用iperf测试网络速度--windows
- IDEA - 官方定制主题,Dark Purple theme,Cyan Light Theme,Gray Theme
- 透彻理解高斯过程Gaussian Process (GP)
- android开发股票数据接口,股票数据接口-股票数据接口api
- osgEarth指北针
- 鱼和熊掌兼得——解密阿里云PCDN如何实现高质量低价格
- 计算机图形学:向量运算(OpenGL)
- vscode - 史上最优秀的 IDE ?
- 实验八 一阶常微分方程初值问题Matlab实现
- FITC-SNA,EBL;荧光素标记的黑接骨木凝集素(SNA,EBL)