1. 概述

本文基于C++语言,描述OpenGL的变换

前置知识可参考:

笔者这里不过多描述每个名词、函数和细节,更详细的文档可以参考:

2. 导入GLM

平移、旋转、缩放等变换主要是使用变换矩阵来实现

OpenGL Mathematics(GLM)是一个基于GLSL的只有头文件的C++数学运算库

GLM的GitHub站点为:g-truc/glm: OpenGL Mathematics (GLM) (github.com)

使用GLM只需将其头文件的根目录包含到工程目录中即可

笔者这里使用的是CMake进行构建,所以只需将GLM目录使用CMake语句进行包含即可:

  1. include_directories(lib)

引入头文件:

  1. #include <glm/glm.hpp>
  2. #include <glm/gtc/matrix_transform.hpp>
  3. #include <glm/gtc/type_ptr.hpp>

3. 设置变换矩阵

设置一个平移、旋转、缩放的矩阵:

  1. glm::mat4 trans = glm::mat4(1.0f);
  2. trans = glm::translate(trans, glm::vec3(0.5f, -0.5f, 0.0f)*(float)sin(glfwGetTime()));
  3. trans = glm::rotate(trans, (float)glfwGetTime(), glm::vec3(0.0f, 0.0f, 1.0f));
  4. trans = glm::scale(trans, glm::vec3(1.0f, 1.0f, 0.0f)*(float)(sin(glfwGetTime()) * 0.5 + 0.5));

在顶点着色器中将变换矩阵与坐标结合:

  1. #version 330 core
  2. layout (location = 0) in vec3 aPos;
  3. layout (location = 1) in vec3 aColor;
  4. layout (location = 2) in vec2 aTexCoord;
  5. out vec3 ourColor;
  6. out vec2 TexCoord;
  7. uniform mat4 transform;
  8. void main()
  9. {
  10. gl_Position = transform * vec4(aPos, 1.0);
  11. ourColor = aColor;
  12. TexCoord = aTexCoord;
  13. }

将变换矩阵输入到GPU:

  1. glUniformMatrix4fv(glGetUniformLocation(ourShader.ID, "transform"), 1, GL_FALSE, glm::value_ptr(trans));

如果顺利的话,结果如下:

4. 完整代码

主要文件test.cpp

  1. #include <glad/glad.h>
  2. #include <GLFW/glfw3.h>
  3. #include <iostream>
  4. #include <math.h>
  5. #include "Shader.hpp"
  6. #define STB_IMAGE_IMPLEMENTATION
  7. #include "stb_image.h"
  8. #include <glm/glm.hpp>
  9. #include <glm/gtc/matrix_transform.hpp>
  10. #include <glm/gtc/type_ptr.hpp>
  11. void framebuffer_size_callback(GLFWwindow *window, int width, int height);
  12. void process_input(GLFWwindow *window);
  13. unsigned int *renderInit();
  14. void render(unsigned int shaderProgram, unsigned int VAO, unsigned int texture1, unsigned int texture2);
  15. bool checkCompile(unsigned int shader);
  16. bool checkProgram(unsigned int shaderProgram);
  17. int main()
  18. {
  19. glfwInit();
  20. glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
  21. glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
  22. GLFWwindow *window = glfwCreateWindow(800, 600, "transformation", nullptr, nullptr);
  23. if (window == nullptr)
  24. {
  25. std::cout << "Faild to create window" << std::endl;
  26. glfwTerminate();
  27. }
  28. glfwMakeContextCurrent(window);
  29. if (!gladLoadGLLoader((GLADloadproc)glfwGetProcAddress))
  30. {
  31. std::cout << "Faild to initialize glad" << std::endl;
  32. return -1;
  33. }
  34. glad_glViewport(0, 0, 800, 600);
  35. glfwSetFramebufferSizeCallback(window, framebuffer_size_callback);
  36. unsigned int *arr = renderInit();
  37. while (!glfwWindowShouldClose(window))
  38. {
  39. process_input(window);
  40. glm::mat4 trans = glm::mat4(1.0f);
  41. trans = glm::translate(trans, glm::vec3(0.5f, -0.5f, 0.0f)*(float)sin(glfwGetTime()));
  42. trans = glm::rotate(trans, (float)glfwGetTime(), glm::vec3(0.0f, 0.0f, 1.0f));
  43. trans = glm::scale(trans, glm::vec3(1.0f, 1.0f, 0.0f)*(float)(sin(glfwGetTime()) * 0.5 + 0.5));
  44. glUniformMatrix4fv(glGetUniformLocation(arr[0], "transform"), 1, GL_FALSE, glm::value_ptr(trans));
  45. // render
  46. std::cout << arr[0] << " " << arr[1] << " " << arr[2] << " " << arr[3] << " " << arr[4] << std::endl;
  47. render(arr[0], arr[1], arr[3], arr[4]);
  48. glfwSwapBuffers(window);
  49. glfwPollEvents();
  50. }
  51. glDeleteProgram(arr[0]);
  52. glDeleteVertexArrays(1, &arr[1]);
  53. glDeleteBuffers(1, &arr[2]);
  54. glfwTerminate();
  55. return 0;
  56. }
  57. void framebuffer_size_callback(GLFWwindow *window, int width, int height)
  58. {
  59. glViewport(0, 0, width, height);
  60. }
  61. void process_input(GLFWwindow *window)
  62. {
  63. if (glfwGetKey(window, GLFW_KEY_ESCAPE) == GLFW_PRESS)
  64. {
  65. glfwSetWindowShouldClose(window, true);
  66. }
  67. }
  68. unsigned int *renderInit()
  69. {
  70. unsigned int VAO;
  71. glGenVertexArrays(1, &VAO);
  72. glBindVertexArray(VAO);
  73. unsigned int texture1;
  74. glGenTextures(1, &texture1);
  75. glBindTexture(GL_TEXTURE_2D, texture1);
  76. // 为当前绑定的纹理对象设置环绕、过滤方式
  77. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
  78. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
  79. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
  80. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
  81. // 加载并生成纹理
  82. int width, height, nrChannels;
  83. unsigned char *data = stbi_load("../container.jpg", &width, &height, &nrChannels, 0);
  84. if (data)
  85. {
  86. glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, data);
  87. glGenerateMipmap(GL_TEXTURE_2D);
  88. }
  89. else
  90. {
  91. std::cout << "Failed to load texture" << std::endl;
  92. }
  93. stbi_image_free(data);
  94. unsigned int texture2;
  95. glGenTextures(1, &texture2);
  96. glBindTexture(GL_TEXTURE_2D, texture2);
  97. // 为当前绑定的纹理对象设置环绕、过滤方式
  98. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
  99. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
  100. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
  101. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
  102. // // 加载并生成纹理
  103. int width2, height2, nrChannels2;
  104. stbi_set_flip_vertically_on_load(true);
  105. unsigned char *data2 = stbi_load("../awesomeface.png", &width2, &height2, &nrChannels2, 0);
  106. if (data2)
  107. {
  108. glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width2, height2, 0, GL_RGBA, GL_UNSIGNED_BYTE, data2);
  109. glGenerateMipmap(GL_TEXTURE_2D);
  110. }
  111. else
  112. {
  113. std::cout << "Failed to load texture" << std::endl;
  114. }
  115. stbi_image_free(data2);
  116. float vertices[] = {
  117. // ---- 位置 ---- ---- 颜色 ---- - 纹理坐标 -
  118. 0.5f, 0.5f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f, // 右上
  119. 0.5f, -0.5f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f, // 右下
  120. -0.5f, -0.5f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, // 左下
  121. -0.5f, 0.5f, 0.0f, 1.0f, 1.0f, 0.0f, 0.0f, 1.0f // 左上
  122. };
  123. unsigned int VBO;
  124. glGenBuffers(1, &VBO);
  125. glBindBuffer(GL_ARRAY_BUFFER, VBO);
  126. glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
  127. unsigned int indices[] = {
  128. 0, 1, 3, // first triangle
  129. 1, 2, 3 // second triangle
  130. };
  131. unsigned int EBO;
  132. glGenBuffers(1, &EBO);
  133. glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO);
  134. glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_STATIC_DRAW);
  135. glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 8 * sizeof(float), (void *)0);
  136. glEnableVertexAttribArray(0);
  137. glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 8 * sizeof(float), (void *)(3 * sizeof(float)));
  138. glEnableVertexAttribArray(1);
  139. glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, 8 * sizeof(float), (void *)(6 * sizeof(float)));
  140. glEnableVertexAttribArray(2);
  141. Shader shaderProgram = Shader("../test.vs.glsl", "../test.fs.glsl");
  142. shaderProgram.use();
  143. glUniform1i(glGetUniformLocation(shaderProgram.ID, "texture1"), 0);
  144. glUniform1i(glGetUniformLocation(shaderProgram.ID, "texture2"), 1);
  145. return new unsigned int[5]{shaderProgram.ID, VAO, VBO, texture1, texture2};
  146. }
  147. void render(unsigned int shaderProgram, unsigned int VAO, unsigned int texture1, unsigned int texture2)
  148. {
  149. glClearColor(0.2, 0.3, 0.3, 1.0);
  150. glClear(GL_COLOR_BUFFER_BIT);
  151. glActiveTexture(GL_TEXTURE0);
  152. glBindTexture(GL_TEXTURE_2D, texture1);
  153. glActiveTexture(GL_TEXTURE1);
  154. glBindTexture(GL_TEXTURE_2D, texture2);
  155. glUseProgram(shaderProgram);
  156. glBindVertexArray(VAO);
  157. glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0);
  158. }

顶点着色器test.vs.glsl

  1. #version 330 core
  2. layout (location = 0) in vec3 aPos;
  3. layout (location = 1) in vec3 aColor;
  4. layout (location = 2) in vec2 aTexCoord;
  5. out vec3 ourColor;
  6. out vec2 TexCoord;
  7. uniform mat4 transform;
  8. void main()
  9. {
  10. gl_Position = transform * vec4(aPos, 1.0);
  11. ourColor = aColor;
  12. TexCoord = aTexCoord;
  13. }

片段着色器test.fs.glsl

  1. #version 330 core
  2. out vec4 FragColor;
  3. in vec3 ourColor;
  4. in vec2 TexCoord;
  5. uniform sampler2D texture1;
  6. uniform sampler2D texture2;
  7. void main()
  8. {
  9. FragColor = mix(texture(texture1, TexCoord), texture(texture2, TexCoord), 0.2);
  10. }

CMake构建文件CMakeLists.txt

  1. cmake_minimum_required(VERSION 3.3)
  2. set(CMAKE_C_STANDARD 11)
  3. set(CMAKE_CXX_STANDARD 14)
  4. project(transformation)
  5. find_package(glfw3 REQUIRED)
  6. find_package( OpenGL REQUIRED )
  7. include_directories( ${OPENGL_INCLUDE_DIRS} lib)
  8. file(GLOB project_file glad.c Shader.hpp test.cpp)
  9. add_executable(${PROJECT_NAME} ${project_file})
  10. target_link_libraries(${PROJECT_NAME} ${OPENGL_LIBRARIES} glfw)

5. 参考资料

[1]变换 - LearnOpenGL CN (learnopengl-cn.github.io)

[2]glm/manual.md at master · g-truc/glm (github.com)

[3]OpenGL学习笔记三——引入GLM库,实现transform_绿洲守望者的博客-CSDN博客_glm库

[4]OpenGL学习笔记(五)纹理 - 知乎 (zhihu.com)

基于C++的OpenGL 04 之变换的更多相关文章

  1. OpenGL 的空间变换(上):矩阵在空间几何中的应用

    在使用 OpenGL 的应用程序中,当我们指定了模型的顶点后,顶点依次会变换到不同的 OpenGL 空间中,最后才会被显示到屏幕上.在变换的过程中,通过使用矩阵,我们更高效地来完成这些变换工作. 本篇 ...

  2. OpenGL 的空间变换(下):空间变换

    通过本文的上篇 OpenGL 的空间变换(上):矩阵在空间几何中的应用 ,我们了解到矩阵的基础概念.并且掌握了矩阵在空间几何中的应用.接下来,我们将结合矩阵来了解 OpenGL 的空间变换. 在使用 ...

  3. 简单理解OpenGL模型视图变换

    前几天学习了OpenGL的绘图原理(其实就是坐标的不停变换变换),看到网上有个比较好的例程,于是学习了下,并在自己感兴趣的部分做了注释. 首先通过glMatrixMode(GL_MODELVIEW)设 ...

  4. 基于Cocos2d-x学习OpenGL ES 2.0系列——纹理贴图(6)

    在上一篇文章中,我们介绍了如何绘制一个立方体,里面涉及的知识点有VBO(Vertex Buffer Object).IBO(Index Buffer Object)和MVP(Modile-View-P ...

  5. opengl中场景变换|2D与3D互转换(转)

    opengl中场景变换|2D与3D互转换 我们生活在一个三维的世界——如果要观察一个物体,我们可以: 1.从不同的位置去观察它.(视图变换) 2.移动或者旋转它,当然了,如果它只是计算机里面的物体,我 ...

  6. 基于Cocos2d-x学习OpenGL ES 2.0之多纹理

    没想到原文出了那么多错别字,实在对不起观众了.介绍opengl es 2.0的不多.相信介绍基于Cocos2d-x学习OpenGL ES 2.0之多纹理的,我是独此一家吧.~~ 子龙山人出了一个系列: ...

  7. 基于Cocos2d-x学习OpenGL ES 2.0系列——使用VBO索引(4)

    在上一篇文章中,我们介绍了uniform和模型-视图-投影变换,相信大家对于OpenGL ES 2.0应该有一点感觉了.在这篇文章中,我们不再画三角形了,改为画四边形.下篇教程,我们就可以画立方体了, ...

  8. 基于Ubuntu Server 16.04 LTS版本安装和部署Django之(五):测试项目

    基于Ubuntu Server 16.04 LTS版本安装和部署Django之(一):安装Python3-pip和Django 基于Ubuntu Server 16.04 LTS版本安装和部署Djan ...

  9. 基于Ubuntu Server 16.04 LTS版本安装和部署Django之(四):安装MySQL数据库

    基于Ubuntu Server 16.04 LTS版本安装和部署Django之(一):安装Python3-pip和Django 基于Ubuntu Server 16.04 LTS版本安装和部署Djan ...

  10. 基于Ubuntu Server 16.04 LTS版本安装和部署Django之(三):设置上传文件夹权限(这里测试用完全共享)

    基于Ubuntu Server 16.04 LTS版本安装和部署Django之(一):安装Python3-pip和Django 基于Ubuntu Server 16.04 LTS版本安装和部署Djan ...

随机推荐

  1. 5V升压8.4V,5V转8.4芯片电路图

    PW5300是电流模式升压DC-DC转换器.其内置0.2Ω功率MOSFET的PWM电路使该稳压器具有效高的功率效率.内部补偿网络还可以程度地减少了6个外部元件的数量.误差放大器的同相输入接到0.6V精 ...

  2. python3中的常见知识点2

    python3中的常见知识点2 列表与栈和队列 map()函数 python列表遍历的4种方式 参考链接 列表栈和队列 1.列表作为栈使用 栈:先进后出,First In Last Out 使用 ap ...

  3. 利用python数据分析

    利用python进行数据分析 本书由Python pandas项目创始人Wes McKinney亲笔撰写,详细介绍利用Python进行操作.处理.清洗和规整数据等方面的具体细节和基本要点.第2版针对P ...

  4. 模板层之标签 自定义过滤器及标签 模板的继承与导入 模型层之前期准备 ORM常用关键字

    目录 模板层之标签 if判断 for循环 自定义过滤器.标签及inclusion_tag(了解) 前期三步骤 自定义过滤器(最大只能接收两个参数) 自定义标签(参数没有限制) 自定义inclusion ...

  5. for循环结构、range方法

    目录 今日内容总结 whlie补充说明 for循环结构 range方法 练习 今日内容总结 whlie补充说明 1.死循环 真正死循环是一旦执行 CPU功耗会急速上升 直到系统采取紧急措施 尽量不要让 ...

  6. Jmeter 之 If 逻辑控制器

    在Jmeter 中如要在某种场景中才执行特殊请求,此时可用If 逻辑控制器来实现. If 逻辑控制器顾名思义当符合某个条件时则执行,添加路径:测试计划->线程组->逻辑控制器->if ...

  7. 基于 Traefik 的激进 TLS 安全配置实践

    前言 Traefik是一个现代的HTTP反向代理和负载均衡器,使部署微服务变得容易. Traefik可以与现有的多种基础设施组件(Docker.Swarm模式.Kubernetes.Marathon. ...

  8. Spark详解(01) - Scala编程语言

    Spark详解(01) - Scala编程语言概述 Scala官网:https://www.scala-lang.org/ 什么是Scala 从英文的角度来讲,Scala并不是一个单词,而是Scala ...

  9. 【白话模电1】PN结与二极管

    距离上一次写半导体,已经过了很久了,上次分享了本征半导体的基本概念: https://zhuanlan.zhihu.com/p/109483580 今天给大家聊聊半导体工业中的基础:PN结与二极管 1 ...

  10. P8474 「GLR-R3」立春

    简要题意 \(\tau(\sigma)\) 表示排列 \(\sigma\) 的逆序对个数,求: \[\sum_{i \in \operatorname{permutation(n)}}2^{\tau( ...