OpenGL(五)——变换

news2024/11/24 15:00:48

目录

一、前言

二、向量

三、矩阵

 四、旋转的箱子

4.1 GLM库

 4.2 构建


一、前言

前面了解渲染架构中uniform可以传递矩阵变换,如从RGBA到YUV,同时它也可以使物体通过矩阵变换动起来。

 

二、向量

向量是包含方向和大小的矢量,平面2D坐标可以看作在3D坐标系下Z坐标为0的向量,已知起始点向终点画出一条指向性箭头。标量只是一个数字,没有方向。

向量加减:

                                           

 点乘:两个向量的点乘等于它们的数乘结果乘以两个向量之间夹角的余弦值

 叉乘:运算结果是一个向量,并且与这两个向量都垂直,是这两个向量所在平面的法线向量。如果输入的两个向量也是正交的,那么叉乘之后将会产生3个互相正交的向量。

 使用右手定则确定其方向

 

 三维向量叉乘

 

 

三、矩阵

单位矩阵:除了对角线外都是0的NxN矩阵,特性是这种变换使一个向量完全不变:

缩放

 位移:

 旋转:在3D空间中需要定义一个角和一个旋转轴。当2D向量在3D空间中旋转时,把旋转轴设为Z轴。

沿x轴旋转:

 沿y轴旋转:

 沿Z轴旋转:

 四、旋转的箱子

4.1 GLM库

GLM是OpenGL Mathematics 也是头文件库,下载地址这里。GLM支持向量、矩阵、变换运算

 4.2 构建

逆时针旋转90度,缩放0.5倍

glm::mat4 trans;
trans = glm::rotate(trans, glm::radians(90.0f), glm::vec3(0.0, 0.0, 1.0));
trans = glm::scale(trans, glm::vec3(0.5, 0.5, 0.5));

增加uniform变量,将旋转矩阵传入到顶点着色器中:

#version 330 core
layout (location = 0) in vec3 aPos;
layout (location = 1) in vec2 aTexCoord;

out vec2 TexCoord;

uniform mat4 transform;

void main()
{
    gl_Position = transform * vec4(aPos, 1.0f);
    TexCoord = vec2(aTexCoord.x, 1.0 - aTexCoord.y);
}

将变换矩阵转化为transform变量:

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

/*
参数1:uniform位置
参数2:发送几个矩阵
参数3:是否转置 , (列排序)
参数4:矩阵数据,使用value_ptr变换数据
*/

 源码:

#include <iostream>
#include <string>

#include "glad.h"
#include "GL/glfw3.h"
#include "Shader.h"
#define STB_IMAGE_IMPLEMENTATION
#include "stb_image.h"
#include <glm/glm.hpp>
#include <glm/gtc/matrix_transform.hpp>
#include <glm/gtc/type_ptr.hpp>

// settings
const unsigned int SCR_WIDTH = 800;
const unsigned int SCR_HEIGHT = 600;

// process all input: query GLFW whether relevant keys are pressed/released this frame and react accordingly
// ---------------------------------------------------------------------------------------------------------
void processInput(GLFWwindow* window)
{
    if (glfwGetKey(window, GLFW_KEY_ESCAPE) == GLFW_PRESS)
        glfwSetWindowShouldClose(window, true);
}

// glfw: whenever the window size changed (by OS or user resize) this callback function executes
// ---------------------------------------------------------------------------------------------
void framebuffer_size_callback(GLFWwindow* window, int width, int height)
{
    // make sure the viewport matches the new window dimensions; note that width and 
    // height will be significantly larger than specified on retina displays.
    glViewport(0, 0, width, height);
}

int main()
{
    // glfw: 初始化、配置
    // ------------------------------
    glfwInit();
    glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
    glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
    glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);

#ifdef __APPLE__
    glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE);
#endif
    // glfw: 创建窗口、绑定回调
    // --------------------
    GLFWwindow* window = glfwCreateWindow(SCR_WIDTH, SCR_HEIGHT, "LearnOpenGL", NULL, NULL);
    if (window == NULL)
    {
        std::cout << "Failed to create GLFW window" << std::endl;
        glfwTerminate();
        return -1;
    }
    glfwMakeContextCurrent(window);
    glfwSetFramebufferSizeCallback(window, framebuffer_size_callback);
    // glad: 加载OpenGL相关函数指针
    // ---------------------------------------
    if (!gladLoadGLLoader((GLADloadproc)glfwGetProcAddress))
    {
        std::cout << "Failed to initialize GLAD" << std::endl;
        return -1;
    }
    // 构建、编译着色器
    // ------------------------------------
    Shader ourShader("vertexTexture.vs", "fragmentTexture.fms");
    // 顶点数据
    // ------------------------------------------------------------------
    float vertices[] = {
        // 位置               // 颜色             // 纹理坐标
         0.5f,  0.5f, 0.0f,   1.0f, 0.0f, 0.0f,   1.0f, 1.0f, // top right
         0.5f, -0.5f, 0.0f,   0.0f, 1.0f, 0.0f,   1.0f, 0.0f, // bottom right
        -0.5f, -0.5f, 0.0f,   0.0f, 0.0f, 1.0f,   0.0f, 0.0f, // bottom left
        -0.5f,  0.5f, 0.0f,   1.0f, 1.0f, 0.0f,   0.0f, 1.0f  // top left 
    };
    unsigned int indices[] = {
        0, 1, 3, // 第一个三角形
        1, 2, 3  // 第二个三角形
    };
    //创建顶点对象
    unsigned int VAO, VBO, EBO;
    glGenVertexArrays(1, &VAO);//顶点数组
    glGenBuffers(1, &VBO);//数据缓存
    glGenBuffers(1, &EBO);//数据缓存
    //绑定数据
    glBindVertexArray(VAO);
    glBindBuffer(GL_ARRAY_BUFFER, VBO);
    glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
    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);
    //创建纹理对象1
    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_MIPMAP_LINEAR);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
    //加载图片1到纹理数据
    int width, height, nrChannels;
    unsigned char* data = stbi_load(std::string("container.jpg").c_str(), &width, &height, &nrChannels, 0);
    if (data)
    {
        //加载数据,生成OpenGL纹理图
        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);
    //创建纹理对象2
    unsigned int texture2;
    // texture 2
// ---------
    glGenTextures(1, &texture2);
    glBindTexture(GL_TEXTURE_2D, texture2);
    // set the texture wrapping parameters
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);	// set texture wrapping to GL_REPEAT (default wrapping method)
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
    // set texture filtering parameters
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
    // load image, create texture and generate mipmaps
    stbi_set_flip_vertically_on_load(true);
    data = stbi_load(std::string("awesomeface.png").c_str(), &width, &height, &nrChannels, 0);
    if (data)
    {
        // note that the awesomeface.png has transparency and thus an alpha channel, so make sure to tell OpenGL the data type is of GL_RGBA
        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);

    //OpenGL解释纹理单元的编号
    ourShader.use(); 
    ourShader.setInt("textur1", 0);
    ourShader.setInt("textur2", 1);

    //旋转90度,缩放0.5倍
    //glm::mat4 trans = glm::mat4(1.0f);
   // trans = glm::rotate(trans, glm::radians(90.0f), glm::vec3(0, 0, 1.0));
    //trans = glm::scale(trans, glm::vec3(0.5, 0.5, 0.5));

    //渲染
    while (!glfwWindowShouldClose(window))
    {
        processInput(window);

        //背景颜色
        glClearColor(0.2f, 0.3f, 0.3f, 1.0f);
        glClear(GL_COLOR_BUFFER_BIT);
        //绑定对应的纹理
        glActiveTexture(GL_TEXTURE0);
        glBindTexture(GL_TEXTURE_2D, texture1);
        glActiveTexture(GL_TEXTURE1);
        glBindTexture(GL_TEXTURE_2D, texture2);
        glm::mat4 trans = glm::mat4(1.0f);
        trans = glm::translate(trans, glm::vec3(0.5f, -0.5f, 0.0f));
        trans = glm::rotate(trans, (float)glfwGetTime(), glm::vec3(0.0f, 0.0f, 1.0f));
        //着色器引用
        ourShader.use();
        unsigned int transformLoc = glGetUniformLocation(ourShader.ID, "transform");
        glUniformMatrix4fv(transformLoc, 1, GL_FALSE, glm::value_ptr(trans));
        //绘图
        glBindVertexArray(VAO);
        glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0);
        /*
        * 
        void glDrawElements(	GLenum mode,
 	    GLsizei count,
 	    GLenum type,
 	    const GLvoid * indices);
        */
        //刷新
        glfwSwapBuffers(window);
        glfwPollEvents();
    }
    //释放缓存资源
    glDeleteVertexArrays(1, &VAO);
    glDeleteBuffers(1, &VBO);
    glDeleteBuffers(1, &EBO);
    //释放glfw资源
    glfwTerminate();

    return 0;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/488836.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

一文吃透Tomcat核心知识点

架构 首先&#xff0c;看一下整个架构图。最全面的Java面试网站 接下来简单解释一下。 Server&#xff1a;服务器。Tomcat 就是一个 Server 服务器。 Service&#xff1a;在服务器中可以有多个 Service&#xff0c;只不过在我们常用的这套 Catalina 容器的Tomcat 中只包含一…

在技术圈超卷的当下,学历到底是敲门砖还是枷锁?

前言 最近&#xff0c;突然之间被“孔乙己文学”刷屏了&#xff0c;短时间内“孔乙己文学”迅速走红&#xff0c;孔乙己是中国文学中的一位经典人物&#xff0c;他的长衫被认为是他的象征之一&#xff0c;孔乙己的长衫折射出很多现象&#xff0c;既有社会的&#xff0c;也有教育…

【Linux】进程信号及信号产生

文章目录 一. 生活层面的信号二. 进程信号三. 硬件中断四. 信号产生五. Term&Core1. 核心转储的意义2. 云服务器为什么关闭核心转储3. core dump标志 六. 总结结束语 一. 生活层面的信号 在学习进程信号前&#xff0c;我们不妨认识一下现实中有哪些信号。 日常生活中&#…

净利润下滑13%,帅丰电器已掉队?

近年来&#xff0c;随着市场竞争加剧&#xff0c;厨电行业加速洗牌&#xff0c;超60%杂牌或被淘汰出局&#xff0c;三类品牌全部被清退。而作为毛利最高的厨电细分市场&#xff0c;集成灶行业吸引了大批企业涌入&#xff0c;市场渗透率快速提升&#xff0c;已经超过30%&#xf…

如何入门数据分析

如何入门数据分析&#xff1f; 随着数字经济、大数据时代的发展&#xff0c;数据已然成为当下时代最重要的盈利资源&#xff0c;让企业在做决策和计划方案时更有针对性和依据&#xff0c;能提前预测市场发展方向&#xff0c;做好布局。由此而产生的数据分析岗位也逐渐被更多企业…

亚马逊、Lazada、阿里国际、eBay、Temu、Ozon好消息不断,机会来了

1. 亚马逊第一季度营收1273.58亿美元 同比扭亏为盈 亚马逊2023财年第一季度财报。亚马逊第一季度净销售额为1273.58亿美元&#xff0c;与上年同期的1164.44亿美元相比增长9%&#xff0c;不计入汇率变动的影响为同比增长11%&#xff1b;净利润为31.72亿美元&#xff0c;上年同期…

“智慧交通”转型升级+创新发展策略

随着“互联网交通”的应用创新推陈出新&#xff0c;传统轨道交通行业客户服务中心已难以满足乘客对便捷高效的客户服务需求&#xff1b;节假日人流量激增&#xff0c;客户服务人手不足&#xff0c;交通、站点堵塞、信息更新不及时等问题是常态。因此&#xff0c;“智慧城市”交…

多租户SAAS系统涉及实战解决方案—案例JeecgBoot低代码平台

JeecgBoot免费低代码平台&#xff0c;提供一键切换多租户模式机制&#xff01;快速实现全系统的saas租户方案&#xff0c;通过租户ID进行数据隔离。 租户设计思路 1、开启全系统租户隔离 开启方法 将 org.jeecg.config.mybatis.MybatisPlusSaasConfig#OPEN_SYSTEM_TENANT_CO…

为什么是三次握手和四次挥手

文章目录 为什么是三次握手为什么是四次挥手什么是TIME_WAIT状态解决TIME_WAIT状态引起的bind失败的方法 为什么是三次握手 因为这是双方都有收发的最小次数 握手的目的&#xff1a;确认网络好着没&#xff0c;对方好着没 确认双方主机是否健康&#xff08;双方&#xff09;…

美国访问学者访问J1签证和商务B1签证的区别

美国校方通常希望他国的访问学者申请访问类签证&#xff08;J1&#xff09;&#xff0c;当然也有很少一部分人以商务签证&#xff08;B1&#xff09;的身份入境&#xff0c;知识人网小编就这两种签证的区别做一下简单介绍。 交流访问学者签证&#xff08;J1&#xff09;旨在促进…

UG NX二次开发(C++)-建模-利用UF_CURVE_ask_line_data()获取直线的矢量

文章目录 1、前言2、总体思路3、代码实现3.1 在视图区选择对象3.2 将选择对象转换为直线对象3.3创建获取直线矢量的函数 4、测试效果 1、前言 选择一条直线&#xff0c;获取直线的矢量方向&#xff0c;采用的是获取直线的数据&#xff0c;并根据直线的首末端点计算矢量方向&am…

【TCP/IP 网络模型】

TCP/IP 网络模型 OSI七层模型、TIP/IP四层模型 OSI七层模型 应用层&#xff0c;负责给应用程序提供统一的接口&#xff1b; 表示层&#xff0c;负责把数据转换成兼容另一个系统能识别的格式&#xff1b; 会话层&#xff0c;负责建立、管理和终止表示层实体之间的通信会话&…

Java基础(十五)集合框架

1. 集合框架概述 1.1 生活中的容器 1.2 数组的特点与弊端 一方面&#xff0c;面向对象语言对事物的体现都是以对象的形式&#xff0c;为了方便对多个对象的操作&#xff0c;就要对对象进行存储。另一方面&#xff0c;使用数组存储对象方面具有一些弊端&#xff0c;而Java 集合…

研报精选230504

目录 【行业230504国联证券】食饮农业2022年报与1Q23季报总结&#xff1a;食饮业绩稳步改善&#xff0c;农业低猪价推动去产能 【行业230504中邮证券】美护行业22年&23Q1财报总结&#xff1a;龙头逆境彰显韧性&#xff0c;期待Q2行业加速 【行业230504安信证券】交通运输行…

3. 内存分区模型

一、内存分区模型 C程序在执行时&#xff0c;将内存大方向划分为4个区域 代码区&#xff1a;存放函数体的二进制代码&#xff0c;由操作系统进行管理的全局区&#xff1a;存放全局变量和静态变量以及常量栈区&#xff1a;由编译器自动分配释放&#xff0c;存放函数的参数值&a…

AI落地:程序员如何用AI?

对于程序员来说&#xff0c;真正能提高效率、可落地的AI应用场景都有哪些&#xff1f; 目前已经能切实落地&#xff0c;融入我日常工作生活的有以下几个场景&#xff1a; 开发工作&#xff1a;自然语言生成代码&#xff0c;自动补全代码 日常工作学习&#xff1a;写作、翻译、…

通达信如何检测未来函数?

未来函数可能引用未来发生的数据&#xff0c;对原来的判断进行修改&#xff0c;这会导致信号漂移&#xff0c;比如产生原来没有的信号、原来的信号改变位置或者已经产生的信号消失。 一、未来函数如何偷梁换柱&#xff1f; 单纯讲概念&#xff0c;对未来函数也没有深刻的认识…

java中Queue、BlockingQueue以及DelayQueue的用法

java中Queue、BlockingQueue以及DelayQueue的用法 一 Queue 的用法Java中Queue的api 二 BlockingQueue 的用法阻塞队列的边界 三 DelayQueue使用DelayQueue常见的应用场景 一 Queue 的用法 Queue(队列)&#xff1a;其特性是先进先出。只允许在表的一端进行插入&#xff0c;而在…

【图像分割】视觉大模型SEEM(Segment Everything Everywhere All at Once)原理解读

文章目录 摘要&#xff08;效果&#xff09;二、前言三、相关工作四、method4.1 多用途4.2 组合性4.3 交互式。4.4 语义感知 五、实验 论文地址&#xff1a;https://arxiv.org/abs/2304.06718 测试代码&#xff1a;https://github.com/UX-Decoder/Segment-Everything-Everywher…

Flask使用Flask-SQLAlchemy对数据库操作详解一(配置、表与表之间一对一、多对一、多对多关系及增删改查参数和代码详细总结)

文章目录 1.先来一个简单的示例2.SQLAlchemy 配置&#xff08;所有的配置都在Flask初始化应用程序之前就执行了&#xff09; 3.声明模型3.1声明模型参数3.2表与表之间的关系&#xff08;详细介绍&#xff09;1.一对一关系2.多对一关系3.多对多关系 1.先来一个简单的示例 from …