具体解释MVP矩阵之ViewMatrix

矩阵推导

ViewMatrix用于直接将World坐标系下的坐标转换到Camera坐标系下。已知相机的坐标系。还有相机在世界空间下的坐标.就能够求出ViewMatrix。以下进行具体推导。

令UVN为相机坐标系下的三个基,,对于一个相机来说,它在開始的时候和世界坐标系是重合的,用户控制相机在世界空间中移动之后,相机的状态能够用两个属性来描写叙述——朝向和位置。也就是说。有了这两个属性,一个相机模型在世界中的状态就确定了。

而这两个属性,我们用变换的理论来描写叙述,就是旋转和平移。

能够想象,对于世界中的不论什么一个相机状态,我们都能够把它看成是:相机先环绕自身基原点旋转一定的角度,然后平移到世界空间的某个地方。下图展示了这个过程

图一 . 相机的变换与逆变换

图中,红色是相机的基,而黑色是世界的基,也就是參考系。

小人是世界中的一个物体。相机在移动之前,两个基是重合的。当相机在屏幕中定位时。它首先会进行朝向的确定——旋转。然后进行位置的确定——平移。图中的Rotation和Translation两步就是相机定位时所发生的变换。能够看到相机相对于小人的运动。而当进行相机变换的时候,小人应该从世界基变换到相机的基里面。

这样,他应该进行一个相机定位的逆定位。先逆平移小人和相机。然后再逆旋转小人和相机。最后相机归位,小人随相机变到了相机空间。这是由Inverse Translation和Inverse Rotation两个步骤完毕的。这两个步骤就是相机变换。

如今我们推导这个变换。我们把关系写出来。相机本身的变换C包含两个元素

C = TR

当中T是平移变换,R是旋转变换。而相机变换是相机本身变换的逆变换

这个C^-1就是我们要求出的相机变换。

当中T^-1非常easy求出,即

R^(-1)比較难求出,这里用到了正交基一些知识,能够參考下碰撞检測之Ray-Cylinder检測前面关于正交基的部分。

当相机变换进行完Inverse Translation这一步之后,相机的原点和世界原点就重合了,也就是处理完了关于平移的变换。接下来我们要做的是逆旋转,而事实上逆旋转的目的,就是要得到眼下世界坐标中经过逆平移的小人在相机坐标系中的坐标。

由坐标转换公式

对于世界坐标中的已经经过逆平移的坐标v’,它在相机坐标系R中的坐标是v’’,而相机坐标系就是

则相机变换的完整公式就是

当中v是小人在世界空间中的坐标。v’’是小人在相机空间中的坐标。则相机变换矩阵就是

常见的求ViewMatrix的情况有三种。一种是用LookAt函数。另外一种是相似FPS游戏中通过pitch和yaw来算,另一种是相似轨迹球的算法。

最后的方法都是转化为求出相机的坐标系的基。

Look At Camera

这里參考是左手坐标系,并且在相机空间,相机的forward是Z轴的负方向。和Unity还有OpenGL一致。

图二 . 相机的左手坐标系

例如以下图,这样的求法须要知道摄像机的位置 eye。一个up向量(global),还有摄像机的观察点at

图三 . LookAt函数模型

Matrix4x4 LookAt(const Vector3& eye, const Vector3& target, const Vector3& up)
{
	Vector3 z((eye - target).normalized());
	Vector3 x((Vector3::Cross(z, up).normalized()));
	Vector3 y(Vector3::Cross(x, z));

	Matrix4x4 result;

	result[0] = x.x;
	result[4] = x.y;
	result[8] = x.z;
	result[12] = -Vector3::Dot(x, eye);

	result[1] = y.x;
	result[5] = y.y;
	result[9] = y.z;
	result[13] = -Vector3::Dot(y, eye);

	result[2] = z.x;
	result[6] = z.y;
	result[10] = z.z;
	result[14] = -Vector3::Dot(z, eye);

	result[3] = result[7] = result[11] = 0.0f;
	result[15] = 1.0f;
	return result;
}

算例

//C++
qDebug() << Transform::LookAt(Vector3(1, 2, 3), Vector3(0, 10, 0), Vector3::up);

图四 . LookAt函数计算结果

//Unity
transform.position = new Vector3(1, 2, 3);
transform.LookAt(new Vector3(0, 10, 0), Vector3.up);
Debug.Log(Camera.main.worldToCameraMatrix);

图五 . Unity中的计算结果

(貌似Unity中的Transform.LookAt函数是直接改动的Camera的Rotation?)

FPS Camera

通过之前的结论

如果原始的坐标系为x-(1,0,0), y-(0,1,0), z(0,0,1),这个坐标系经过一个旋转矩阵Matrix旋转之后,新的坐标系就是这个旋转矩阵的转置三个列向量。

事实上这里要求的仅仅是旋转矩阵的转置。

注意相机的Z方向并非相机正对的方向,而是相机的背面。

Matrix4x4 Transform::FPSView(const Vector3& eye, Quaternion rotation)
{
	Matrix4x4 rotMatrix = rotation.GetRotMatrix().transpose();
	Vector3 x(rotMatrix[0], rotMatrix[4], rotMatrix[8]);
	Vector3 y(rotMatrix[1], rotMatrix[5], rotMatrix[9]);
	Vector3 z(-rotMatrix[2], -rotMatrix[6], -rotMatrix[10]);

	Matrix4x4 result;

	result[0] = x.x;
	result[4] = x.y;
	result[8] = x.z;
	result[12] = -Vector3::Dot(x, eye);

	result[1] = y.x;
	result[5] = y.y;
	result[9] = y.z;
	result[13] = -Vector3::Dot(y, eye);

	result[2] = z.x;
	result[6] = z.y;
	result[10] = z.z;
	result[14] = -Vector3::Dot(z, eye);

	result[3] = result[7] = result[11] = 0.0f;
	result[15] = 1.0f;
	return result;
}

算例

//C++
qDebug() << Transform::FPSView(Vector3(1,2,3), Quaternion::Euler(30, 45, 60));

结果

图六 . FPV函数计算结果

//unity
transform.position = new Vector3(1, 2, 3);
transform.rotation = Quaternion.Euler(30, 45, 60);
Debug.Log(Camera.main.worldToCameraMatrix);

图七 . Unity中执行结果

參考

Understanding the View Matrix - http://www.3dgep.com/understanding-the-view-matrix/

Tutorial 3 : Matrices - http://www.opengl-tutorial.org/beginners-tutorials/tutorial-3-matrices/

OpenGL Transformation - http://www.songho.ca/opengl/gl_transform.html

推导相机变换矩阵 - http://blog.csdn.net/popy007/article/details/5120158

链接

具体解释MVP矩阵之齐次坐标和ModelMatrix

具体解释MVP矩阵之齐次坐标和ViewMatrix

具体解释MVP矩阵之齐次坐标和ProjectionMatrix

时间: 08-18

具体解释MVP矩阵之ViewMatrix的相关文章

详解MVP矩阵之ViewMatrix

矩阵推导 ViewMatrix用于直接将World坐标系下的坐标转换到Camera坐标系下.已知相机的坐标系,还有相机在世界空间下的坐标.就可以求出ViewMatrix,下面进行具体推导. 令UVN为相机坐标系下的三个基,,对于一个相机来说,它在开始的时候和世界坐标系是重合的,用户控制相机在世界空间中移动之后,相机的状态可以用两个属性来描述--朝向和位置.也就是说,有了这两个属性,一个相机模型在世界中的状态就确定了.而这两个属性,我们用变换的理论来描述,就是旋转和平移.可以想象,对于世界中的任何

阴影映射(Shadow Map)的研究(五)

阴影映射(Shadow Map)的研究(五) 我成功地将别人的例子加以改进,使用QOpenGLWidget作为渲染窗口,将阴影映射渲染了出来.目前可以确定的是,使用OpenGL ES 2.0作为渲染的接口要求,能够让目前绝大多数机器都能够顺利兼容,但是囿于渲染窗口,可能在某些平台上表现不好.如果移植到Qt Quick 2,这样能够支持的平台就更多了.现在我将这些接口统统使用Qt的方式实现了,移植到Qt Quick 2也很简单. 这里主要参考的是OpenGLUnderQML这个例子,自定义了一个Q

Cg入门10:Vertex Shader - 几何变换 —MVP矩阵变换

Unity内建矩阵类型: M:世界矩阵 V:摄像机矩阵 P:投影矩阵 T :矩阵的转置 IT : 转置的的逆 _Object2World: 模型到世界矩阵 _World2Object:世界到模型矩阵 MVP 矩阵变换:Shader Demo MVP 转置变换:C# demo Matrix4x4 mvp = Camera.main .projectionMatrix * Camera.main .worldToCameraMatrix * transform .localToWorldMatrix

适用android的MVP:如何组织展示层

原文 MVP for Android:How to organize presentation layer http://antonioleiva.com/mvp-android/ 译文 MVP(Model-View-Presenter)模式是著名的MVC(Model-View-Controller)模式的衍生.这段时间,MVP在Android应用开发上得到重视.越来越多的人讨论它,但是可靠的和结构化的信息仍然很少.这就是为什么我想利用这个博客鼓励这种讨论,并且把我们所知 以最好的方式应用到项目

python小白之矩阵matrix笔记(updating)

Matrix #python学习之矩阵matrix 2018.4.18 # -*- coding: UTF-8 -*- from numpy import * import numpy as np import math a=np.matrix('1 2 7;3 4 8;5 6 9')#矩阵的换行必须使用分号隔开,内部数据必须为字符串形式,元素之间必须以空格隔开 print(np.matrix([[1,2],[3,4]])) m=np.asmatrix(a)#将输入的a解释为矩阵m,并修改m中某

LeetCode 861. 翻转矩阵后的得分

有一个二维矩阵 A 其中每个元素的值为 0 或 1 . 移动是指选择任一行或列,并转换该行或列中的每一个值:将所有 0 都更改为 1,将所有 1 都更改为 0. 在做出任意次数的移动后,将该矩阵的每一行都按照二进制数来解释,矩阵的得分就是这些数字的总和. 返回尽可能高的分数. 示例: 输入:[[0,0,1,1],[1,0,1,0],[1,1,0,0]] 输出:39 解释: 转换为 [[1,1,1,1],[1,0,0,1],[1,1,1,1]] 0b1111 + 0b1001 + 0b1111 =

力扣——翻转矩阵后的得分

有一个二维矩阵 A 其中每个元素的值为 0 或 1 . 移动是指选择任一行或列,并转换该行或列中的每一个值:将所有 0 都更改为 1,将所有 1 都更改为 0. 在做出任意次数的移动后,将该矩阵的每一行都按照二进制数来解释,矩阵的得分就是这些数字的总和. 返回尽可能高的分数. 示例: 输入:[[0,0,1,1],[1,0,1,0],[1,1,0,0]] 输出:39 解释: 转换为 [[1,1,1,1],[1,0,0,1],[1,1,1,1]] 0b1111 + 0b1001 + 0b1111 =

LeetCode 中级 - 翻转矩阵后的得分(861)

有一个二维矩阵 A 其中每个元素的值为 0 或 1 . 移动是指选择任一行或列,并转换该行或列中的每一个值:将所有 0 都更改为 1,将所有 1 都更改为 0. 在做出任意次数的移动后,将该矩阵的每一行都按照二进制数来解释,矩阵的得分就是这些数字的总和. 返回尽可能高的分数. 示例: 输入:[[0,0,1,1],[1,0,1,0],[1,1,0,0]] 输出:39 解释: 转换为 [[1,1,1,1],[1,0,0,1],[1,1,1,1]] 0b1111 + 0b1001 + 0b1111 =

关于数组与矩阵

数组在计算机里的存储是按行列,下标即是哪行哪列.而在科学计算的语言的中,都是按列行,比如matlab.fortran.于是如果是在计算机中定义的数组,将数组的数据导入到数学计算的矩阵中时,要先转置.典型的就是opengl导入glsl时,传入的数组会被解释成矩阵,也就是转置了.一个题外话,glm里矩阵乘法是反的,比如,如果想作a*b*c,要写成c*b*a,毕竟20几年才到0.995的版本,还不完善. 原文地址:https://www.cnblogs.com/lector/p/10843568.ht