详解MVP矩阵之齐次坐标和ModelMatrix

齐次坐标(Homogeneous Coordinates)

其次坐标这个概念在第一次看real-time rendering 这本书的时候就有提起到,但当时看的一头雾水,只知道其次坐标在某些计算中比较方便,而事实上齐次坐标有着非常重要的意义和作用,主要是在处理三维透视方面,常用的几个地方,比如texture mapping 透视矫正,Projection Matrix的计算等等。

在笛卡尔坐标系中,两条平行线是永不相交的,而在现实中,两条平行线是可能相交于一点的,比如说下面的铁轨。



图一 . 铁路越来越窄,最后汇集到一点


在这种透视空间中,笛卡尔坐标就无法描述了。


解决方案就是齐次坐标,一句话解释,就是用N+1个数来表示N维空间中的点。

比如一个二维坐标(X,Y),它的齐次坐标就是(x, y, w),  关系如下

X = x/w 
Y = y/w 

所以在知道齐次坐标的情况下,可以很方便地得到其笛卡尔坐标。之所以称之为其次坐标,是因为奇次坐标具有缩放不变性,比如(1,2,3),(2,4,6), (1a,2a,3a) 所表达的笛卡尔坐标是一样的!

有了其次坐标我们就可以证明两条平行线相交了。

有两条直线

Ax + By + C = 0

Ax + By + D = 0

很明显他们在平面内是平行线,永不相交(如果C==D的话,两条直线就重合了)

化为其次坐标,

A(x/w) + B(y/w) +  C = 0;

A(x/w) + B(y/w) +  D = 0;

同乘w,得到

Ax + By + Cw = 0

Ax + By + Dw = 0

则有解 (x,y,0),所以两条平行线相交在(x,y,0),也就是相交在无穷远的点。


ModelMatrix

在Unity中,每一个GameObject上面都会有一个Transform,用来记录这个Object的position,rotation和scale.


图二 . Unity中的Transform Compoent


这三项都可以用矩阵来表示,位移矩阵是



旋转矩阵由Quatenion转过来 

R = (  
        1.0f - 2.0f*y*y - 2.0f*z*z, 2.0f*x*y - 2.0f*z*w, 2.0f*x*z + 2.0f*y*w, 0.0f,  
        2.0f*x*y + 2.0f*z*w, 1.0f - 2.0f*x*x - 2.0f*z*z, 2.0f*y*z - 2.0f*x*w, 0.0f,  
        2.0f*x*z - 2.0f*y*w, 2.0f*y*z + 2.0f*x*w, 1.0f - 2.0f*x*x - 2.0f*y*y, 0.0f,  
        0.0f, 0.0f, 0.0f, 1.0f  
        )  

缩放矩阵


具体的矩阵推导可以参考我之前写的Real-Time Rendering (2) - 变换和矩阵(Transforms and Matrics)


所谓的ModelMatrix,就是将模型坐标变换到WorldMatrix的Matrix,


WorldMatrix = Mt * Mr * Ms

Vw = WorldMatrix * Vm


注意这里的Matrix都是列主序,  Vm是Model坐标系下的坐标,Vw是世界坐标系下的坐标,矩阵是右乘Vm, Vm用的齐次坐标,w = 1.

顺序一定是T*R*S。


Transform Class

这里写一个简单的类来处理GameObejct的位置,旋转和缩放.

Transform.h

#pragma once
#include "Quaternion.h"
#include "RiCore/RiDevice.h"

class Transform
{
public:

	Transform();
	Transform(const Vector3& position, const Quaternion& rotation, const Vector3& scale);
	~Transform();

	Matrix4x4 GetLocalToWorldMatrix();
	bool isDirty;
	Vector3 position;
	Quaternion rotation;
	Vector3 scale;

	void Translate(const Vector3 &delta);
	void Rotate(float xRot, float yRot, float zRot);
	void Scale(const Vector3 &scale);

private:
	Matrix4x4 localToWorldMatrix;
	Matrix4x4 worldToLocalMatrix;
};

Transform.cpp

#include "stableheader.h" 
#include "Transform.h"
#include "Log/Log.h"

Transform::Transform()
{

}

Transform::Transform(const Vector3& _position, const Quaternion& _rotation, const Vector3& _scale)
{
	position = _position;
	rotation = _rotation;
	scale = _scale;
	isDirty = true;
}

Transform::~Transform()
{

}

Matrix4x4 Transform::GetLocalToWorldMatrix()
{
	if (isDirty)
	{
		Matrix4x4 transMatrix(1, 0, 0, 0,
			0, 1, 0, 0,
			0, 0, 1, 0,
			position.x, position.y, position.z, 1);

		Matrix4x4 scaleMatrix(scale.x, 0, 0, 0,
			0, scale.y, 0, 0,
			0, 0, scale.z, 0,
			0, 0, 0, 1);

		localToWorldMatrix = transMatrix * rotation.GetRotMatrix() * scaleMatrix;
	}
	return localToWorldMatrix;
}

void Transform::Translate(const Vector3 &delta)
{
	position.x += delta.x;
	position.y += delta.y;
	position.z += delta.z;

	isDirty = true;

}


void Transform::Rotate(float xRot, float yRot, float zRot)
{
	rotation = rotation * Quaternion::Euler(xRot, yRot, zRot);
	isDirty = true;
}

Matrix4x4 Transform :: Scale(const Vector3& _scale)
{
	scale = _scale;
	isDirty = true;
}


用了一个标志位来记录position,rotation,scale是否发生改变,如果发生改变就将isDirty至为true,下次获取WorldMatrix的时候就重新计算。


测试


//Unity
transform.position = new Vector3(1, 2, 3);
transform.rotation = Quaternion.Euler(30, 45, 60);
transform.localScale = new Vector3(3, 2, 1);
Debug.Log(transform.localToWorldMatrix);


图三 . Unity中的运行结果


//C++
renderObj = new RenderObject();
renderObj->transform->Translate(Vector3(1, 2, 3));
renderObj->transform->Rotate(30, 45, 60);
renderObj->transform->Scale(Vector3(3, 2, 1));
qDebug() << renderObj->transform->GetLocalToWorldMatrix();



图四 .C++运行结果


参考

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

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

Homogeneous Coordinates - http://www.songho.ca/math/homogeneous/homogeneous.html

The Truth Behind Homogeneous Coordinates - http://deltaorange.com/2012/03/08/the-truth-behind-homogenous-coordinates/

Real Time Rendering 3rd


链接

详解MVP矩阵之齐次坐标和ModelMatrix

详解MVP矩阵之齐次坐标和ViewMatrix

详解MVP矩阵之齐次坐标和ProjectionMatrix



  • 2
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
要进行坐标系之间的转换,需要使用旋转矩阵和平移向量。根据给定的三个点在两个坐标系下的坐标,可以通过以下步骤求解转换参数。 1. 首先,选择其中一个点作为世界坐标系的原点,并将其在相机坐标系中的坐标作为平移向量T。这个平移向量描述了世界坐标系到相机坐标系的平移关系。 2. 接下来,使用另外两个不共线的点来构建旋转矩阵R。旋转矩阵描述了世界坐标系到相机坐标系的旋转关系。具体步骤可以通过计算两个坐标系中的向量之间的旋转变换得到。 3. 如果没有现成的矩阵相乘函数,可以自己编写代码实现矩阵相乘的功能。初始时可以使用数组存放矩阵,但后续考虑到方便性和可扩展性,可以转换思路,使用vector动态存放数组,这样可以更方便地进行矩阵的计算,并适应后续用户增加顶点操作的需求。 通过以上步骤,可以得到坐标系之间的旋转矩阵R和平移向量T,从而实现坐标系之间的转换。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* [三点解算两个坐标系之间的旋转矩阵和平移向量](https://download.csdn.net/download/yangzhe1215/12449123)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 33.333333333333336%"] - *2* [原理详解_三点解算两个坐标系之间的旋转矩阵和平移向量](https://download.csdn.net/download/zhangxz259/10815707)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 33.333333333333336%"] - *3* [基于OpenGL的计算机图形学实验四简单几何形体(三角形、多边形等)的平移、缩放、旋转等几何变换(完整可...](https://download.csdn.net/download/weixin_53249260/88236610)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 33.333333333333336%"] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值