在上文中实现的OpenGL画线效果比较粗糙,但Canvas做绘制线条这方面的比较好用而且方便;但是Canvas移动图形实在是太慢了,所以我试着把两者结合起来使用——Canvas做线条绘制,当需要缩放和移动画面时,使用OpenGL加速。

 

一、坐标的摆弄:

默认长宽比为16比9的情况下,OpenGL的坐标如图所示:

Android surfaceView透明问题 android canvas surface_Canvas

 

无论什么分辨率,GLSurfaceView都会把视口设定成如上图所示的坐标,然后用百分比的方式读取

而Canvas的坐标如下所示(以1920*1080像素为例):

Android surfaceView透明问题 android canvas surface_高速_02

 

 

为了方便坐标对齐,我决定使用GLSurfaceView的右下角象限进行绘图,并且为了有最大到200%的的放大率,需要先预先把Z轴设定为-2f,也就是把整个画面往前“推”一下,此时坐标情况如下:

Android surfaceView透明问题 android canvas surface_OpenGL_03

 

然后通过gl.glTranslatef(-2f * ratio, 2f, -2f) 平移画面到右下象限,此时的坐标如下:

Android surfaceView透明问题 android canvas surface_OpenGL_04

此时,通过下面的一系列换算,即可把Canvas坐标投射到GLSurfaceView的坐标系中(在还没漫游过的情况下):

glX = canvasX / canvas宽 * 16 / 9 * 4

glY = - canvasY / canvas宽  * 4

 

 

 

 

二、缩放

缩放方面,Canvas和GLSurfaceView完全是不同的逻辑,从上一章的知识中可以发现,GLSurfaceView从默认的视距到2倍的视距时,坐标系在视口大小一样的情况下,单位数变成了2倍,也意味就像现实世界中的近大远小法则——等同速度的物体,越靠近观察者,视觉上移动速度越快。即:

当视距为1倍时,物体移动1个单位,在视口中实际显示的是移动1个单位;

当视距为2倍时,物体移动1个单位,在视口中实际显示的只会是移动1/2个单位。

而在Canvas中,无论怎么缩放,坐标轴是不会发生任何变化的。

 

那我们针对某一个缩放中心缩放一定的比例之后,如何使得两个模式显示的画面依然可以同步起来呢?

 

我们以Canvas中的画面,以(1920,1080)缩小到原来的50%来考虑这个问题:

设定Scale为0.5。

 

Android surfaceView透明问题 android canvas surface_高速_05

 

 

       此时已知Canvas已缩放Scale(0.5)的大小,那么我们的OpenGL画布需要推更远来使得画面看起来更小,例如变为原来的一半大小即Z轴的负数变大两倍,所以我们需要把Z轴的值调整为 -2f * (1 / scale),此时,你会看到OpenGL画布的内容以屏幕中心为缩放中心,所有图案缩小面积为原来的二分之一。

       但此时,OpenGL显示的内容虽然和Canvas显示的内容大小已经一样,但是方位却产生了错位,必须进行纠正。

       此时可以认为OpenGL的矩形x轴已经移动了(1-scale)比例那么多的位置量,那么如果我们现在要把它重新退回x为0的位置,则Canvas的方式下需要偏移(-1920 * (1 - scale))的单位量,而由于OpenGL存在Z轴,所以移动量要按照Z轴的距离乘以那么多倍(见第一章),所以OpenGL方式下需要偏移(-1920 * (1 - scale)) *  Z轴大小。而我们的缩放中心是1920,则相当于要右移OpenGL矩形到目标方位的话,需要(1920 * 2 - 1920 * (1 - scale))*  Z轴大小,然后再除以OpenGL视口的宽度得到比例值,从而最终得到确切的缩放后的偏移量。

glDx  = (缩放中心x * 2 -1920 * (1 - scale)) *  Z轴大小 / OpenGL视口宽度

glDy  = (缩放中心y * 2 -1080 * (1 - scale)) *  Z轴大小 / OpenGL视口宽度

 

 

效果如下:

Android surfaceView透明问题 android canvas surface_高速_06