学习资料
十分感谢GcsSloop
,直接去看他的博客学习,图文并茂
Android
中有2个Camera
,android.hardware.Camera
和android.graphics.Camera
,看包名就可以区分出两个Camera
的作用。hardware
硬件,是摄像头;graphics
,图像,用于图形处理。android.hardware.Camera
在5.0
后被废弃,由android.hardware.Camera2
代替,具体使用可以看看Android Camera2 拍照入门学习 : )
1. android.graphics.Camera <p>
A camera instance can be used to compute 3D transformations and generate a matrix that can be applied, for instance, on a Canvas.
Camera
对象可以用来计算3D
变换,并将计算结果封装进一个Matrix
矩阵,之后便进行应用(ps:我这都啥破翻译)
Camera
可以用在画布上 。计算过程进行了封装,内部有一个Matrix
只有一个空的构造方法Camera()
Camera
既然可以用来做3D
三维变换,坐标系就和之前学习遇到的二维坐标系不同,是左手坐标系统,Y轴
在三维坐标系中是向上的,Z轴
是朝向屏幕里面的
Z轴
是朝里面的,屏幕像一个窗口,我们看到的是窗口外面的物体投射到窗口上的二维镜像。Camera
实际上就像我们的眼睛,眼睛看到的是物体投射到窗口上的图形,其实这里就有3个要素,一是物体,二是窗子,三是眼睛,也就是物体,屏幕和Camera
。最终呈现在用户面前的是屏幕上的图形。影响物体投射到屏幕上的效果,可以移动物体(Matrix
),也可以移动眼睛(setLocation()
方法)
以上从麻花儿wt的android camera 3d特效 详解与进阶摘抄
在一个虚拟的3D的立体空间中,由于我们无法直接用眼睛去观察这一个空间,所以要借助摄像机采集信息,制成2D影像供我们观察。简单来说,摄像机就是我们观察虚拟3D空间的眼睛。<p>
Android 上面观察View的摄像机默认位置在屏幕左上角,而且是距屏幕有一段距离的,假设灰色部分是手机屏幕,白色是上面的一个View,摄像机位置看起来大致就是下面这样子的(为了更好的展示摄像机的位置,做了一个空间转换效果的动图)。
Camera
默认距离为-8
,1
为72像素
,在坐标系中(0,0,-576)
以上从GcsSloop 安卓自定义View进阶-Matrix Camera摘抄
对于一个像素点的矩阵来说
1
为Camera
在Z轴
的默认值,比1
大,代表相对于默认位置,将屏幕进行拉远。远小近大,值越大就越远,投射到Camera
上的图像也就也小
2. 方法 <p>
Camera
中方法并不算多
原始图像只是将Bitmap
宽高缩小为1/2
后,绘制在了画布上
2.1 translate(float x, float y, float z) <p>
方法的名字和参数都比较容易理解,这个方法可以理解为移动了物体,但z
这个值,会影响x,y
的值。
例如mCamera.translate(100,0,100)
,x
的值为100,但最终显示效果,图像右移的距离并没有100。z
值导致图像缩放,移动距离也进行了缩放
Y轴
是向上的,mCamera.translate(0,30,0)
与mMatrix.translate(0,-30)
效果是一样的
2.2 rotate(float x, float y, float z) <p>
这个方法是rotateX(float x),rotateY(float y),rotateZ(float z)
的综合
以默认点左上角为中心绕值不为0
的轴顺时针进行旋转
例如rotate(30,0,0)
,就是以左上角为中心,绕X轴
顺时针旋转30°
x
的值为角度,0°到360°
简单使用:
/**
* 初始化
*/
private void init() {
mCamera = new Camera();
mMatrix = new Matrix();
BitmapFactory.Options options = new BitmapFactory.Options();
options.inSampleSize = 2;
options.inPreferredConfig = Bitmap.Config.RGB_565;
mBitmap = BitmapFactory.decodeResource(getResources(), R.drawable.test, options);
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
mCamera.save();
mCamera.rotate(180,0,0);
mCamera.getMatrix(mMatrix);
mCamera.restore();
mMatrix.postTranslate(0,500);
canvas.drawBitmap(mBitmap,mMatrix, null);
}
mMatrix.postTranslate(0,500)
,矩阵后乘,由于图片默认以左上角为旋转中心,绕着x轴
旋转180°
,图片已经超出了屏幕,使用后乘平移,将图片再移动到屏幕范围内。不可以setTanslate()
,因为set
方法会将原先的矩阵的值清空,成为初始矩阵
其他同理
2.3 setLocation(float x, float y, float z) <p>
设置相机的位置,默认为-8
简单修改代码,修改相机的位置
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
mCamera.save();
mCamera.setLocation(0,0,-30);//设置相机位置
mCamera.rotate(0,30,0);
mCamera.getMatrix(mMatrix);
mCamera.restore();
mMatrix.postTranslate(0,500);
canvas.drawBitmap(mBitmap,mMatrix, null);
}
Y轴
方向是向屏幕里的,所以-30
比-8
要离物体远,这样旋转的最终效果就会减轻,根据生活经验,手机拍照时,手机距离拍摄物的远近,物体进行同样角度的改变,照片的效果并不完全一样。但Z轴
的值并不会影响平移操作
3.结合动画,形成简单的3D效果 <p>
代码是从GcsSloop 安卓自定义View进阶-Matrix Camera学到,里面涉及到的优化原理讲的很好
动画代码:
public class Rotate3DAnimation extends Animation {
private final float mFromDegrees;
private final float mToDegrees;
private final float mCenterX;
private final float mCenterY;
private final float mDepthZ;
private final boolean mReverse;
private Camera mCamera;
float scale = 1; // 像素密度
/**
* 创建一个绕y轴旋转的3D动画效果,旋转过程中具有深度调节,可以指定旋转中心。
* @param context <------- 添加上下文,为获取像素密度准备
* @param fromDegrees 起始时角度
* @param toDegrees 结束时角度
* @param centerX 旋转中心x坐标
* @param centerY 旋转中心y坐标
* @param depthZ 最远到达的z轴坐标
* @param reverse true 表示由从0到depthZ,false相反
*/
public Rotate3DAnimation(Context context, float fromDegrees, float toDegrees,
float centerX, float centerY, float depthZ, boolean reverse) {
mFromDegrees = fromDegrees;
mToDegrees = toDegrees;
mCenterX = centerX;
mCenterY = centerY;
mDepthZ = depthZ;
mReverse = reverse;
// 像素密度
scale = context.getResources().getDisplayMetrics().density;
}
@Override
public void initialize(int width, int height, int parentWidth, int parentHeight) {
super.initialize(width, height, parentWidth, parentHeight);
mCamera = new Camera();
}
@Override
protected void applyTransformation(float interpolatedTime, Transformation t) {
final float fromDegrees = mFromDegrees;
float degrees = fromDegrees + ((mToDegrees - fromDegrees) * interpolatedTime);
final float centerX = mCenterX;
final float centerY = mCenterY;
final Camera camera = mCamera;
final Matrix matrix = t.getMatrix();
camera.save();
// 调节深度
if (mReverse) {
camera.translate(0.0f, 0.0f, mDepthZ * interpolatedTime);
} else {
camera.translate(0.0f, 0.0f, mDepthZ * (1.0f - interpolatedTime));
}
// 绕y轴旋转
camera.rotateY(degrees);
camera.getMatrix(matrix);
camera.restore();
// 修正失真,主要修改 MPERSP_0 和 MPERSP_1
float[] mValues = new float[9];
matrix.getValues(mValues); //获取数值
mValues[6] = mValues[6]/scale; //数值修正
mValues[7] = mValues[7]/scale; //数值修正
matrix.setValues(mValues); //重新赋值
// 调节中心点
matrix.preTranslate(-centerX, -centerY);
matrix.postTranslate(centerX, centerY);
}
}
Activity
代码:
public class CameraGActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_camera_g);
initView();
}
private void initView() {
ImageView iv = (ImageView) findViewById(R.id.iv_camera_g_activity);
iv.setImageResource(R.drawable.test);
iv.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
// 计算中心点(这里是使用view的中心作为旋转的中心点)
final float centerX = v.getWidth() / 2.0f;
final float centerY = v.getHeight() / 2.0f;
//括号内参数分别为(上下文,开始角度,结束角度,x轴中心点,y轴中心点,深度,是否扭曲)
final Rotate3DAnimation rotation = new Rotate3DAnimation(CameraGActivity.this, 0, 360, centerX, centerY, 0f, true);
rotation.setDuration(3000);
rotation.setFillAfter(true);
rotation.setInterpolator(new LinearInterpolator());
v.startAnimation(rotation);
}
});
}
}
优化就是修正失真,主要修改 MPERSP_0
和 MPERSP_1
4. 最后
本篇内容的学习,是最近学习过程中,效率最低的,Camera
与物体,屏幕三者的关系没有搞清楚,一开始搜到的学习博客,感觉有错误,质量不是很高。
强烈推荐学习GcsSloop的系列博客,感觉质量都很高,真正的图文并茂
本人很菜,写的很水,有错误请指出
共勉 : )