学习资料

  • GcsSloop 安卓自定义View进阶-Matrix Camera
  • 麻花儿wt的android camera 3d特效 详解与进阶

十分感谢GcsSloop,直接去看他的博客学习,图文并茂


Android中有2个Cameraandroid.hardware.Cameraandroid.graphics.Camera,看包名就可以区分出两个Camera的作用。hardware硬件,是摄像头;graphics,图像,用于图形处理。android.hardware.Camera5.0后被废弃,由android.hardware.Camera2代替,具体使用可以看看Android Camera2 拍照入门学习 : )


1. android.graphics.Camera

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轴是朝向屏幕里面的

3维左手坐标系

Z轴是朝里面的,屏幕像一个窗口,我们看到的是窗口外面的物体投射到窗口上的二维镜像。Camera实际上就像我们的眼睛,眼睛看到的是物体投射到窗口上的图形,其实这里就有3个要素,一是物体,二是窗子,三是眼睛,也就是物体,屏幕和Camera。最终呈现在用户面前的是屏幕上的图形。影响物体投射到屏幕上的效果,可以移动物体(Matrix),也可以移动眼睛(setLocation()方法)

以上从麻花儿wt的android camera 3d特效 详解与进阶摘抄


在一个虚拟的3D的立体空间中,由于我们无法直接用眼睛去观察这一个空间,所以要借助摄像机采集信息,制成2D影像供我们观察。简单来说,摄像机就是我们观察虚拟3D空间的眼睛。


Android 上面观察View的摄像机默认位置在屏幕左上角,而且是距屏幕有一段距离的,假设灰色部分是手机屏幕,白色是上面的一个View,摄像机位置看起来大致就是下面这样子的(为了更好的展示摄像机的位置,做了一个空间转换效果的动图)。

Camera位置

Camera默认距离为-8172像素,在坐标系中(0,0,-576)

以上从GcsSloop 安卓自定义View进阶-Matrix Camera摘抄


对于一个像素点的矩阵来说

一个像素点矩阵

1CameraZ轴的默认值,比1大,代表相对于默认位置,将屏幕进行拉远。远小近大,值越大就越远,投射到Camera上的图像也就也小


2. 方法

Camera中方法并不算多

原始图像

原始图像只是将Bitmap宽高缩小为1/2后,绘制在了画布上


2.1 translate(float x, float y, float z)

方法的名字和参数都比较容易理解,这个方法可以理解为移动了物体,但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)

这个方法是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);    }
以控件左上角为旋转中心,绕x轴旋转180°

mMatrix.postTranslate(0,500),矩阵后乘,由于图片默认以左上角为旋转中心,绕着x轴旋转180°,图片已经超出了屏幕,使用后乘平移,将图片再移动到屏幕范围内。不可以setTanslate(),因为set方法会将原先的矩阵的值清空,成为初始矩阵

其他同理


2.3 setLocation(float x, float y, float z)

设置相机的位置,默认为-8

相机在默认位置,绕Y轴旋转30°

简单修改代码,修改相机的位置

    @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效果

代码是从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_0MPERSP_1


4. 最后

本篇内容的学习,是最近学习过程中,效率最低的,Camera与物体,屏幕三者的关系没有搞清楚,一开始搜到的学习博客,感觉有错误,质量不是很高。

强烈推荐学习GcsSloop的系列博客,感觉质量都很高,真正的图文并茂

本人很菜,写的很水,有错误请指出

共勉 : )

更多相关文章

  1. 【Android(安卓)进阶】Iconfont 图标的使用以及自定义
  2. Android(安卓)UI开发第十一篇――右上角带个泡泡
  3. Android之利用android:indeterminateDrawable来实现ProgressBar
  4. Android进阶之抢购倒计时功能
  5. Android属性动画2-----自定义属性动画
  6. Android音频进阶
  7. Android自定义组件系列【7】——进阶实践(4)
  8. android UI进阶之自定义组合控件
  9. [sg] Android(安卓)4.4 屏幕旋转的两种方式

随机推荐

  1. android的PowerManager和PowerManager.Wa
  2. 初识android
  3. Android(Java):Android(安卓)事件分发机
  4. Android应用程序启动过程源代码分析
  5. 【Tech-Android-Other】android中的Parce
  6. android Content Provider 详解
  7. [转]Android(安卓)实现TextView中文字链
  8. android 实现静默安装、卸载(图)
  9. 个人对android中项目命名规则的整理
  10. Android(安卓)Studio中Can't resolve sym