基于C++的OpenGL 04 之变换
1. 概述
本文基于C++语言,描述OpenGL的变换
前置知识可参考:
笔者这里不过多描述每个名词、函数和细节,更详细的文档可以参考:
2. 导入GLM
平移、旋转、缩放等变换主要是使用变换矩阵来实现
OpenGL Mathematics(GLM)是一个基于GLSL的只有头文件的C++数学运算库
GLM的GitHub站点为:g-truc/glm: OpenGL Mathematics (GLM) (github.com)
使用GLM只需将其头文件的根目录包含到工程目录中即可
笔者这里使用的是CMake进行构建,所以只需将GLM目录使用CMake语句进行包含即可:
include_directories(lib)
- 笔者将GLM头文件的根目录放置在工程文件夹下的的
lib
目录 - Windows平台上使用VS的可以参考:OpenGL学习笔记三——引入GLM库,实现transform_绿洲守望者的博客-CSDN博客_glm库
引入头文件:
#include <glm/glm.hpp>
#include <glm/gtc/matrix_transform.hpp>
#include <glm/gtc/type_ptr.hpp>
3. 设置变换矩阵
设置一个平移、旋转、缩放的矩阵:
glm::mat4 trans = glm::mat4(1.0f);
trans = glm::translate(trans, glm::vec3(0.5f, -0.5f, 0.0f)*(float)sin(glfwGetTime()));
trans = glm::rotate(trans, (float)glfwGetTime(), glm::vec3(0.0f, 0.0f, 1.0f));
trans = glm::scale(trans, glm::vec3(1.0f, 1.0f, 0.0f)*(float)(sin(glfwGetTime()) * 0.5 + 0.5));
在顶点着色器中将变换矩阵与坐标结合:
#version 330 core
layout (location = 0) in vec3 aPos;
layout (location = 1) in vec3 aColor;
layout (location = 2) in vec2 aTexCoord;
out vec3 ourColor;
out vec2 TexCoord;
uniform mat4 transform;
void main()
{
gl_Position = transform * vec4(aPos, 1.0);
ourColor = aColor;
TexCoord = aTexCoord;
}
将变换矩阵输入到GPU:
glUniformMatrix4fv(glGetUniformLocation(ourShader.ID, "transform"), 1, GL_FALSE, glm::value_ptr(trans));
如果顺利的话,结果如下:
4. 完整代码
主要文件test.cpp
:
#include <glad/glad.h>
#include <GLFW/glfw3.h>
#include <iostream>
#include <math.h>
#include "Shader.hpp"
#define STB_IMAGE_IMPLEMENTATION
#include "stb_image.h"
#include <glm/glm.hpp>
#include <glm/gtc/matrix_transform.hpp>
#include <glm/gtc/type_ptr.hpp>
void framebuffer_size_callback(GLFWwindow *window, int width, int height);
void process_input(GLFWwindow *window);
unsigned int *renderInit();
void render(unsigned int shaderProgram, unsigned int VAO, unsigned int texture1, unsigned int texture2);
bool checkCompile(unsigned int shader);
bool checkProgram(unsigned int shaderProgram);
int main()
{
glfwInit();
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
GLFWwindow *window = glfwCreateWindow(800, 600, "transformation", nullptr, nullptr);
if (window == nullptr)
{
std::cout << "Faild to create window" << std::endl;
glfwTerminate();
}
glfwMakeContextCurrent(window);
if (!gladLoadGLLoader((GLADloadproc)glfwGetProcAddress))
{
std::cout << "Faild to initialize glad" << std::endl;
return -1;
}
glad_glViewport(0, 0, 800, 600);
glfwSetFramebufferSizeCallback(window, framebuffer_size_callback);
unsigned int *arr = renderInit();
while (!glfwWindowShouldClose(window))
{
process_input(window);
glm::mat4 trans = glm::mat4(1.0f);
trans = glm::translate(trans, glm::vec3(0.5f, -0.5f, 0.0f)*(float)sin(glfwGetTime()));
trans = glm::rotate(trans, (float)glfwGetTime(), glm::vec3(0.0f, 0.0f, 1.0f));
trans = glm::scale(trans, glm::vec3(1.0f, 1.0f, 0.0f)*(float)(sin(glfwGetTime()) * 0.5 + 0.5));
glUniformMatrix4fv(glGetUniformLocation(arr[0], "transform"), 1, GL_FALSE, glm::value_ptr(trans));
// render
std::cout << arr[0] << " " << arr[1] << " " << arr[2] << " " << arr[3] << " " << arr[4] << std::endl;
render(arr[0], arr[1], arr[3], arr[4]);
glfwSwapBuffers(window);
glfwPollEvents();
}
glDeleteProgram(arr[0]);
glDeleteVertexArrays(1, &arr[1]);
glDeleteBuffers(1, &arr[2]);
glfwTerminate();
return 0;
}
void framebuffer_size_callback(GLFWwindow *window, int width, int height)
{
glViewport(0, 0, width, height);
}
void process_input(GLFWwindow *window)
{
if (glfwGetKey(window, GLFW_KEY_ESCAPE) == GLFW_PRESS)
{
glfwSetWindowShouldClose(window, true);
}
}
unsigned int *renderInit()
{
unsigned int VAO;
glGenVertexArrays(1, &VAO);
glBindVertexArray(VAO);
unsigned int texture1;
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);
// 加载并生成纹理
int width, height, nrChannels;
unsigned char *data = stbi_load("../container.jpg", &width, &height, &nrChannels, 0);
if (data)
{
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, data);
glGenerateMipmap(GL_TEXTURE_2D);
}
else
{
std::cout << "Failed to load texture" << std::endl;
}
stbi_image_free(data);
unsigned int texture2;
glGenTextures(1, &texture2);
glBindTexture(GL_TEXTURE_2D, texture2);
// 为当前绑定的纹理对象设置环绕、过滤方式
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 width2, height2, nrChannels2;
stbi_set_flip_vertically_on_load(true);
unsigned char *data2 = stbi_load("../awesomeface.png", &width2, &height2, &nrChannels2, 0);
if (data2)
{
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width2, height2, 0, GL_RGBA, GL_UNSIGNED_BYTE, data2);
glGenerateMipmap(GL_TEXTURE_2D);
}
else
{
std::cout << "Failed to load texture" << std::endl;
}
stbi_image_free(data2);
float vertices[] = {
// ---- 位置 ---- ---- 颜色 ---- - 纹理坐标 -
0.5f, 0.5f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f, // 右上
0.5f, -0.5f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f, // 右下
-0.5f, -0.5f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, // 左下
-0.5f, 0.5f, 0.0f, 1.0f, 1.0f, 0.0f, 0.0f, 1.0f // 左上
};
unsigned int VBO;
glGenBuffers(1, &VBO);
glBindBuffer(GL_ARRAY_BUFFER, VBO);
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
unsigned int indices[] = {
0, 1, 3, // first triangle
1, 2, 3 // second triangle
};
unsigned int EBO;
glGenBuffers(1, &EBO);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_STATIC_DRAW);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 8 * sizeof(float), (void *)0);
glEnableVertexAttribArray(0);
glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 8 * sizeof(float), (void *)(3 * sizeof(float)));
glEnableVertexAttribArray(1);
glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, 8 * sizeof(float), (void *)(6 * sizeof(float)));
glEnableVertexAttribArray(2);
Shader shaderProgram = Shader("../test.vs.glsl", "../test.fs.glsl");
shaderProgram.use();
glUniform1i(glGetUniformLocation(shaderProgram.ID, "texture1"), 0);
glUniform1i(glGetUniformLocation(shaderProgram.ID, "texture2"), 1);
return new unsigned int[5]{shaderProgram.ID, VAO, VBO, texture1, texture2};
}
void render(unsigned int shaderProgram, unsigned int VAO, unsigned int texture1, unsigned int texture2)
{
glClearColor(0.2, 0.3, 0.3, 1.0);
glClear(GL_COLOR_BUFFER_BIT);
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, texture1);
glActiveTexture(GL_TEXTURE1);
glBindTexture(GL_TEXTURE_2D, texture2);
glUseProgram(shaderProgram);
glBindVertexArray(VAO);
glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0);
}
顶点着色器test.vs.glsl
:
#version 330 core
layout (location = 0) in vec3 aPos;
layout (location = 1) in vec3 aColor;
layout (location = 2) in vec2 aTexCoord;
out vec3 ourColor;
out vec2 TexCoord;
uniform mat4 transform;
void main()
{
gl_Position = transform * vec4(aPos, 1.0);
ourColor = aColor;
TexCoord = aTexCoord;
}
片段着色器test.fs.glsl
:
#version 330 core
out vec4 FragColor;
in vec3 ourColor;
in vec2 TexCoord;
uniform sampler2D texture1;
uniform sampler2D texture2;
void main()
{
FragColor = mix(texture(texture1, TexCoord), texture(texture2, TexCoord), 0.2);
}
CMake构建文件CMakeLists.txt
:
cmake_minimum_required(VERSION 3.3)
set(CMAKE_C_STANDARD 11)
set(CMAKE_CXX_STANDARD 14)
project(transformation)
find_package(glfw3 REQUIRED)
find_package( OpenGL REQUIRED )
include_directories( ${OPENGL_INCLUDE_DIRS} lib)
file(GLOB project_file glad.c Shader.hpp test.cpp)
add_executable(${PROJECT_NAME} ${project_file})
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 之变换的更多相关文章
- OpenGL 的空间变换(上):矩阵在空间几何中的应用
在使用 OpenGL 的应用程序中,当我们指定了模型的顶点后,顶点依次会变换到不同的 OpenGL 空间中,最后才会被显示到屏幕上.在变换的过程中,通过使用矩阵,我们更高效地来完成这些变换工作. 本篇 ...
- OpenGL 的空间变换(下):空间变换
通过本文的上篇 OpenGL 的空间变换(上):矩阵在空间几何中的应用 ,我们了解到矩阵的基础概念.并且掌握了矩阵在空间几何中的应用.接下来,我们将结合矩阵来了解 OpenGL 的空间变换. 在使用 ...
- 简单理解OpenGL模型视图变换
前几天学习了OpenGL的绘图原理(其实就是坐标的不停变换变换),看到网上有个比较好的例程,于是学习了下,并在自己感兴趣的部分做了注释. 首先通过glMatrixMode(GL_MODELVIEW)设 ...
- 基于Cocos2d-x学习OpenGL ES 2.0系列——纹理贴图(6)
在上一篇文章中,我们介绍了如何绘制一个立方体,里面涉及的知识点有VBO(Vertex Buffer Object).IBO(Index Buffer Object)和MVP(Modile-View-P ...
- opengl中场景变换|2D与3D互转换(转)
opengl中场景变换|2D与3D互转换 我们生活在一个三维的世界——如果要观察一个物体,我们可以: 1.从不同的位置去观察它.(视图变换) 2.移动或者旋转它,当然了,如果它只是计算机里面的物体,我 ...
- 基于Cocos2d-x学习OpenGL ES 2.0之多纹理
没想到原文出了那么多错别字,实在对不起观众了.介绍opengl es 2.0的不多.相信介绍基于Cocos2d-x学习OpenGL ES 2.0之多纹理的,我是独此一家吧.~~ 子龙山人出了一个系列: ...
- 基于Cocos2d-x学习OpenGL ES 2.0系列——使用VBO索引(4)
在上一篇文章中,我们介绍了uniform和模型-视图-投影变换,相信大家对于OpenGL ES 2.0应该有一点感觉了.在这篇文章中,我们不再画三角形了,改为画四边形.下篇教程,我们就可以画立方体了, ...
- 基于Ubuntu Server 16.04 LTS版本安装和部署Django之(五):测试项目
基于Ubuntu Server 16.04 LTS版本安装和部署Django之(一):安装Python3-pip和Django 基于Ubuntu Server 16.04 LTS版本安装和部署Djan ...
- 基于Ubuntu Server 16.04 LTS版本安装和部署Django之(四):安装MySQL数据库
基于Ubuntu Server 16.04 LTS版本安装和部署Django之(一):安装Python3-pip和Django 基于Ubuntu Server 16.04 LTS版本安装和部署Djan ...
- 基于Ubuntu Server 16.04 LTS版本安装和部署Django之(三):设置上传文件夹权限(这里测试用完全共享)
基于Ubuntu Server 16.04 LTS版本安装和部署Django之(一):安装Python3-pip和Django 基于Ubuntu Server 16.04 LTS版本安装和部署Djan ...
随机推荐
- 干电池升压5V,功耗比较低
干电池升压5V,功耗10uA PW5100干电池升压5V芯片 输出电容: 所以为了减小输出的纹波,需要比较大的输出电容值.但是输出电容过大,就会使得系统的 反应时间过慢,成本也会增加.所以建议使用一个 ...
- Qt从实习到搬砖
Qt C++ 工具箱 从零开始的Qt开发之路 里面大概会写一些和Qt相关的内容,也不说是从0开始,感觉Qt做东西和用 C#也差不了很多?也许吧,总之慢慢来,一步一个脚印,直到给它拿下. 2022.5. ...
- react 高效高质量搭建后台系统 系列 —— 脚手架搭建
其他章节请看: react 高效高质量搭建后台系统 系列 脚手架搭建 本篇主要创建新项目 myspug,以及准备好环境(例如:安装 spug 中用到的包.本地开发和部署.自定义配置 react-app ...
- Kagol:2022年最值得推荐的前端开源文章
大家好,我是 Kagol,Vue DevUI 作者,从2020年开始一直专注于前端开源组件库的建设,在前端开源组件库.开源社区运营方面积累了一些经验,2020年主要的创作也是围绕前端组件库和开源两个主 ...
- CSP-S2022 游记
Day 998244350 模拟赛场场被学弟吊打.最后几天写了一堆随机化乱搞题以及奇怪的搜索,都是 CSP 不曾考的玩意(书接下文). 点分治已经敲烂了.最后两场每场一个. Day 499122175 ...
- Web初级——数组对象常用api
js数组常用api 连接函数:join("连接符") var array = [1,2,3,4,5] console.log(array.join("+")) ...
- 二十一、B树的定义、查找、插入和删除
一.B树的定义 一棵m阶的B树,或为空树,或为满足下列特性的m叉树: (1)树中每个结点至多有m棵子树:(2)B树是所有结点的平衡因子均等于0的多路平衡查找树:(3)若根结点不是叶子结点,则至少有两棵 ...
- 最好用的在线图片压缩工具——TinyPNG
前言 不知道大家在写博客或者工作时有没有这种烦恼呢?想要上传某张图片,但却因为图片文件过大而导致无法上传.这时你可能会去百度搜索关于图片压缩的软件,但往往下载的软件都是那种"垃圾软件&quo ...
- HelloWorld的常见问题与Notepad++使用-程序注释与Hello World说明
HelloWorld的常见问题与Notepad++使用 编译和运行是两回事 编译:是指将我们编写的Java源文件翻译成JVM认识的class文件,在这个过程中, javac 编译器会检查我们 所写的程 ...
- 笔记:C#Quart帮助类 定时器 拿来即用
using Quartz.Impl; using Quartz.Impl.Triggers; using System; using System.Collections.Generic; using ...