仅在垂直方向上扭曲位图

8
我希望您能将位图倾斜(如果这不是正确的词,请纠正我),以便它看起来具有深度。一个好的可视化方式是,想象一下星球大战的字幕如何倾斜以显示深度。
我尝试了以下方法:
canvas.getMatrix().postSkew(kx,ky,px,py);

并且

canvas.skew(sx,sy);

但是我没有取得太大的成功。以上方法似乎总是将位图转换为平行四边形。有没有一种方法可以将位图转换为梯形呢?

这是我从Romain指给我的示例中提取的一小段代码。

canvas.rotate(-mOrientation[0] + mHeading, mCenterX, mCenterY);

camera.save();

if (mReverse) {
    camera.translate(0.0f, 0.0f, mDepthZ * interpolatedTime);
} else {
    camera.translate(0.0f, 0.0f, mDepthZ * (1.0f - interpolatedTime));
}

camera.rotateX(mOrientation[1]);
camera.applyToCanvas(canvas);
canvas.drawPath(mPath, mPaint);
canvas.drawCircle(mCenterX, mCenterY, mRadius - 37, mPaint);

camera.restore();
3个回答

13

我今天花了很多时间在这上面(遇到了同样的问题),并编写了以下代码。

需要注意的关键一点是,你需要将preTranslate()和postTranslate()设置到画布区域的中心(或其他位置)。似乎意味着它使用图像的中心来应用变换,而不是默认的左上角(x=0,y=0)。这就是为什么你会得到一个平行四边形而不是你期望的梯形(感谢你教给我这些名字)。

我学到的另一个重要事项是Canvas/Camera上的Save/Restore函数。基本上,如果你连续三次调用Rotate函数而没有每次都恢复状态,你将保持围绕自身不断旋转的对象。这可能是你想要的,但在我的情况下肯定不是。对画布也是同样的道理,因为你基本上是将相机对象的矩阵应用于画布上,所以需要重置,否则会发生同样的事情。

希望这能帮助到某些人,这对初学者来说并不是很好文档化。给任何阅读这篇文章的人一个提示,看看SDK示例中的APIDemos文件夹。其中有一个Rotate3dAnimation.java文件,也演示了这一点。

//Snippet from a function used to handle a draw
mCanvas.save(); //save a 'clean' matrix that doesn't have any camera rotation in it's matrix
ApplyMatrix(); //apply rotated matrix to canvas
Draw(); //Does drawing
mCanvas.restore(); //restore clean matrix
//    

public void ApplyMatrix() {
  mCamera.save();
  mCamera.rotateX(-66);
  mCamera.rotateY(0);
  mCamera.rotateZ(0);
  mCamera.getMatrix(mMatrix);

  int CenterX = mWidth / 2;
  int CenterY = mHeight / 2; 
  mMatrix.preTranslate(-CenterX, -CenterY); //This is the key to getting the correct viewing perspective
  mMatrix.postTranslate(CenterX, CenterY); 

  mCanvas.concat(mMatrix);
  mCamera.restore();    
}

这似乎符合我的要求。我仍然很难使用方向值(方位角、俯仰角、翻滚角)来转换矩阵并操作画布。我正在尝试实现类似于原生Android相册的效果,即当设备向左或向右倾斜时,图像似乎保持不变(根据用户视角的方向)。 - mdupls
这似乎是我遇到的类似问题,只不过我同时处理位图和文本。请您也看看这个问题:http://stackoverflow.com/q/32180534/878126 - android developer

6

使用skew()函数无法实现您想要的效果。但是,您可以使用Camera对象和3D旋转来实现此效果。相机将为您生成一个矩阵,然后您可以将其应用于画布上。请注意,结果可能不是透视正确的,但对于您的目的而言足够好了。例如,在Honeycomb的Launcher中(以及许多其他应用程序中)就是这样完成3D旋转的。


3
是的,在ApiDemos中有一个例子——旋转3D动画,其中使用了Camera类。创建一个新的Android项目,选择“从现有示例创建项目”,选择目标操作系统,然后选择ApiDemos。当应用程序正在运行时,选择View > Animation > 3D transition。 - Lumis
我认为动画不是解决问题的方法。我正在根据设备传感器值的持续流来操作画布上的图形(增强现实)。还有其他方法可以做到这一点吗?我应该使用像OpenGL这样的3D图形吗?谢谢。 - mdupls
你不需要动画。那个演示使用我提到的Camera对象来进行3D变换。这是如何使用Camera的示例。你不需要OpenGL,只需要android.graphics.Camera。 - Romain Guy
我已经查看了演示,但是在将旋转围绕屏幕中心进行时遇到了困难。例如,给定一个正方形,当沿任何轴旋转时,我希望正方形的中心保持在屏幕中央。我已经用我目前正在使用的代码编辑了我的问题。 - mdupls
这似乎是我遇到的相似问题,只不过我同时处理位图和文本。你能否也看一下这个问题:http://stackoverflow.com/q/32180534/878126 - android developer

1

我认为“星球大战效应”不是仿射变换,而这些变换是Matrix支持的唯一操作。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接