投影及各种变换
摄像机的设置
Matrix.setLookAtM(
mVMatrix, //存储生成矩阵元素的float[]类型数组
0, //填充起始偏移量
cx, cy, cz, //摄像机位置X,Y,Z坐标
tx, ty, tz, //观察目标X,Y,Z坐标
upx,upy,upz //up向量在X,Y,Z上的分量
);
两种投影方式
- 正交投影
- 根据应用程序中提供的投影矩阵,管线会确定一个可视空间,称之为视景体.
视景体是由6个平面确定的,上平面(up),下平面(down),左平面(left),右平面(right),
远平面(far),近平面(near). - 场景中处于视景体内的物体会被投影到近平面上(视景体外面的物体将被裁减掉),然后再将
近平面上投影出内容映射到屏幕的视口中. - 对于正交投影,视景体及近平面的情况如下图
说明:视点为摄像机的位置;离视点较近(距离为near),垂直于观察方向向量的平面为近平面,离
视点较远(距离为far),垂直于观察方向向量的平面为远平面.与观察方向平行,从上下左右四个
方向约束视景体范围的4个平面分别为上平面,下平面,左平面,右平面,这四个平面与视景体中心轴线
的距离分别为top,bottom,left,right.
如上图,正交投影是平行投影的一种,其投影线(物体的顶点与近平面上投影点连线)是平行的.所以该视景体为长方体,
投影到近平面上的图形不会产生真实世界中”近大远小”的效果.如下示意图.
Java的Matrix类完成对正交投影的设置
- 根据应用程序中提供的投影矩阵,管线会确定一个可视空间,称之为视景体.
Matrix.orthoM(
mProjMatrix, //存储生成矩阵元素的float[]类型数组
0, //填充起始偏移量
left, right, //near面的left,right
bottom, top, //near面的bottom,top
near, far //near面,far面与视点的距离
);
//设置视口
GLES20.glViewport(x, y, width, height);
视口理解图
提示:尽量保持,近平面与视口的宽高比相同.即
((left + right) / (top + bottom)) == (width / height),否则显示在屏幕上的图像会拉伸变形
设置正交投影的重要代码
private static float[] mMVPMatrix; //最后起作用的总变换矩阵
private static float[] mVMatrix = new float[16]; //Camera位置朝向9参数矩阵
private static float[] mProjMatrix = new float[16];//4x4矩阵 投影用
/**
*绘制图像绕轴旋转 重要代码
*/
public void drawSelf()
{
Matrix.setRotateM(mMMatrix, 0, 0, 0, 1, 0);//初始化变换矩阵
Matrix.translateM(mMMatrix, 0, 0, 0, 1);//设置沿Z轴正向移动1
Matrix.rotateM(mMMatrix, 0, yAngle, 0, 1, 0);//设置绕Y轴旋转yAngle度
Matrix.rotateM(mMMatrix, 0, xAngle, 1, 0, 0);//设置绕X轴旋转xAngle度
//合成最终旋转矩阵
mMVPMatrix = new float[16];
//整合(矩阵相乘)旋转的矩阵
Matrix.multiplyMM(
mMVPMatrix,//存放结果的矩阵
0,//结果矩阵偏移量
mVMatrix,//Camera位置朝向9参数矩阵,左矩阵
0,//偏移量
mMMatrix,//乘法右矩阵
0//偏移量
);
//整合(矩阵相乘)投影与旋转到最终矩阵
Matrix.multiplyMM(mMVPMatrix, 0, mProjMatrix, 0, mMVPMatrix, 0);
//最终将矩阵传到OpenGL
GLES20.glUniformMatrix4fv(muMVPMatrixHandle, 1, false, mMVPMatrix, 0);
}
- 透视投影
透视投影的投影线是不平行的,它们相交于视点.
说明:远近平面+4个斜面确定了视景体的范围.
产生远小近大的原理图如下
透视投影的重要代码
Matrix.frustumM(
mProjMatrix, //要填充矩阵元素的float[]类型数组
0, //填充起始偏移量
left, right, //near面的left,right
bottom, top, //near面的bottom, top
near, far //near面,far面与视点的距离
);
各种变换
- 基本变化的相关数学知识
基本变换都是通过将表示点坐标的向量与特定的变换矩阵相乘完成的,
进行基于矩阵的变换是,三维空间中点的位置需要表示成齐次坐标形式.
⎛⎝⎜⎜⎜⎜QxQyQz1⎞⎠⎟⎟⎟⎟=⎛⎝⎜⎜⎜m11m21m310m12m22m320m13m23m330m14m24m341⎞⎠⎟⎟⎟×⎛⎝⎜⎜⎜PxPyPz1⎞⎠⎟⎟⎟或简写成:Q=MP
说明:上述线性代数表达式中最左侧是变换后Q点的齐次坐标.中间为4x4的变换矩阵
右侧为变换前P点的齐次坐标.
提示:
数学上,向量可以有两种选择:行向量与列向量.OpenGL ES中使用的是列向量.列向量和矩阵相乘实现变换时,只能在列向量前面乘以矩阵,而行向量则反之.反则乘法没有意义.
平移变换
OpenGL ES 中的基本变换都是通过变换矩阵完成.变换矩阵的基本格式如下:
M=⎛⎝⎜⎜⎜100001000010mxmymz1⎞⎠⎟⎟⎟
上述矩阵中的 mx,my,mz 分别表示平移变换中沿X,Y,Z轴方向的位移.
简单的线性代数计算验证如下:
MP=⎛⎝⎜⎜⎜100001000010mxmymz1⎞⎠⎟⎟⎟⎛⎝⎜⎜⎜PxPyPz1⎞⎠⎟⎟⎟=⎛⎝⎜⎜⎜Px+mxPy+myPz+mz1⎞⎠⎟⎟⎟
上述化简得:
⎛⎝⎜⎜⎜⎜QxQyQz1⎞⎠⎟⎟⎟⎟=⎛⎝⎜⎜⎜Px+mxPy+myPz+mz1⎞⎠⎟⎟⎟
旋转变换
OpenGL ES 中,旋转角度的正负可以用右手螺旋定则来确定.
旋转矩阵M的基本格式
重要的代码
public static void rotate(float angle, float x, float y, float z) {
Matrix.rotateM(currMatrix, 0, angle, x, y, z);
}
缩放变换
OpenGL ES 中的基本变换都是通过变换矩阵完成的,缩放变换矩阵的基本格式.
M=⎛⎝⎜⎜⎜Sx0000Sy0000Sz00001⎞⎠⎟⎟⎟
上述矩阵中 Sx,Sy,Sz 分别表示缩放变换中的沿X,Y,Z轴方向的缩放率.验证如下
MP=⎛⎝⎜⎜⎜Sx0000Sy0000Sz00001⎞⎠⎟⎟⎟⎛⎝⎜⎜⎜PxPyPz1⎞⎠⎟⎟⎟=⎛⎝⎜⎜⎜SxPxSyPySzPz1⎞⎠⎟⎟⎟
化简可得:
⎛⎝⎜⎜⎜⎜QxQyQz1⎞⎠⎟⎟⎟⎟=⎛⎝⎜⎜⎜SxPxSyPySzPz1⎞⎠⎟⎟⎟