首页 > 其他分享 >OpenGL入门——矩阵变换与坐标系统

OpenGL入门——矩阵变换与坐标系统

时间:2023-10-15 21:11:07浏览次数:64  
标签:mat4 1.0 glm OpenGL 变换 矩阵 坐标 入门

一、OpenGL的数学库GLM

向量和矩阵的运算就不作说明了,直接介绍OpenGL中如何使用矩阵变换。

GLM(官网:OpenGL Mathematics (g-truc.net))是OpenGL Mathematics的缩写,它是一个只有头文件的库,也就是说只需包含对应的头文件就行了,不用链接和编译。把头文件的根目录复制到项目的includes文件夹,就可以使用这个库了。

 

GLM大多功能都包含在以下四个头文件中

#include <glm/glm.hpp>
#include <glm/gtc/matrix_transform.hpp>
#include <glm/gtc/type_ptr.hpp>

 

向量位移示例

//向量平移:向量(1, 0, 0)位移(1, 1, 0)个单位
void vector_translate()
{
    glm::vec4 vec(1.0f, 0.0f, 0.0f, 1.0f);//定义一个向量

    glm::mat4 trans = glm::mat4(1.0f);//定义4x4单位矩阵
    trans = glm::translate(trans, glm::vec3(1.0f, 1.0f, 0.0f));//创建位移矩阵:translate函数将给定矩阵乘以位移向量得到位移变换矩阵
    vec = trans * vec;//变换矩阵与向量相乘得到位移后的向量
    std::cout << vec.x << "," << vec.y << "," << vec.z << std::endl;//输出:2,1,0
}

 

上一节OpenGL入门——多个纹理 - 一只小瓶子 - 博客园 (cnblogs.com)进行旋转缩放平移示例

在顶点着色器中将顶点坐标进行旋转缩放

//vertex shader source
#version 330 core
layout(location = 0) in vec3 position;     //位置X,Y,Z
layout(location = 1) in vec3 color;        //颜色R,G,B
layout(location = 2) in vec2 texture;    //纹理S,T

out vec3 vertexColor;    //顶点颜色
out vec2 textureCoord;    //顶点对应纹理坐标

uniform mat4 transform;    //变换矩阵

void main()
{
    gl_Position = transform * vec4(position, 1.0);    //顶点坐标左乘变换矩阵
    vertexColor = color;                //从顶点数据那里得到的输入颜色
    textureCoord = texture;                //从顶点数据那里得到的对应纹理坐标
}

把变换矩阵传递给着色器

    //定义变换矩阵
    glm::mat4 trans = glm::mat4(1.0f);//定义4x4单位矩阵
    trans = glm::translate(trans, glm::vec3(0.5f, -0.5f, 0.0f));//平移到右下角
    trans = glm::scale(trans, glm::vec3(0.5, 0.5, 1.0));//x,y轴缩小到一半
    trans = glm::rotate(trans, glm::radians(90.0f), glm::vec3(0.0f, 0.0f, 1.0f));//绕着z轴旋转90度(参数为弧度值)
    unsigned int transformLoc = glGetUniformLocation(shader.getShaderID(), "transform");//获得着色器中变换矩阵位置
    glUniformMatrix4fv(transformLoc, 1, GL_FALSE, glm::value_ptr(trans));//赋值变换矩阵:因为是左乘变换矩阵,所以是先旋转再缩放再平移

注意变换顺序,因为着色器中顶点是左乘变换矩阵的,所以变换顺序是相反的(先旋转再缩放后平移)

示例效果

 

二、坐标系统

物体的顶点在最终转化为屏幕坐标之前还会被变换到多个坐标系统,将物体的坐标变换到几个过渡坐标系的优点在于,在这些特定的坐标系统中,一些操作或运算更加方便和容易。

5个重要的坐标系统:

  • 局部空间(Local Space,或者称为物体空间(Object Space))
  • 世界空间(World Space)
  • 观察空间(View Space,或者称为视觉空间(Eye Space))
  • 裁剪空间(Clip Space)
  • 屏幕空间(Screen Space)

这就是一个顶点在最终被转化为片段之前需要经历的所有不同状态

  1. 局部坐标是对象相对于局部原点的坐标,也是物体起始的坐标。
  2. 下一步是将局部坐标变换为世界空间坐标,世界空间坐标是处于一个更大的空间范围的。这些坐标相对于世界的全局原点,它们会和其它物体一起相对于世界的原点进行摆放。
  3. 接下来我们将世界坐标变换为观察空间坐标,使得每个坐标都是从摄像机或者说观察者的角度进行观察的。
  4. 坐标到达观察空间之后,我们需要将其投影到裁剪坐标。裁剪坐标会被处理至-1.0到1.0的范围内,并判断哪些顶点将会出现在屏幕上。
  5. 最后,我们将裁剪坐标变换为屏幕坐标,我们将使用一个叫做视口变换(Viewport Transform)的过程。视口变换将位于-1.0到1.0范围的坐标变换到由glViewport函数所定义的坐标范围内。最后变换出来的坐标将会送到光栅器,将其转化为片段。这一阶段在顶点着色器运行的最后被自动执行。

第4步将观察坐标转换为裁剪坐标的方式称为投影,投影的形式有两种:正射投影(类似立方体的平截头箱)和透视投影(近大远小)。

从局部坐标到裁剪坐标的公式:

 

 三、OpenGL 3D

进行3D绘图时,首先在顶点着色器中进行坐标转换

//vertex shader source
#version 330 core
layout(location = 0) in vec3 position;     //位置X,Y,Z
layout(location = 1) in vec3 color;        //颜色R,G,B
layout(location = 2) in vec2 texture;    //纹理S,T

out vec3 vertexColor;    //顶点颜色
out vec2 textureCoord;    //顶点对应纹理坐标

uniform mat4 model;        //模型矩阵矩阵:局部空间->世界空间
uniform mat4 view;        //观察矩阵:世界空间->观察空间
uniform mat4 projection;//透视投射矩阵:观察空间->裁剪空间

void main()
{
    gl_Position = projection * view * model * vec4(position, 1.0);    //顶点坐标变换
    vertexColor = color;                //从顶点数据那里得到的输入颜色
    textureCoord = texture;                //从顶点数据那里得到的对应纹理坐标
}

然后定义变换矩阵传入着色器中

    ///定义变换矩阵
    //模型矩阵矩阵:局部空间->世界空间
    glm::mat4 model = glm::mat4(1.0f);
    model = glm::rotate(model, glm::radians(-55.0f), glm::vec3(1.0f, 0.0f, 0.0f));//绕X轴旋转-55度
    unsigned int transModelLoc = glGetUniformLocation(shader.getShaderID(), "model");//获得变换矩阵位置
    glUniformMatrix4fv(transModelLoc, 1, GL_FALSE, glm::value_ptr(model));//赋值变换矩阵

    //观察矩阵:世界空间->观察空间
    glm::mat4 view = glm::mat4(1.0f);
    view = glm::translate(view, glm::vec3(0.0f, 0.0f, -3.0f));//向Z轴负方向移动3,相当于把物体往后移动
    unsigned int transViewLoc = glGetUniformLocation(shader.getShaderID(), "view");//获得变换矩阵位置
    glUniformMatrix4fv(transViewLoc, 1, GL_FALSE, glm::value_ptr(view));//赋值变换矩阵

    //透视投射矩阵:观察空间->裁剪空间
    glm::mat4 projection = glm::mat4(1.0f);
    projection = glm::perspective(glm::radians(45.0f), 800.0f / 600.0f, 0.1f, 100.0f);//第2个参数是:窗口宽度 / 窗口高度
    unsigned int transProjectionLoc = glGetUniformLocation(shader.getShaderID(), "projection");//获得变换矩阵位置
    glUniformMatrix4fv(transProjectionLoc, 1, GL_FALSE, glm::value_ptr(projection));//赋值变换矩阵

效果图

 

标签:mat4,1.0,glm,OpenGL,变换,矩阵,坐标,入门
From: https://www.cnblogs.com/ping-code/p/17765448.html

相关文章

  • Spark入门指南:从基础概念到实践应用全解析
    本文已收录至GitHub,推荐阅读......
  • Scala语言入门:初学者的基础语法指南
    本文已收录至GitHub,推荐阅读......
  • HBase入门指南
    本文已收录至GitHub,推荐阅读......
  • 每个后端都应该了解的OpenResty入门以及网关安全实战
    简介在官网上对OpenResty是这样介绍的(http://openresty.org):“OpenResty是一个基于Nginx与Lua的高性能Web平台,其内部集成了大量精良的Lua库、第三方模块以及大多数的依赖项。用于方便地搭建能够处理超高并发、扩展性极高的动态Web应用、Web服务和动态网关。”“......
  • 行列式与矩阵树定理
    定义定义矩阵的行列式:\[\detA=\sum_{\sigma}(-1)^{\tau(\sigma)}\prod_{i=1}^nA_{i\sigma_i}\]\(\tau(\sigma)\)是原排列的逆序对数。性质:若矩阵的某一行或某一列全为\(0\),则行列式为\(0\)。\(\detA=\detA^T\)。交换\(A\)的两行或两列,行列式取反。某一行或某一......
  • aFlex脚本入门
    aFlex脚本入门对于A10的aFelx脚本,相信很多人都知道,甚至用过,但是实际上很多工程师在各种项目中的使用可能都是按照模板进行修改,虽然能ok,但是却缺乏对aFelx脚本本质上的了解,所以在用户实际场景与脚本应用场景不完全一致的时候,就会碰到问题,不知如何修改。而更多的技术人员或者用户更......
  • 【C语言入门】第十四天
    【例题1】1260.二维网格迁移-力扣(LeetCode)/***Returnanarrayofarraysofsize*returnSize.*Thesizesofthearraysarereturnedas*returnColumnSizesarray.*Note:Bothreturnedarrayand*columnSizesarraymustbemalloced,assumecallercallsfree(......
  • 【C语言入门】第十五天
    【例题1】938.二叉搜索树的范围和-力扣(LeetCode)/***Definitionforabinarytreenode.*structTreeNode{*intval;*structTreeNode*left;*structTreeNode*right;*};*/intrangeSumBST(structTreeNode*root,intlow,inthigh){......
  • 物联网应用与维护搭建入门-准备工作
    1.设置SQLserver配置管理器。 先点击Windows键,找到M的文件,打开列表,找到SQLserver配置管理器。双击打开。进来后我们点击SQLserver网络配置,点击MSSQLSERVER的协议,找到TCP/IP,双击打开。(下面的VIA这个时候要注意看有没有开启,开启了的话我们这个TCP/IP是打不开的)启用......
  • Kafka 入门教程
     Kafka是分布式发布-订阅消息系统,它最初由LinkedIn公司开发,使用Scala语言编写,之后成为Apache项目的一部分。在Kafka集群中,没有“中心主节点”的概念,集群中所有的服务器都是对等的,因此,可以在不做任何配置的更改的情况下实现服务器的的添加与删除,同样的消息的生产者和消费者......