我一直在使用Android的Canvas
做一些工作,特别是试图确定其getClipBounds
结果的确定方式。我了解Canvas
在内部保留了一个转换Matrix
,该转换会在我调用translate
,scale
等时更新,但尝试复制Matrix
的结果已经困惑我。
@Override
public void onDraw(Canvas canvas) {
Rect clipBounds;
RectF viewport;
canvas.save();
canvas.concat(translationMatrix);
//viewportMatrix.preConcat(canvas.getMatrix());
viewportMatrix.set(canvas.getMatrix());
clipBounds = canvas.getClipBounds();
viewport = GetViewport();
Log.d("clipBounds", clipBounds.toString() + " (" + clipBounds.width() + ", " + clipBounds.height() + ")");
Log.d("viewport", viewport.toString() + " (" + viewport.width() + ", " + viewport.height() + ")");
//drawing is done here
canvas.restore();
}
//viewport code modeled after http://stackoverflow.com/a/17142856/2245528
private RectF GetViewport() {
RectF viewport = new RectF();
viewportMatrix.mapRect(viewport, originalViewport);
return viewport;
}
private void Translate(float x, float y) {
translationMatrix.postTranslate(x, y);
invalidate();
}
private void Scale(float scaleFactor, PointF focusPoint) {
if (focusPoint == null) {
translationMatrix.postScale(scaleFactor, scaleFactor);
}
//keep the focus point in focus if possible
else {
translationMatrix.postScale(scaleFactor, scaleFactor, focusPoint.x, focusPoint.y);
}
invalidate();
}
private final Matrix translationMatrix = new Matrix();
private final RectF originalViewport = new RectF();
private final Matrix viewportMatrix = new Matrix();
originalViewport
设置为0, 0, canvas.getWidth(), canvas.getHeight()
。 <{1}}和Translate
是从手势事件处理程序调用的,它们正常工作。
令我困惑的部分是Scale
。我是否
viewportMatrix
或
viewportMatrix.set(canvas.getMatrix());
甚至一次性致电
viewportMatrix.preConcat(canvas.getMatrix());
在开头,然后是对两个矩阵的并排viewportMatrix.set(canvas.getMatrix());
/ Translate
调用。我甚至试图完全忽略Scale
的内置Canvas
并重写Matrix
为
GetViewport
我似乎永远不会匹配//viewport code modeled after http://stackoverflow.com/a/17142856/2245528
private RectF GetViewport() {
RectF viewport = new RectF();
translationMatrix.mapRect(viewport, originalViewport);
return viewport;
}
,而且差异非常严重:
getClipBounds()
:
clipBounds:Rect(-97,-97 - 602,452)(699,549)
视口:RectF(97.04178,97.06036,797.04175,647.06036)(700.0,550.0)
viewportMatrix.set(canvas.getMatrix)
:
clipBounds:Rect(-97,-96 - 602,453)(699,549)
viewport:RectF(2708.9663,2722.2754,3408.9663,3272.2754)(700.0,550.0)
viewportMatrix.preConcat(canvas.getMatrix)
:
clipBounds:Rect(-96,-96 - 603,453)(699,549)
viewport:RectF(96.73213,96.85794,796.7321,646.8579)(700.0,550.0)
对translationMatrix.mapRect
进行一次性通话,然后是并排的viewportMatrix.preConcat(canvas.getMatrix())
/ Translate
来电:
clipBounds:Rect(-96,-97 - 603,452)(699,549)
视口:RectF(96.57738,97.78168,796.5774,647.7817)(700.0,550.0)
对Scale
进行一次性通话,然后是并排的viewportMatrix.set(canvas.getMatrix())
/ Translate
来电:
clipBounds:Rect(-96,-96 - 603,453)(699,549)
viewport:RectF(96.40051,96.88153,796.4005,646.88153)(700.0,550.0)
我甚至无法检查the Canvas
source,因为所有Scale
代码都会消失为未显示代码的私有本机调用。
为什么我的Matrix
电话如此严重,以及GetViewport
在幕后发生了什么?
答案 0 :(得分:1)
我通读this answer on GameDev SE,它使用矩阵反转在屏幕和世界坐标系之间交换:
要从屏幕转到世界空间,只需使用Vector2.Transform即可。这通常用于获取鼠标在世界中的位置以进行对象拾取。
Vector2.Transform(mouseLocation, Matrix.Invert(Camera.TransformMatrix));
从世界到屏幕空间只需做相反的事情。
Vector2.Transform(mouseLocation, Camera.TransformMatrix);
受这种方法的启发,我尝试反转变换矩阵,如下所示:
private RectF GetViewport() {
RectF viewport = new RectF();
Matrix viewportMatrix = new Matrix();
translationMatrix.invert(viewportMatrix);
viewportMatrix.mapRect(viewport, originalViewport);
return viewport;
}
此视口正确匹配getClipBounds
返回的结果。
This matrix tutorial解释了我在transform
次调用的结果中注意到的内容,但没有应用于我的矩阵:
在计算机程序中,相机根本不会移动,实际上,世界正朝着相反的方向和方向移动,希望相机在现实中移动。< / p>
为了正确理解这一点,我们必须考虑两个不同的事情:
- 相机转换矩阵:将相机置于世界空间中的正确位置和方向的转换(如果您愿意,可以应用于相机的3D模型的转换在场景中代表它。)
- 视图矩阵:此矩阵将顶点从世界空间转换为视图空间。 此矩阵是上述相机变换矩阵的反转。
醇>