学习三种变换:Scaling, Rotation和Translation。

上学期修了Kobbelt教授(男神!)的图形学基础课,这部分内容已经接触过。

添加GLM库,直接给出齐次坐标系下的变换矩阵和相应的代码表示:

Scaling

\(M=\begin{bmatrix}
a&0&0&0\\
0&b&0&0\\
0&0&c&0\\
0&0&0&1\\
\end{bmatrix}\)

glm::mat4 m = glm::scale(glm::mat4(1.0f), glm::vec3(a, b, c));

Rotation

绕x轴,\(\theta\)表示旋转角度:

\(M=\begin{bmatrix}
1&0&0&0\\
0&\cos\theta&-\sin\theta&0\\
0&\sin\theta&\cos\theta&0\\
0&0&0&1\\
\end{bmatrix}\)

glm::mat4 m = glm::rotate(glm::mat4(1.0f), glm::radians(theta), glm::vec3(1.0f, 0.0f, 0.0f));

绕y轴:

\(M=\begin{bmatrix}
\cos\theta&0&\sin\theta&0\\
0&1&0&0\\
-\sin\theta&0&\cos\theta&0\\
0&0&0&1\\
\end{bmatrix}\)

glm::mat4 m = glm::rotate(glm::mat4(1.0f), glm::radians(theta), glm::vec3(0.0f, 1.0f, 0.0f));

绕z轴:

\(M=\begin{bmatrix}
\cos\theta&-\sin\theta&0&0\\
\sin\theta&\cos\theta&0&0\\
0&0&1&0\\
0&0&0&1\\
\end{bmatrix}\)

glm::mat4 m = glm::rotate(glm::mat4(1.0f), glm::radians(theta), glm::vec3(0.0f, 0.0f, 1.0f));

绕任意轴(x, y, z),(x, y, z)为单位向量:

\(M=\begin{bmatrix}
\cos\theta+x^2(1-\cos\theta)&xy(1-\cos\theta)-z\cos\theta&xz(1-\cos\theta)+y\cos\theta&0\\
yx(1-\cos\theta)+z\cos\theta&\cos\theta+y^2(1-\cos\theta)&yz(1-\cos\theta)-x\cos\theta&0\\
zx(1-\cos\theta)-y\cos\theta&zy(1-\cos\theta)+x\cos\theta&\cos\theta+z^2(1-\cos\theta)&0\\
0&0&0&1\\
\end{bmatrix}\)

glm::mat4 m = glm::rotate(glm::mat4(1.0f), glm::radians(theta), glm::vec3(x, y, z));

Translation

\(M=\begin{bmatrix}
1&0&0&t_x\\
0&1&0&t_y\\
0&0&1&t_z\\
0&0&0&1\\
\end{bmatrix}\)

glm::mat4 m = glm::translate(glm::mat4(1.0f), glm::vec3(tx, ty, tz));

在glm中,矩阵以column-major的顺序储存,即原变换矩阵的转置。以上述Translation代码为例,变换矩阵m的各元素索引为:

m[0][0] == 1.0f, m[0][1] == 0.0f, m[0][2] == 0.0f, m[0][3] == 0.0f
m[1][0] == 0.0f, m[1][1] == 1.0f, m[1][2] == 0.0f, m[1][3] == 0.0f
m[2][0] == 0.0f, m[2][1] == 0.0f, m[2][2] == 1.0f, m[2][3] == 0.0f
m[3][0] == tx, m[3][1] == ty, m[3][2] == tz, m[3][3] == 1.0f

练习

1.Using the last transformation on the container, try switching the order around by first rotating and then translating. See what happens and try to reason why this happens.

先Rotation,再Translation

新建transform.cpp和transform.h,并添加到工程中。定义一个transform函数返回变换矩阵:

transform.h

#ifndef TRANSFORM_H
#define TRANSFORM_H #include <glm/glm/glm.hpp>
#include <glm/glm/gtc/matrix_transform.hpp>
#include <glm/glm/gtc/type_ptr.hpp>
#include <GLFW/glfw3.h>
#include <iostream> glm::mat4 transform(); #endif // TRANSFORM_H

transform.cpp

#include "transform.h"

glm::mat4 transform()
{
glm::mat4 transMatrix = glm::mat4(1.0f);
transMatrix = glm::translate(transMatrix, glm::vec3(0.5f, -0.5f, 0.0f));
transMatrix = glm::rotate(transMatrix, glm::radians(45.0f), glm::vec3(0.0f, 0.0f, 1.0f));
return transMatrix;
}

修改Vertex Shader,定义uniform将变换矩阵传递到Shader中,对顶点坐标进行位置变换:

#version 330 core
layout (location = 0) in vec3 Pos;
layout (location = 1) in vec3 Col;
layout (location = 2) in vec2 Tex;
out vec4 Color;
out vec2 texCoord;
uniform mat4 transform; void main()
{
gl_Position = transform * vec4(Pos, 1.0f);
Color = vec4(Col, 1.0f);
texCoord = Tex;
}

在渲染循环中添加一行代码,调用glUniformMatrix4fv函数更新uniform的值,即transform函数的返回值。glUniformMatrix4fv函数的第二和第三个参数分别表示矩阵的数量以及是否对矩阵转置:

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



先Translation,再Rotation

只需要修改transform.cpp:

#include "transform.h"

glm::mat4 transform()
{
glm::mat4 transMatrix = glm::mat4(1.0f);
transMatrix = glm::rotate(transMatrix, glm::radians(45.0f), glm::vec3(0.0f, 0.0f, 1.0f));
transMatrix = glm::translate(transMatrix, glm::vec3(0.5f, -0.5f, 0.0f));
return transMatrix;
}



2.Try drawing a second container with another call to glDrawElements but place it at a different position using transformations only. Make sure this second container is placed at the top-left of the window and instead of rotating, scale it over time.

在transform.cpp中定义transform2函数:

glm::mat4 transform2()
{
float timeValue = glfwGetTime();
float scaleValue = sin(timeValue)/2.0f+0.5f;
glm::mat4 transMatrix = glm::mat4(1.0f);
transMatrix = glm::translate(transMatrix, glm::vec3(-0.5f, 0.5f, 0.0f));
transMatrix = glm::scale(transMatrix, glm::vec3(scaleValue, scaleValue, 0.0f));
return transMatrix;
}

OpenGL(5)——变换的更多相关文章

  1. OpenGL法向量变换

    OpenGL光照开启时,法向量用于决定特定顶点或面上接受到光照的多少.光照处理过程作用于观察坐标空间,因此,模型对象坐标系的法向量也需要使用GL_MODELVIEW矩阵变换到观察坐标系. 然而,法向量 ...

  2. opengl视图变换 投影变换推导

    视图变换在opengl中,视图变换的输入是:(1)眼睛位置(或者说相机位置)eys:(2)眼睛朝向的中心center,(就是眼睛朝哪里看);(3)头的方向up.任何一点经过视图变换后都会转化到眼睛坐标 ...

  3. SharpGL学习笔记(七) OpenGL的变换总结

    笔者接触OpenGL最大的困难是: 经常调试一份代码时, 屏幕漆黑一片, 也不知道结果对不对,不知道如何是好! 这其实就是关于OpenGL"变换"的基础概念没有掌握好, 以至于对& ...

  4. OpenGL判断一个点是否可见

    关于OpenGL中判断一个点是否可见,可以分成两种情况讨论:点在2D空间中和3D空间中的时候.并且"在2D空间中"可以看作"在3D空间中"的特殊情况. 温馨提示 ...

  5. SharpGL学习笔记(八) 矩阵堆栈和变换的综合例子: 机器人

    我们先引入关于"矩阵堆栈"的官方说法: OpenGL的矩阵堆栈指的就是内存中专门用来存放矩阵数据的某块特殊区域.实际上,在创建.装入.相乘模型变换和投影变换矩阵时,都已用到堆栈操作 ...

  6. 一文详解 OpenGL ES 3.x 渲染管线

    OpenGL ES 构建的三维空间,其中的三维实体由许多的三角形拼接构成.如下图左侧所示的三维实体圆锥,其由许多三角形按照一定规律拼接构成.而组成圆锥的每一个三角形,其任意一个顶点由三维空间中 x.y ...

  7. OpenGL变换

    概述 OpenGL变换矩阵 实例:GL_MODELVIEW矩阵 实例:GL_PROJECTION矩阵 概述 OpenGL管线中,在光栅化操作之前,包括顶点位置与法线向量的几何数据经顶点操作与图元装配操 ...

  8. OpenGL中旋转平移缩放等变换的顺序对模型的影响

    l 前提: 0x01. 假设绘制顶点的语句为Draw Array,变换的语句(旋转.平移.缩放)为M,而 M0; M1; M2; Draw Array; 则称对Array先进行M2再进行M1.M0 0 ...

  9. OpenGL学习进程(12)第九课:矩阵乘法实现3D变换

    本节是OpenGL学习的第九个课时,下面将详细介绍OpenGL的多种3D变换和如何操作矩阵堆栈.     (1)3D变换: OpenGL中绘制3D世界的空间变换包括:模型变换.视图变换.投影变换和视口 ...

  10. 详解OpenGL中的各种变换(投影变换,模型变换,视图变换)(完)——法线变换

    前面两节内容已经说完了所有的三种变换.也就是说我们现在程序里面既不需要glLookAt(),也不需要gluPerspective(),这些矩阵我们都可以自己写.然后,再用glMultMatrix()来 ...

随机推荐

  1. 【H5】 经纬度位置获取navigator.geolocation.getCurrentPosition

    navigator.geolocation.getCurrentPosition(function(){})经度 : coords.longitude 纬度 : coords.latitude 准确度 ...

  2. TCP IP协议和网络安全

    传输层的两个协议:     可靠传输 TCP 分段传输 建立对话(消耗系统资源) 丢失重传netstat -n     不可靠传输 UDP 一个数据包就能表达完整的意思或屏幕广播   应用层协议(默认 ...

  3. 25、自动装配-@Profile根据环境注册bean

    25.自动装配-@Profile根据环境注册bean 指定组件在哪个环境的情况下才能被注册到容器中 加了环境标识的,只有这个环境被激活才能注册到组件中 默认是default环境 写在类上,整个配置类的 ...

  4. 第九章 利用CSS3制作网页动画

    一.CSS3变形transform 1.平移:translate(x,y) translateX(x) translateY(y) 注意:如果想只向X轴平移那么可以translateX,如果想只向X轴 ...

  5. 二进制文件方式安装kubernetes集群

    所有操作全部用root使用者进行,高可用一般建议大于等于3台的奇数,我们使用3台master来做高可用 练习环境说明: 参考GitHub master: kube-apiserver,kube-con ...

  6. UVA1426 Discrete Square Roots

    思路:\(exgcd\) 提交:\(2\)次 错因:输出格式错误OTZ 题解: 求:\(r^2 ≡ x \mod N , 0 \leq r < N\),并且题目会给出 \(x,N\) 和一个合法 ...

  7. Mysql 高可用集群PXC

    PXC是percona公司的percona  xtraDB  cluster,简称PXC.它是基于Galera协议的高可用集群方案.可以实现多个节点间的数据同步复制以及读写,并且可保障数据库的服务高可 ...

  8. DP(第二版)

    第一版请见:直通 话不多说,直接上题 1.P1040 加分二叉树 直通 思路: 已知中序遍历,相当于一段区间了,所以我们枚举一个k,如果以k为根节点,能够将分数更新,那么这段区间的根节点就置为k,最后 ...

  9. python实现随机生成头像

    今天遇到如何给用户分配随机头像的问题,想着要在本地放很多图片,有点无聊,就找了一些生成头像的工具.发现gravatar生成图像还不错,挺好玩的. 1.下面上代码 # -*- coding: utf-8 ...

  10. Java主线程在子线程执行完毕后再执行

    一.join() Thread中的join()方法就是同步,它使得线程之间由并行执行变为串行执行. public class MyJoinTest { public static void main( ...