详解MVP矩阵之ViewMatrix

矩阵推导

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

令UVN为相机坐标系下的三个基,,对于一个相机来说,它在开始的时候和世界坐标系是重合的,用户控制相机在世界空间中移动之后,相机的状态可以用两个属性来描述——朝向和位置。也就是说,有了这两个属性,一个相机模型在世界中的状态就确定了。而这两个属性,我们用变换的理论来描述,就是旋转和平移。可以想象,对于世界中的任何一个相机状态,我们都可以把它看成是:相机先围绕自身基原点旋转一定的角度,然后平移到世界空间的某个地方。下图展示了这个过程

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

图中,红色是相机的基,而黑色是世界的基,也就是参考系。小人是世界中的一个物体。相机在移动之前,两个基是重合的。当相机在屏幕中定位时,它首先会进行朝向的确定——旋转,然后进行位置的确定——平移。图中的Rotation和Translation两步就是相机定位时所发生的变换。可以看到相机相对于小人的运动。而当进行相机变换的时候,小人应该从世界基变换到相机的基里面。这样,他应该进行一个相机定位的逆定位,先逆平移小人和相机,然后再逆旋转小人和相机,最后相机归位,小人随相机变到了相机空间。这是由Inverse Translation和Inverse Rotation两个步骤完成的,这两个步骤就是相机变换。现在我们推导这个变换。我们把关系写出来,相机本身的变换C包括两个元素

C = TR

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

这个C^-1就是我们要求出的相机变换。其中T^-1很容易求出,即

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

时间: 2024-10-10 23:58:31

详解MVP矩阵之ViewMatrix的相关文章

具体解释MVP矩阵之ViewMatrix

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

android矩阵详解

Matrix,中文里叫矩阵,高等数学里有介绍,在图像处理方面,主要是用于平面的缩放.平移.旋转等操作. 在Android里面,Matrix由9个float值构成,是一个3*3的矩阵.最好记住.如下图: 解释一下,上面的sinX和cosX,表示旋转角度的cos值和sin值,注意,旋转角度是按顺时针方向计算的. translateX和translateY表示x和y的平移量.scale是缩放的比例,1是不变,2是表示缩放1/2,这样子. 在android.graphics.Matrix中有对应旋转的函

基于柯西矩阵的Erasure Code技术详解

一.概述 Erasure Code可以应用于分布式存储系统中,替代多份数据拷贝的数据冗余方式,从而可以提高存储空间利用率.此外,Erasure code还可以应用于传统RAID系统中,增加数据冗余度,支持多块盘同时发生故障,从而可以提高数据可靠性. 采用范德蒙矩阵可以构建Erasure code(关于范德蒙矩阵的编解码方法,可以参考文章<基于范德蒙矩阵的Erasure code技术详解>),其生成矩阵表示如下: 采用范德蒙矩阵作为编码矩阵的问题在于算法复杂度太高,其解码算法复杂度为O(n^3)

MVP 详解

Android MVP 详解(上) Android MVP 详解(下) 附: Google 官方MVP Demo

cublas 矩阵相乘API详解

#include "cuda_runtime.h"#include "device_launch_parameters.h" #include <stdio.h>#include <stdlib.h>#include "cublas_v2.h" void multiCPU(float *c, float *a, float *b, unsigned int aH, unsigned int aW, unsigned int

计算机视觉和图形学中的摄像机内参数矩阵详解【转】

计算机视觉和图形学中的摄像机内参数矩阵详解[转] 在计算机视觉和图形学中都有“摄像机内参数矩阵”这个概念,其含义大致相同,但在实际使用过程中,这两个矩阵却相差甚远.在增强现实中,为了使计算机绘制的虚拟物体和真实环境图像对其,需要令虚拟摄像机的内参数和真实摄像机的内参数相一致.因此,理解这两个内参数矩阵的详细含义和算法很重要. 在计算机视觉中,摄像机内参数矩阵可以表示为: 其中 f 为摄像机的焦距,单位一般是mm,dx,dy 为像元尺寸,u0,v0 为图像中心.由此可以计算出摄像机纵向视场角有:

OpenCv学习笔记(四)--Mat基本图像容器Mat对象信息头,矩阵体的创建,深复制,浅复制详解

1--我们知道Mat是一个图像容器类,这个数据结构由两部分组成: 1--矩阵头--即class Mat类所实例化的类对象所开辟的空间里面存储的数据---就是这个矩阵的信息,当我们以 Mat object;这样声明类对象的时候,也仅仅是创建了一个Mat的信息头,并没有创建矩阵体,也就是说,我们并 没有给将要存储的图像开辟相应的空间 2--矩阵头--包含: 1--矩阵的尺寸----比如---class Mat这个类中的----数据成员rows,cols---就可以指定图像的尺寸 2--存储方法---

《Unity3D 实战核心技术详解》书中关于矩阵的错误

最近一直在学习实时渲染,不免要接触线性代数.而渲染中,一定会用到矩阵,当我再次去复习我之前看的书时,发现<Unity3D 实战核心技术详解>关于矩阵就有几处错误 ,特标注出来. 书的第一章<3D数学与Unity>,1.3.2讲矩阵缩放.1.3.3讲矩阵的旋转.缩放是一个矩阵,后面旋转针对绕三个不同的轴的旋转矩阵(x.y.z),总共4个矩阵,其中3个是错误的,只有一个绕y轴旋转是正确的.我不确定是印刷问题,还是作者本身对矩阵了解和掌握的就不深入,但出现这样的低级错误实属不该. 我直接

热门前沿知识相关面试问题-MVC/MVP/MVVM架构设计模式面试问题详解

MVC: MVC的定义:M:业务逻辑处理.[业务MODEL]V:处理数据显示的部分.[如xml布局文件]C:Activity处理用户交互的问题.[也就是Activity在MVC中扮演着C的角色] MVC的特点:①.耦合性低.②.可扩展性好.③.模块职责划分明确. MVC的实例详解: 总结:①.利用MVC设计模式,使得项目有了很好的可扩展和维护性.②.controller(控制器)是一个中间桥梁的作用.③.什么时候适合使用MVC模式呢?当一个项目很小, MVP: MVVM: 原文地址:https: