一、基本概念和前提
基本矩阵含义,四元数含义,欧拉角。
理解矩阵的
基向量特点
分解组合作用;四元数有一般的信息在变换乘法中;欧拉角存在万向锁。
不同坐标系下乘法顺序,矩阵逆,旋转绕向,正面定义不同。
变换坐标系区别(左手坐标系,右手坐标系是不同的,3ds max坐标系),矩阵行列式的区别,乘法顺序的区别,正反面的区别,一定要清楚变换前提条件,否则很容易导致难以觉察的计算错误。
二、变换物体和变换坐标系的连续区别
变换坐标系来实现变换例如的视图变换。
三、单一的完整变换的顺序和转换为线性变换(过原点)
单一坐标系中的完整缩放旋转平移,OGL是平移旋转缩放。其中原因DX一说是变换基于的坐标都是原坐标系的变换,缩放不影响基于原坐标系的旋转平移,旋转不影响基于原坐标系的平移,最后平移,顺序乱了会有问题;OGL中说是变换基于的坐标系都是基于本地Local坐标系的,平移不影响基于Local的旋转缩放,旋转不影响基于Local的缩放,最后缩放,顺序乱了会有问题。其实都可以解释得通,但是最主要的原因是按照乘法规则和乘法顺序,DX下只有SRT,OGL下书面写是M^t= (SRT)^t=T^t*R^t*S^t,但是是从右往左乘所以X写法是S^t*R^t*
T^t, ^t是转置,代码中的顺序是glTranslate->glRotate->glScale的顺序。
非线性变换,也就是不在原点的变换,可以先想物体变换回原点,然后进行线性变换,经过线性变换后再变换到原来的状态。变换的过程中一定要清楚变换的顺序,否则会导致问题。
四、嵌套坐标系在左手,右手父子上行(物惯)下行(惯物)的连续变换
U3D中的transform是对它上面的物体或子物体产生影响的,所以要计算它自己的position在父节点的父节点中的位置(世界坐标系是左手坐标系)是:
Vparent-parent = Vpos * Sparent * Rparent + Tparent
这是物惯变换,在父子坐标系中的惯物变换是,例如知道上面的子节点的世界坐标系,那么求子节点中的local坐标系;
那么: Vpos = (Vparent-parent - Tparent) * (Sparent * Rparent)^-1 = (Vparent-parent - Tparent) * Rparent^-1 * Sparent *^-1 顺序相反量相反(取逆变换)实现。
骨骼动画,复杂的特效表现,类似这样的处理。
五、各种变换之间的灵活转换思想
1.不同坐标系,左手,右手坐标系,3ds max坐标系,不同的坐标系统之间的转换。
2.各种变换之间的转换,例如四元数,欧拉角,矩阵间的转换。
3.为了得到目标空间位置,在各个摄像机,各个坐标空间,坐标位置之间的变换,和相对变换。
见:http://blog.csdn.net/blues1021/article/details/46289403
更多具体后面补充。
六、图形渲染中的变换和应用
模型坐标系
(OGL右手,DX左手)->世界坐标系(OGL右手,DX左手)->视图(摄像机)坐标系(
OGL右手,DX左手,变换了坐标系而不是物体,在视图坐标系中可能进行光照计算)->投影(裁剪坐标系或正交直接到NDC坐标系)坐标系(OGL 右手,DX左手)->硬件进行裁剪和透视除法(2D正交投影没有除法)->NDC规范化坐标系(OGL,DX都是变为了左手坐标系)->屏幕坐标系背面剔除(OGL左下角,DX右上角,有些UI世界坐标系可能不同3D世界坐标系)->接着进行片元插值会丢弃了冗余的片元屏幕坐标位置->Fragment Shader->全局雾计算 alpha stencil depth测试(遮挡剔除)->源帧缓存到目标后台缓存(之前的draw call)进行融合
抖动逻辑操作->写入目标后台缓存->flush/swapbuffer提交后台缓存到屏幕监视器显示2D图像。
D3D图形API是从前往后的顺序来进行矩阵乘法设置,OGL是从后往前的顺序来进行矩阵乘法设置,原因是:
Mtotal = Vector * Mworld * Mview * Mproject or ortho(3d中要硬件/w到ndc) * Mviewport
Mtotal的转置为单个矩阵转置相反的顺序相乘,虽然写法是从右往左乘,但代码中还是列式矩阵,相反顺序相乘的。
透视投影的图形学式的透视和部分投影到4D中的思想,统一左手的 NDC坐标系,映射到不同的屏幕坐标系。
网格中顶点位置法向量光照的计算, 法向量转换到视图空间的计算和顶点转换到视图空间的计算不一样?应该是一样的具体有机会研究下。
用gluPerspective函数构造的是一个对称的视锥,如果你想要构造非对称视锥必须直接使用glFrustum()函数。例如,你想要把一个宽场景绘制到两个相连的屏幕上,你可以将视锥分割为左右两个非对称的视锥,然后在每个视锥中渲染场景。
GL_TEXTURE纹理矩阵
纹理坐标(s,t,r,q)在进行任何纹理映射前乘以GL_TEXTURE。默认情况下,它是一个单位阵,因此纹理会被映射到物体的位置,那个你指定纹理坐标的位置。通过修改GL_TEXTURE,你可以滑动、旋转、拉伸以及收缩纹理。
glMatrixMode(GL_TEXTURE);
glRotatef(angle, 1, 0, 0)
GL_COLOR 颜色矩阵
颜色分量(r,g,b,a)乘以GL_COLOR矩阵。可以用于颜色空间转换和颜色分量交换。GL_COLOR矩阵被经常使用,并且需要GL_ARB_imaging拓展。
七、实践工程中的变换通过建模数学思维灵活处理变换
最好不要复杂的变量,通过中间变量,相对位置来计算。通过转换数学思想来实现。
转换时候进行的各种辅助变换,不满足要求的变换,转换到标准位置,例如费放射变换平移回原点;通过相对位置变换,骨骼动画中运动是相对网格位置的;通过中间位置来变换例如屏幕坐标系,不同摄像机之间的变换。
变换的不断实践和积累和研究,例如ogre中的逆向动力学,复杂的骨骼动画,粒子特性。
-- 例如地图的边界通过摄像机和屏幕坐标系变换到世界中得到,
-- 士兵的位置在mainCamera中转换屏幕坐标系再转到UICamera中mUICamera.ScreenToWorldPoint(uiScreenPos)中。
-- UI坐标中转换到屏幕坐标,包含z值;转换到MainCamera world space中,每帧刷新mainCamera 的Pos在摄像机中的位置再布局位置即可。
--
嵌套坐标系中的变换,
子坐标转换到父坐标,子坐标做基于左手坐标系子->父坐标变换:先缩放后旋转再平移得到。
Vector3 GetCameraToWorldPos(Vector3 vecCameraNodePos)
{
Transform cameraCtrl = GameObject.Find("CamPosCtrl").transform;
//Transform cameraNode = Camera.main.transform; //GameObject.Find("CamPosCtrl/mainCamera").transform;
if(cameraCtrl == null)
{
GSELog.LogErr("UISmallMapLogic error, CamPosCtrl GameObject is not exist.");
}
Vector3 cameraWorldPos = cameraCtrl.rotation * vecCameraNodePos;// cameraNode.localPosition;
cameraWorldPos += cameraCtrl.localPosition;
return cameraWorldPos;
}