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)

引入头文件:

#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 之变换的更多相关文章

  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. 像go 一样 打造.NET 单文件应用程序的编译器项目bflat 发布 7.0版本

    现代.NET和C#在低级/系统程序以及与C/C++/Rust等互操作方面的能力完全令各位刮目相看了,有人用C#开发的64位操作系统: GitHub - nifanfa/MOOS: C# x64 ope ...

  2. Qt对象跨线程出现的问题记录,以及解决方案

    Qt在跨线程开发的时候可能会出现不少问题,在这里记录一下 Qt目前用下来还是非常强大的,虽然只是用在桌面端程序开发上,但是其强大的桌面开发库真的挺好用的(Layout除外,你妈死了). Qt除了UI, ...

  3. 软件开发目录规范、python常用内置模块

    编程思想的转变 1.面条版阶段 所有的代码全部堆叠在一起.可以看成是直接将所有的数据放在C盘        视频.音频.文本.图片 2.函数版阶段 根据功能的不同封装不同的函数.可以看成是将C盘下的数 ...

  4. 教你用JavaScript实现计数器

    案例介绍 欢迎来到我的小院,我是霍大侠,恭喜你今天又要进步一点点了!我们来用JavaScript编程实战案例,做一个计数器.点击按钮数字改变,点击重置数字归0.通过实战我们将学会forEach循环.c ...

  5. day11-功能实现10

    家居网购项目实现010 以下皆为部分代码,详见 https://github.com/liyuelian/furniture_mall.git 24.bugFix-添加购物车按钮动态处理 24.1需求 ...

  6. python3使用OCR识别图片

    放假三天,闲来无事,想学下python爬虫.本想跟着网上教程操作一遍,奈何安装使用过程中出现一堆问题,并且在网上搜了一堆复制黏贴的答案,关键都不能起作用,最后终于找到一篇生效,为了以后不至于再经历这种 ...

  7. [OpenCV实战]52 在OpenCV中使用颜色直方图

    颜色直方图是一种常见的图像特征,顾名思义颜色直方图就是用来反映图像颜色组成分布的直方图.颜色直方图的横轴表示像素值或像素值范围,纵轴表示该像素值范围内像素点的个数或出现频率.颜色直方图属于计算机视觉中 ...

  8. 单向绑定vs双向绑定、单向数据流vs双向数据流

    参考文章:http://www.qb5200.com/article/482839.html 单双向绑定指的是View层跟Model层之间的映射关系 单向绑定vs双向绑定 react采用单向绑定,vu ...

  9. 模板层之标签、自定义模板语法、母版(模版)的继承与导入、模型层前期准备知识点、ORM常用关键字

    今日内容概要 模板层之标签 if判断 {% if 条件1 %} #条件1成立 <p>Hello!</p> #执行 {% elif 条件2 %} #条件1不成立 条件2成立 &l ...

  10. Coolify系列-解决WARNING: IPv4 forwarding is disabled. Networking will not work.以及开启防火墙端口

    背景 我在windows电脑安装了一个VM,使用VM开启了Linux服务器,运行docker,然后遇到了这个报错. 解决 首先:在宿主机上执行 echo "net.ipv4.ip_forwa ...