嗯?学习3D效果还有便捷模式?Camera解析及其调试代码实现

最近在复习自定义view相关的知识点,也不是说为了面试,就是懒,这个简单一点。既然都没达到深入浅出的目的,那就看书。 《Android自定义控件高级进阶与精彩实例》 这本书挺好的,启航大佬两本书都看,别的不说,起码自定义view相关的基础知识还是补了上来。这次主要还是将这本书上第一章《3D特效》上的知识点进行汇总共享。

emmmm,还是建议看看看原文。

正文

说到3D特效,我记得昨年到处都在是3D特效的实现blog。有一丢丢的自定义view基础的我,嗯,看到脑阔大,毕竟自己矩阵学得差,自己算Matrix,感觉可以要了我的老命。但是现在不一样了,从书中看到了一个类: android.graphics.Camera。既然3D都做的出来,那么小小的viewGroup转场动画不是信手拈来? OK,那么直接开整。

3D和2D的区别

这个概念逻辑尤为的重要,可以大致的精炼为以下几点:

  • 手机屏幕就是2D,左上角到右上角为X+,左上角到左下角为Y+。
  • 3D坐标系中,左上角到右上角为X+,y轴则是沿着屏幕向上,Z轴则是垂直屏幕向里。这里偷一张图:
  • 3D坐标系分为,左手坐标系和右手坐标系。计算机通常用左右坐标系, 默认说的也是左手坐标系。数学中右手坐标系用得较多。

手背向上用左手比左手坐标系的手势,就是屏幕上的3D坐标。

3D坐标系与2D坐标系的转换关系

这个贼复杂,我们能做的就是在2D屏幕上做出看起来是3D的效果,所以在屏幕上的核心还是基于Matrix,所以记住matrix即可。那么我们除了手动计算matrix,有没有工具类呢? 答案就是: android.graphics.Camera

android.graphics.Camera 介绍

还是上官网地址:google官网Camera 这个类的介绍相当直白:

可用于计算 3D 变换并生成可应用于 Canvas

既然3D是人眼的观看感受,那么这个动效就分为两个类别

  • 基于某个方向平移,就是靠近某物,或者远离某物,对应的函数是:translate(float x, float y, float z)
  • 基于某个方向平移视角,就是旋转脑袋。对应的函数:rotate(float x, float y, float z) 或者 rotateX(float deg)rotateY(float deg)rotateZ(float deg) 等。

当然还有其他函数,比如说设置视角的开始位置:setLocation(float x, float y, float z) 。OK,道理都懂了,我们还是看一下官方提供的函数:

Public methods
void applyToCanvas(Canvas canvas)Computes the matrix corresponding to the current transformation and applies it to the specified Canvas.
float dotWithNormal(float dx, float dy, float dz)
float getLocationX()Gets the x location of the camera.
float getLocationY()Gets the y location of the camera.
float getLocationZ()Gets the z location of the camera.
void getMatrix(Matrix matrix)Computes the matrix corresponding to the current transformation and copies it to the supplied matrix object.
void restore()Restores the saved state, if any.
void rotate(float x, float y, float z)Applies a rotation transform around all three axis.
void rotateX(float deg)Applies a rotation transform around the X axis.
void rotateY(float deg)Applies a rotation transform around the Y axis.
void rotateZ(float deg)Applies a rotation transform around the Z axis.
void save()Saves the camera state.
void setLocation(float x, float y, float z)Sets the location of the camera.
void translate(float x, float y, float z)Applies a translation transform on all three axis.

location(x,y,z)

当我们创建camera对象后,直接获取location,可以发现x=0,y=0,z=-8。那么应该怎么理解这个location呢?通俗的讲,这个就是3D坐标,这个坐标代表什么意思呢?

通俗的讲就是物品不动,人在不停的换位置去观看这个物体。

  • 当z 的值约小,结合手背朝上的左手3D坐标系,说明这个屏幕离我们越近,所以说这个可以看作是基于某个点的方法。等于0的时候视角重合就看不到东西。所以无限趋近于0的且为负数的时候,图片最小。
  • 当z值约大,结合手背朝上的左手3D坐标系,说明屏幕离我们越来越远,所以无限趋近于0 但是为正的时候,图片最大。
  • x的值结合z轴的值,就可以概括为X加的时候就是基于视角点往左移动,X减的时候就是往右移动。
  • Y的值同理。Y加的时候向屏幕下面移动,Y减的时候,向屏幕上面移动。

translate(x,y,z)

直接翻译出来就是平移的意思。这个和location有一些不同。这个感觉像是视角的移动,但是人是不移动的。比如说,频繁调用camera.translate(0f, 0f, 1f) 结合上面的知识,这个看起来就是缩小,反之 camera.translate(0f, 0f, -1f) 就是放大,x于y的变动也是类似逻辑。但是这个函数有一个特点,就是获取location获取下来的x、y、z是没变动的。

rotate(x,y,z)

这个直接翻译为旋转。所以这个逻辑上location获取下来的x、y、z是不会变动的。

  • 比如说不停的设置camera.rotateX(1f) 就是基于X轴不动,感觉物体的往屏幕上翻,那么 camera.rotateX(-1f) 就是物品往屏幕下翻。总结就是:基于X轴,参数为正,往上翻,参数为负往下翻
  • 结合X的经验。camera.rotateY(1f) 就是基于Y轴,物品往屏幕里面翻,参数为正就是基于Y轴往外翻。总结就是:基于Y轴,参数为正往里面翻,参数为负往外面翻
  • 那么Z轴也应该是;基于Z轴进行反转,参数为正往上翻,参数为负往下翻。

调试代码的实现

道理都懂,我们还是需要看一下是否是自己分析的结果。 回归初心,我们主要是基于camera 获取一个Matrix,而camera 提供Matrix 主要是两个函数:

  • applyToCanvas(Canvas canvas) 把canvas 传递进去,会在native层,把值赋值上去。
  • getMatrix(Matrix matrix) 传递一个matrix进去。然后把值给matrix 对象。最后,我们需要将matrix 赋值给canvas。

那么我们基于AppCompatImageView 整一个自定view。然后通过canvas 绘制一张bitmap。核心代码:

scss 复制代码
override fun onDraw(canvas: Canvas) {
    super.onDraw(canvas)
    canvas.save()
    camera?.let {
        it.save()
        it.applyToCanvas(canvas)
        it.restore()
    }
    canvas.drawBitmap(bitmap, rect, rect, paint)
    canvas.restore()
}

所以调试代码运行出来:

浮动到上面的是我们获取到的matrix 绘制的bitmap。 完整代码

总结

全篇涉及到的知识点还是有的,只是说有些和2D图像逻辑有点差异。下面罗列下知识点:

  • 手机屏幕就是2D,左上角到右上角为X+,左上角到左下角为Y+。

  • 3D坐标系中,左上角到右上角为X+,y轴则是沿着屏幕向上,Z轴则是垂直屏幕向里。

  • 手背向上用左手比左手坐标系的手势,就是屏幕上的3D坐标。

  • location 里面:

    • 当z 的值约小,结合手背朝上的左手3D坐标系,说明这个屏幕离我们越近,所以说这个可以看作是基于某个点的方法。等于0的时候视角重合就看不到东西。所以无限趋近于0的且为负数的时候,图片最小。
    • 当z值约大,结合手背朝上的左手3D坐标系,说明屏幕离我们越来越远,所以无限趋近于0 但是为正的时候,图片最大。
    • x的值结合z轴的值,就可以概括为X加的时候就是基于视角点往左移动,X减的时候就是往右移动。
    • Y的值同理。Y加的时候向屏幕下面移动,Y减的时候,向屏幕上面移动。
  • 频繁调用camera.translate(0f, 0f, 1f) 结合上面的知识,这个看起来就是缩小,反之 camera.translate(0f, 0f, -1f) 就是放大,x于y的变动也是类似逻辑。但是这个函数有一个特点,就是获取location获取下来的x、y、z是没变动的。

  • rotate:

    • 基于X轴,参数为正,往上翻,参数为负往下翻
    • 基于Y轴,参数为正往里面翻,参数为负往外面翻
    • 基于Z轴进行反转,参数为正往上翻,参数为负往下翻
  • applyToCanvas 和getMatrix 均可以设置变换。建议用applyToCanvas。因为会减少一个Java 层的对象。

整体来说,这篇更像认知的扩展,通过提高认知,那么面对所谓的3D特效可能更容易切换到编码思维。ok ,水完了,嗯,今天又是没有卡12点的一天哦。

相关推荐
CYRUS_STUDIO2 小时前
使用 AndroidNativeEmu 调用 JNI 函数
android·逆向·汇编语言
梦否2 小时前
【Android】类加载器&热修复-随记
android
徒步青云2 小时前
Java内存模型
android
今阳2 小时前
鸿蒙开发笔记-6-装饰器之@Require装饰器,@Reusable装饰器
android·app·harmonyos
-优势在我7 小时前
Android TabLayout 实现随意控制item之间的间距
android·java·ui
hedalei7 小时前
android13修改系统Launcher不跟随重力感应旋转
android·launcher
Indoraptor8 小时前
Android Fence 同步框架
android
峥嵘life9 小时前
DeepSeek本地搭建 和 Android
android
叶羽西9 小时前
Android14 Camera框架中Jpeg流buffer大小的计算
android·安卓
jiasting9 小时前
Android 中 如何监控 某个磁盘有哪些进程或线程在持续的读写
android