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

声明:

本系列文章使用的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进去的。

     

    好了,矩阵变换就到这里了, 有什么问题大家可以多多指教。

  • 3
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值