设计师:"裸眼 3D 效果,你们客户端实现很难吗?"

自如-黄进 | 作者

承香墨影 | 编辑

https://juejin.cn/post/6989227733410644005 | 原文

Hi,大家好,这里是承香墨影!

说到裸眼 3D 效果,最先想到的就是利用 MR 实现的虚拟增强技术,例如下图就流传甚广。

但这种效果,通常需要通过 AI 或者使用 MR 再加上后期特效渲染而成。

那么有没有更简单的实现裸眼 3D 的效果呢?

自然是有。裸眼 3D 最基础的原理,就是利用「视觉差」,我们只需要让大脑误认为有层次有景深的感觉,就可以模拟出 3D 的效果。

比如一些常见的 Gif 图,就是利用 2 条辅助线,制造出裸眼 3D 的效果。

比如:

比如:

比如:

既然是利用「视觉差」可以模拟出裸眼 3D 效果,那么我们可以将 UI 视图分层,然后将不同层次的元素,按照不同的速率运动,造成伪立体的感觉,就是一种裸眼 3D 的效果。

这有点像前几年知乎 App 在启动 Banner 里实现的「视差动画」,只是它利用的是 UI 的滚动来带动元素的视差移动,而要实现裸眼 3D 还需要借助传感器,利用 SensorManager 获取到的数据,来偏移某些图层上的元素。

今天推荐一个来自自如大前端研发中心-黄进的一篇文章,讲述他在自如 App 中如何将裸眼 3D 效果应用在首页 Banner 上。

按照惯例,先上效果。


背景

移动端界面设计如此火热的今天,各类大厂的设计规范和设计语言,已经非常的成熟,我们想做一些在这套成熟的设计规范之外的尝试和创新,所以有别于传统的 Banner 交互形式,成为了我们的发力点。

设计理念

由于 App 版面空间有限,除了功能导向、阅读习惯和设计美观外,自如想在既定的框下,做一下不同的设计尝试,哪怕这种尝试只能提升用户 1% 的观感。

可能租了几年自如的房子,用了几年自如客 App,你可能也不会注意到一些小的细节。但如果哪天,作为用户的你突然发现了这个隐藏的 “彩蛋”,看到了自如在这些小细节上的用心,我相信那天你将会对自如这个品牌有更深层次的认识和理解。

裸眼 3D 技术,一般都是应用在裸眼 3D 大屏、全息投影等等比较常见的场景中。在 APP 的 Banner 上应用,的确也是一次全新的尝试。

我们通过借助移动设备上的传感器、以及自身的屏显清晰度、画面呈现,将 2D 影像转化为景深效果,以呈现出不用 "3D" 眼镜就可看到的 3D 效果。

实现方式

以下以 Android 为例,介绍一下该效果的实现方式。

分层

自如客 App 的 Banner 其实一直在创新当中,有专门注意过的同学可能知道,在裸眼 3D 效果之前,自如客 App 其实就已经实现了分层。

当时为了实现更加自然和精致的切换效果:在每个 Banner 滑入滑出的时候,底部其实会在原地进行渐显渐隐,内容会跟随手势滑入滑出。

此次为了实现 3D 效果,我们在以前分层的基础上加了一层中景,将原有的前景拆分为前景和中景。

上图的 sl_bg 为背景,pv_middle 为中景,sl 为前景。

由于切换的交互,实际上 Banner 使用了两个 ViewPager 进行了联动。背景在最底层的 ViewPager 里面,中景和前景在另外一个 ViewPager 里。

跟手位移

打开自如客 App 后,用户操作设备可以明显感受到画面的错位移动,造成视觉上的景深效果。这种错位移动,其实就是借助设备本身的传感器来实现的,具体实现方式,是我们让中景始终保持不动,同时从设备传感器获取当前设备对应的倾斜角,根据倾斜角计算出背景和前景的移动距离,然后执行背景和前景移动的动作。

如下图所示:

为了使用的方便,我们封装了一个 SensorLayout,专门用于根据设备的倾斜角执行内容的位移;SensorLayout 内部的主要实现:

注册对应的传感器
mSensorManager = (SensorManager) getContext().getSystemService(Context.SENSOR_SERVICE);

mAcceleSensor = mSensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);

mMagneticSensor = mSensorManager.getDefaultSensor(Sensor.TYPE_MAGNETIC_FIELD);

mSensorManager.registerListener(this, mAcceleSensor, SensorManager.SENSOR_DELAY_GAME);
mSensorManager.registerListener(this, mMagneticSensor, SensorManager.SENSOR_DELAY_GAME);
计算偏转角度
if (event.sensor.getType() == Sensor.TYPE_ACCELEROMETER) {
  mAcceleValues = event.values;
}
if (event.sensor.getType() == Sensor.TYPE_MAGNETIC_FIELD) {
  mMageneticValues = event.values;
}

float[] values = new float[3];
float[] R = new float[9];
SensorManager.getRotationMatrix(R, null, mAcceleValues, mMageneticValues);
SensorManager.getOrientation(R, values);

values[1] = (float) Math.toDegrees(values[1]);

values[2] = (float) Math.toDegrees(values[2]);

通过重力传感器和地磁场传感器,获取设备的偏转角度

根据偏转角度执行滑动
if (mDegreeY <= 0 && mDegreeY > mDegreeYMin) {
  hasChangeX = true;
  scrollX = (int) (mDegreeY / Math.abs(mDegreeYMin) * mXMoveDistance*mDirection);
} else if (mDegreeY > 0 && mDegreeY < mDegreeYMax) {
  hasChangeX = true;
  scrollX = (int) (mDegreeY / Math.abs(mDegreeYMax) * mXMoveDistance*mDirection);
}
if (mDegreeX <= 0 && mDegreeX > mDegreeXMin) {
  hasChangeY = true;
  scrollY = (int) (mDegreeX / Math.abs(mDegreeXMin) * mYMoveDistance*mDirection);
} else if (mDegreeX > 0 && mDegreeX < mDegreeXMax) {
  hasChangeY = true;
  scrollY = (int) (mDegreeX / Math.abs(mDegreeXMax) * mYMoveDistance*mDirection);
}
smoothScrollTo(hasChangeX ? scrollX : mScroller.getFinalX(), hasChangeY ? scrollY : mScroller.getFinalY());

mDegreeX 即为第二部中获取的偏转角度,mDegreeXMinmDegreeXMax 为 X 轴可发生偏转位移的角度的最大值和最小值,mYMoveDistance 即为 Y 轴上的最大偏移距离(围绕 X 轴发生旋转,视图会沿 Y 轴上发生位移);Y 轴上的偏转同理;就算好 X 轴和 Y 轴的偏移距离后,使用 scroller 进行滑动;

实现总结

读到这里,相信大家已经基本了解了这套 Banner 的实现方案。

Android 端在布局上进行了分层,中景位置不变,借助重力传感器和地磁场传感器获取偏转角度,根据角度使背景和前景进行错位移动。iOS 端的实现原理也基本一致,不再赘述。

墨影小结

正如文章开头讲的,利用「视觉差」实现裸眼 3D 效果,最重要的就是 2 点:

  • UI 视图分层;

  • 利用传感器(SensorManager)让不同层次的元素,规律移动;

关键代码已经在文内展示,有兴趣的可以自己动手实现。再给自己加一个新的封装要求就更好了。例如何封装不同图层元素显式位置的规则,以适应设计师频繁的替换元素而无需修改代码。

-- End --

本文对你有帮助吗?留言、转发、点好看是最大的支持,谢谢!

推荐阅读:

百度技术:“App 优化网络,先从 HTTPDNS 开始” | 原理到实战

Android 架构,拒绝生搬硬套!

Android 的 Window 如何理解?Dialog 到底是不是子窗口?

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值