大家好,接下来为大家介绍OpenGL ES 3. 的投影方式。
1、摄像机的设置
从日常生活的经验中可以很容易地了解到,随着摄像机位置、姿态的不同,就算是对同一 个场景进行拍摄,得到的画面也是迥然不同的。因此摄像机的位置、姿态在OpenGL ES 应用程序的开发中就显得非常重要,首先需要介绍一下摄像机的设置方法。
摄像机的设置需要给出 3 方面的信息,包括摄像机的位置、观察的方向以及 up 方向,具体情况如下图所示。
a:摄像机的位置很容易理解,用其在 3D 空间中的坐标来表示。
b:摄像机观察的方向可以理解为摄像机镜 头的指向,用一个观察目标点来表示(通过摄像机位置与观察目标点可以确定一个向量,此向量 即代表了摄像机观察的方向)。
c:摄像机的 up 方向可以理解为摄像机顶端的指向,用一个向量来表示。
设置摄像机的api如下:
Matrix.setLookAtM(
mVMatrix, //存储生成矩阵元素的 float[]类型数组
0, //填充起始偏移量
cx, cy, cz, //摄像机位置的 X、Y、Z 坐标
tx, ty, tz, //观察目标点 X、Y、Z 坐标
upx, upy, upz //up 向量在 X、Y、Z 轴上的分量
)
2、正交投影
OpenGL ES 中,根据应用程序中提供的投影矩阵,管线会确定一个可视空间区域,称为视景体。视景体是由 6 个平面确定的,这 6 个平面分别为:上平面(up)、下平面(down)、左平 面(left)、右平面(right)、远平面(far)、近平面(near)。
场景中处于视景体内的物体会被投影到近平面上(视景体外面的物体将被裁剪掉),然后再将近平面上投影出的内容映射到屏幕上的视口中。
正交投影示意图如下图所示:
使用Matrix.orthoM()来设置正交投影。
/**
* @param m 生成的投影矩阵,float[4*4]
* @param mOffset 填充时候起始的偏移量
* @param left 近平面left边的x坐标
* @param right 近平面right边的x坐标
* @param bottom 近平面bottom边的y坐标
* @param top 近平面top边的y坐标
* @param near 近平面距离摄像机的距离
* @param far 远平面距离摄像机的距离
*/
public static void orthoM(float[] m, int mOffset,
float left, float right, float bottom, float top,
float near, float far) {
}
正交投影的使用示例如下:
public class MatrixState {
private static float[] mProjMatrix = new float[16];
private static float[] mVMatrix = new float[16];
private static float[] mMVPMatrix;
public static void setCamera(
float cx, float cy, float cz,
float tx, float ty, float tz,
float upx, float upy, float upz
){
Matrix.setLookAtM(mVMatrix, 0, cx, cy, cz, tx, ty, tz, upx, upy, upz);
}
public static void setProjectOrtho(
float left, float right,
float bottom, float top,
float near, float far
){
Matrix.orthoM(mProjMatrix, 0, left, right, bottom, top, near, far);
}
}
private class SceneRenderer implements GLSurfaceView.Renderer{
public void onDrawFrame(GL10 gl) {
GLES30.glClear( GLES30.GL_DEPTH_BUFFER_BIT |
GLES30.GL_COLOR_BUFFER_BIT); //清除深度缓冲与颜色缓冲
}
public void onSurfaceChanged(GL10 gl, int width, int height) {
GLES30.glViewport(0, 0, width, height); //设置视口的大小及位置
float ratio= (float) width / height; //计算视口的宽高比
MatrixState.setProjectOrtho(-ratio, ratio, -1, 1, 1, 10);//设置正交投影
MatrixState.setCamera(0, 0, 3f, 0, 0, 0f, 0f, 1.0f, 0.0f);//设置摄像机
}
}
3、透视投影
现实世界中人眼观察物体时会有“近大远小”的效果,因此,要想开发出更加真实的场景, 仅使用正交投影是远远不够的,这时可以采用透视投影。透视投影的投影线是不平行的,他们相 交于视点。通过透视投影,可以产生现实世界中“近大远小”的效果,大部分 3D 游戏采用的都 是透视投影。
透视投影示意图如下图所示:
红点为摄像机位置(eyeX,eyeY,eyeZ) = (0, 0, 3)。 蓝色三角形为被观察的物体,绿色长方体为视景体,此时三角形全部在视景体内。 近平面各坐标: left=-1,right=1,top=2,bottom=-2, 近平面z坐标 = eyeZ - near=2, 远平面z坐标 = eyeZ - far = -2 。
使用Matrix.frustumM()来设置正交投影。
/**
* @param m 生成的投影矩阵,float[4*4]
* @param mOffset 填充时候起始的偏移量
* @param left 近平面left边的x坐标
* @param right 近平面right边的x坐标
* @param bottom 近平面bottom边的y坐标
* @param top 近平面top边的y坐标
* @param near 近平面距离摄像机的距离
* @param far 远平面距离摄像机的距离
*/
public static void frustumM(float[] m, int mOffset,
float left, float right, float bottom, float top,
float near, float far) {
}
透视投影的使用示例如下:
public class MatrixState {
private static float[] mProjMatrix = new float[16];
private static float[] mVMatrix = new float[16];
private static float[] mMVPMatrix;
public static void setCamera(
float cx, float cy, float cz,
float tx, float ty, float tz,
float upx, float upy, float upz
){
Matrix.setLookAtM(mVMatrix, 0, cx, cy, cz, tx, ty, tz, upx, upy, upz);
}
public static void setProjectOrtho(
float left, float right,
float bottom, float top,
float near, float far
){
Matrix.orthoM(mProjMatrix, 0, left, right, bottom, top, near, far);
}
public static void setProjectFrustum(
float left, float right,
float bottom, float top,
float near, float far
){
Matrix.frustumM(mProjMatrix, 0, left, right, bottom, top, near, far);
}
}
private class SceneRenderer implements GLSurfaceView.Renderer{
public void onDrawFrame(GL10 gl) {
GLES30.glClear( GLES30.GL_DEPTH_BUFFER_BIT |
GLES30.GL_COLOR_BUFFER_BIT); //清除深度缓冲与颜色缓冲
}
public void onSurfaceChanged(GL10 gl, int width, int height) {
GLES30.glViewport(0, 0, width, height); //设置视口的大小及位置
float ratio= (float) width / height; //计算视口的宽高比
MatrixState.setProjectFrustum(-ratio, ratio, -1, 1, 1, 10);//设置正交投影
MatrixState.setCamera(0, 0, 3f, 0, 0, 0f, 0f, 1.0f, 0.0f);//设置摄像机
}
}
4、near、far的取值范围规定:
- 正交投影时,摄像机可位于视景体中间,此时near < 0,far > 0,近平面位于视点后面(Z轴正方向),远平面位于视点前面(Z轴负方向)
- 正交投影时,视景体也可位于视点后面(Z轴正方向),此时near < 0, far < 0
- 正交投影时,far 和 near没有规定的大小关系,既可以far > near 也可以 far < near,只要物体在视景体内都可以被观察到。
- 透视投影时,摄像机必须位于视景体前面:eyeZ>近平面Z坐标 && eyeZ > 远平面Z坐标,即:eyeZ > (eyeZ - near) && eyeZ > (eyeZ - far)。
最后,欢迎大家一起交流学习:微信:liaosy666 ; QQ:2209115372 。