您的位置:首页 > 其它

Libgdx专题系列:镜头篇源码分析 Camera

2013-12-10 17:13 323 查看
声明:

本系列文章使用的Libgdx版本均为0.99版本

Libgdx游戏开发交流群 323876830



在Opengl中,有许多矩阵变换,可以分为视角(Viewing),模型(Modeling)和投影(Projection)操作,这些操作可以有选择,平移,缩放,正侧投影,透视投影等。

如果我们使用照相机拍照的过程做类比,可以更好的理解3D 坐标变换的过程。



拍照时第一步是架起三角架并把相机的镜头指向需要拍摄的场景,对应到3D 变换为viewing transformation (平移或是选择Camera )
然后摄影师可能需要调整被拍场景中某个物体的角度,位置,比如摄影师给架好三角架后给你拍照时,可以要让你调整站立姿势或是位置。对应到3D绘制就是Modeling transformation (调整所绘模型的位置,角度或是缩放比例)。
之后摄影师可以需要调整镜头取景(拉近或是拍摄远景),相机取景框所能拍摄的场景会随镜头的伸缩而变换,对应到3D绘图则为Projection transformation(裁剪投影场景)。
按下快门后,对于数码相机可以直接在屏幕上显示当前拍摄的照片,一般可以充满整个屏幕(相当于将坐标做规范化处理NDC),此时你可以使用缩放放大功能显示照片的部分。对应到3D绘图相当于viewport transformation (可以对最终的图像缩放显示等)
下图为Android OpenGL ES坐标变换的过程:





Object Coordinate System: 也称作Local coordinate System,用来定义一个模型本身的坐标系。
World Coordinate System: 3d 虚拟世界中的绝对坐标系,定义好这个坐标系的原点就可以用来描述模型的实现的位置,Camera 的位置,光源的位置。
View Coordinate System: 一般使用用来计算光照效果。
Clip Coordinate System: 对3D场景使用投影变换裁剪视锥。
Normalized device coordinate System (NDC): 规范后坐标系。
Windows Coordinate System: 最后屏幕显示的2D坐标系统,一般原点定义在屏幕左上角。


好了,上面只是对opengl三维变换知识的一个普及。 下面我们将要针对Libgdx中怎么处理这些东西的做一下分析。



Viewing和Modeling(MODELVIEW) 变换

为什么把这两个放在一起呢?我们可以这样想想, 当我们拉近镜头(物体不动)的时候,和物体靠近镜头(镜头不动),

或者镜头视角向上偏移(物体不动)和物体视角相对镜头向下偏移, 效果是一样的。 如下图:



view变换在Camera中给我们提供了所需字段 镜头位置,镜头指向目标位置的方向,镜头观测点方向为“上”的向量

/** the position of the camera **/
	public final Vector3 position = new Vector3();
	/** the unit length direction vector of the camera **/
	public final Vector3 direction = new Vector3(0, 0, -1);
	/** the unit length up vector of the camera **/
	public final Vector3 up = new Vector3(0, 1, 0);

变换的结果存储在view矩阵中

/** the view matrix **/
 public final Matrix4 view = new Matrix4();

model的变换的操作其实都已经移交到view变换中了, 所以就没有单独计算了。



投影变换Projection

在Opengl中的两种投影变换对应于Camera中的两个子类OrthographicCamera和PerspectiveCamera,分别是正投影和

透视投影。

先看看透视投影,如下图



粉色区域就是我们要得到的区域,又叫视锥。需要的数据也就有 视锥的view angle,视锥的宽高比,裁剪面的近距离,创建面的远距离

在PerspectiveCamera透视投射镜头中,我们也可以找到这些我们所需要的数据。

/** the field of view in degrees **/
	public float fieldOfView = 67;
/** the near clipping plane distance, has to be positive **/
	public float near = 1;
	/** the far clipping plane distance, has to be positive **/
	public float far = 100;

组装投射矩阵数据

float aspect = viewportWidth / viewportHeight;
		projection.setToProjection(Math.abs(near), Math.abs(far), fieldOfView, aspect);

下图为正投影镜头



它的视锥为一长方体,特点是物体的大小不随到观测点的距离而变化,投影后可以保持物体之间的距离和夹角。

在OrthographicCamera中表示

this.near = 0;
projection.setToOrtho(zoom * -viewportWidth / 2, zoom * (viewportWidth / 2), zoom * -(viewportHeight / 2), zoom
			* viewportHeight / 2, near, far);


在绘制的时候,我们可以使用Camera的apply方法,应用矩阵

public void apply (GL10 gl) {
		gl.glMatrixMode(GL10.GL_PROJECTION);
		gl.glLoadMatrixf(projection.val, 0);
		gl.glMatrixMode(GL10.GL_MODELVIEW);
		gl.glLoadMatrixf(view.val, 0);
	}



这里要多提一下SpriteBatch中使用镜头的方式

GL10 gl = Gdx.gl10;
			gl.glMatrixMode(GL10.GL_PROJECTION);
			gl.glLoadMatrixf(projectionMatrix.val, 0);
			gl.glMatrixMode(GL10.GL_MODELVIEW);
			gl.glLoadMatrixf(transformMatrix.val, 0);

大家有没有发现有点诡异?

在投射模式下使用的是projectionMatrix投影矩阵,乍一看是没什么问题, 但是这个projectionMatrix是由

投影矩阵和view变换矩阵的组合矩阵

combined.set(projection);
		Matrix4.mul(combined.val, view.val);

projectionMatrix其实就是combined

而transformMatrix这个也不是我们上面的view变换矩阵,而是一个空矩阵,可以让我们来set进去的。



好了,矩阵变换就到这里了, 有什么问题大家可以多多指教。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: