拿去吧你!用Compose 打造裸眼 3D 效果!

2021-12-09 技術最TOP

作者:付十一
連結:https://juejin.cn/post/6992169168938205191

前段時間自如團隊發了自如客APP裸眼3D效果的文章讓人眼前一亮,還沒看過的,可以看看之前發的文章:Android自如客APP裸眼3D效果的實現

之後 Nayuta 大佬使用 Flutter 也實現了該功能,那 Jetpack compose 版本怎麼能落下。

前人栽樹後人乘涼,首先在這裡感謝 自如大前端團隊 和 Nayuta ,下文所用的素材也有一部分來自 Nayuta 的項目。

思路

從自如團隊所提供的思路來看,裸眼3D效果是將整個圖片結構分為3層:上層、中層、以及底層。在手機左右上下旋轉時,上層和底層的圖片呈相反的方向進行移動,中層則不動,在視覺上給人一種3D的效果。

至於使用 Jetpack Compose 來實現,主要想法如下:

使用 Compose 的 Canvas 對三層圖片進行繪製,且使用 translate 對上層和底層圖片進行平移;註冊手機陀螺儀傳感器的監聽,拿到手機旋轉時,xyz 軸的旋轉角度;根據旋轉角度計算圖片平移的距離,期間做好最大平移距離的控制;得到平移距離後,將距離設置給標記了 mutableStateOf 的平移距離變量,使得UI刷新,呈平移效果。實現

根據上面的思路,我們首先使用 compose 繪製出靜態的三張圖片,compose 繪製圖片的方式有多種,Image、Canvas 等,因為考慮到後面圖片需要進行移動,這裡就選用 Canvas 進行繪製。

val imageBack = ImageBitmap.imageResource(id = R.drawable.back)
val imageMid = ImageBitmap.imageResource(id = R.drawable.mid)
val imageFore = ImageBitmap.imageResource(id = R.drawable.fore)

Canvas(
    modifier = Modifier
        .fillMaxSize()) {
        //底層
    drawImage(imageBack)
    //中層
    drawImage(imageMid)
    //s
    drawImage(imageFore)
    
}

生成靜態的效果圖如下:

靜態圖片加載是件簡單的事情,那如何讓圖片動起來?

Compose 的 Canvas 中有一個 translate 方法,作平移效果用,也就是分別在 x 和 y 坐標中通過給定的像素增量對坐標空間進行平移。參數傳入 x 軸上平移的距離以及 y 軸上平移的距離。

這裡分別定義為 xDistance , yDistance 。因為只有上層和底層的圖片會進行移動,所以在 Canvas 中,對上層和底層圖片的繪製加上 translate。如下:

 translate(-xDistance, -yDistance) { drawImage(imageBack) }
 drawImage(imageMid)
 translate(xDistance, yDistance) {  drawImage(imageFore) }

傳入 xDistance,yDistance 參數值,這裡需要注意的是,上層與底層圖片為互為相反移動,所以對上層圖片傳入的是 xDistance 的相反值。到這裡,圖片就會根據 xDistance 以及 yDistance 的距離進行平移。

那 xDistance 和 yDistance 的值該如何動態改變呢?

Compose 其實提供了一個狀態 mutableStateOf,

標記了 mutableStateOf 的 data 後,該 data 就表明是有狀態的,如果後續狀態發生了改變,那麼所有引用這個狀態的控制項都會重新繪製。也就是說,將 xDistance 和 yDistance 設置成該狀態,因為 Canvas 引用了 xDistance 值,所有當 xDistance 值發生改變時,圖片也就會重新繪製,也就是做平移的效果。

var xDistance by remember { mutableStateOf(0f) }
var yDistance by remember { mutableStateOf(0f) }

xDistance 和 yDistance 已經動態標記。下面就需要依據手機陀螺儀移動,來動態設置 xDistance 和 yDistance 的值。在開始說傳感器之前,這裡還存在一個問題,當圖片進行平移上下或者作用平移時,會存在左右或者上下兩側屏幕露出的情況,這個時候就需要將圖片做放大處理,

給圖片設置邊界,讓圖片在最大平移距離中移動,防止圖片平移露出屏幕背景,將 Canvas 設置為原來的 1.3 倍。

Canvas(
       modifier = Modifier
          .fillMaxSize()
          .scale(1.3f)) {}

最後的效果也就是如下所示:

手機陀螺儀傳感器

通過手機的旋轉,圖片進行移動的操作歸功於傳感器,

如圖所示,傳感器坐標系一共分為 x, y, z 三軸,當手機左右翻轉時,則是圍繞 Y 軸運動,當手機上下翻轉時,則是圍繞 x 軸運動,當手機平放在桌面,左右畫圓時,則是圍繞 z 軸運動。

當手機旋轉時,傳感器則會通知我們三個方向的移動角速度,也就根據這移動角度來確定圖片的平移距離。

首先我們先看看傳感器該如何監聽?Android 其實已經為我們封裝好了 API,SensorManager,直接按照說明創建就好。

    val context = LocalContext.current
    val sensorManager: SensorManager? = getSystemService(context, SensorManager::class.java)
    val sensor = sensorManager?.getDefaultSensor(Sensor.TYPE_GYROSCOPE)

通過 getSystemService 獲取到 SensorManager 後,設置 sensor 的種類為 TYPE_GYROSCOPE,也就是陀螺儀傳感器。並且監聽 xyz 三個方向旋轉角速度。

sensorManager?.registerListener(object : SensorEventListener {
        override fun onSensorChanged(event: SensorEvent?) {
        //Y軸角速度
       speedY = event?.values?.get(1)!!
       //X軸角速度
       speedX = event?.values?.get(0)!!
       //Z軸角速度
       speedZ = event?.values?.get(2)!!
 }
         override fun onAccuracyChanged(sensor: Sensor?, accuracy: Int) {

        }
}

通過 SensorEventListener 監聽到手機三個方向的角速度,因為陀螺儀讀出的是角速度,大家都知道,角速度乘以時間,就是轉過的角度,直接計算旋轉的角度值。

 // 將手機在各個軸上的旋轉角度相加
 angularX += (event.values[0] * dT).toLong()
 angularY += (event.values[1] * dT).toLong()
 angularZ += (event.values[2] * dT).toLong()

 //設置x軸y軸最大邊界值,
 if (angularY > mMaxAnular) {
    angularY = mMaxAnular.toFloat()
 } else if (angularY < -mMaxAnular) {
    angularY = -mMaxAnular.toFloat()
 }

 if (angularX > mMaxAnular) {
    angularX = mMaxAnular.toFloat()
 } else if (angularX < -mMaxAnular) {
    angularX = -mMaxAnular.toFloat()
 }

角度計算完成後,因為圖片移動是需要移動距離的,那接下來就需要知道圖片的平移距離。其實在上面就提出為圖片設置了最大平移邊界,這裡也設置了最大旋轉角度,那麼就可以依據角度比例來到推出平移距離。

依據公式 旋轉角度/最大角度 = 平移距離/最大平移距離 反推出 平移距離= 旋轉角度/最大角度*最大平移距離

val xRadio: Float = (angularY / mMaxAnular).toFloat()
val yRadio: Float = (angularX / mMaxAnular).toFloat()
xDistance = xRadio * maxOffset
yDistance = yRadio * maxOffset

圖片距離計算完成,基本上隨手機移動,圖片會呈平移效果,但是發現還有一個問題,onSensorChanged 的回調刷新很快,當圍繞 Y 軸左右運動時,圖片也會上下平移,這就導致圖片會不規則跳動,繞 Y 軸左右運動其實只需要左右平移即可,同樣的,圍繞 x 軸運動,圖片只需要上下移動即可。這裡針對 x,y 軸運動,設置了旋轉條件控制。

  x = Math.abs(event.values[0])
  y = Math.abs(event.values[1])
  z = Math.abs(event.values[2])

  if (x > y + z) {
      xDistance = 0f
      yDistance = yRadio * maxOffset
   } else if (y > x + z) {
      xDistance = xRadio * maxOffset
      yDistance = 0f}

好了,功能完成,我們來看看最後的效果:

最後

市面上的App的設計基本上是千篇一律,一個有意思的 idea 總是會讓人多看一眼,再次感謝自如團隊提供了這個創意。對了,今天在螞蟻森林收能量時,發現樹木也有點此效果的味道,你不妨去瞅一眼。

相關焦點

  • Android OpenGL仿自如APP裸眼3D效果
    另一個重要的原因是,GPU更適合圖形、圖像的處理,裸眼3D效果中有大量的縮放和位移操作,都可在java層通過一個矩陣對幾何變換進行描述,通過shader小程序中交給GPU處理 ——因此,理論上OpenGL的渲染性能比其它幾個方案更好一些。本文重點是描述OpenGL繪製時的思路描述,因此下文僅展示部分核心代碼,對具體實現感興趣的讀者可參考文末的連結。
  • 雲計算核心技術Docker教程:Docker Compose指定單個compose文件
    docker-compose可以使用該-f標誌通過命令行或通過在外殼程序或環境文件中設置COMPOSE_FILE環境變量來指定不在當前目錄中的Compose文件的路徑。
  • 這交互炸了,Android 仿自如APP裸眼 3D 效果 OpenGL 版
    之前自如系列各個版本:自如App裸眼3D效果最近火爆了,各個版本齊了~之前看到 自如團隊 發布的 自如客APP裸眼3D效果的實現 ,非常有趣,不久後,社區內 Android 的開發者們陸續提供了 Flutter、 Android 原生 、Android Jetpack Compose 等不同的實現版本。
  • Android OpenGL仿自如APP裸眼3D效果
    /   作者簡介   /本篇文章轉自卻把清梅嗅的博客,文章主要分享了他用OpenGL模仿自如APP的裸眼3D效果,相信會對大家有所幫助!原文地址:https://juejin.cn/post/7035645207278256165/   概述   /之前看到自如團隊發布的自如客APP裸眼3D效果的實現 ,非常有趣,不久後,社區內Android的開發者們陸續提供了Flutter、 Android原生 、Android Jetpack Compose等不同的實現版本。
  • 裸眼3D大揭秘!這些圖片你能看出神奇的3D效果嗎?
    裸眼3D作為屏顯技術的重要發展方向,更是被寫進「十三五」發展規劃當中: 「加快虛擬實境、增強現實、全息成像、裸眼三維圖形顯示(裸眼 3D)、交互娛樂引擎開發、文化資源數位化處理、互動影視等核心技術創新發展。」 裸眼3D究竟是什麼?它是指在無需佩戴任何輔助設備的前提下,通過裸眼即可看到3D影像。
  • 有趣的裸眼3D,教新手如何看裸眼3D圖~
    鑑於大部分人不會看裸眼3D圖片,又非常有興趣想要學會看裸眼3D圖,故開此貼,服務大眾,請大家認真閱讀教程的每個語句,只有讀會了,加上不急不躁的心情冷靜看圖,你也就會了。這張是我的啟蒙圖,我第一次看的就是它,是無意中看出來的,然後就瘋狂地熱愛上了裸眼3D,這圖上是一個立體木捶
  • 欺騙你眼睛,裸眼3D背後的奧秘!
    沒想到這個「水箱」其實是D' strict專門為SM公司專門打造的海浪動態顯示屏。整塊LED曲面屏幕寬80米,高23米。無論是浪花翻湧的視覺衝擊還是逼真的聽覺模擬,都讓人們感覺浪花會衝破玻璃。完成這一奇觀的,當然就是我們經常聽聞的裸眼3D技術。今天小黑就帶大家一起來探索裸眼3D背後的秘密。
  • 首款裸眼3D智能硬體3D Box現身國內
    3DBox產品現身線下渠道 相信大家對3D電影都已經非常熟悉,3D電影帶來的震撼效果和沉浸式觀看體驗是普通2D電影所不能做到的。通常觀影者需要藉助紅藍眼鏡或偏振鏡進行觀看,但是觀眾往往會抱怨觀影時需要佩戴3D眼鏡非常的麻煩。
  • 裸眼3D屏上熱搜背後
    裸眼3D屏豐富而多元的展示效果,即使是廣告內容依然吸引了不少人前往「打卡」,實現廣告宣傳效益的最大化,同時也刷新了戶外顯示的呈現形式。對於裸眼3D屏「出圈」,LED封裝行業龍頭企業國星光電並不意外。早在前兩年,國星光電就已布局適配裸眼3D等新一代內容技術的自主高端品牌REESTAR,且已被國內國際多個重要場合當作首選器件。當然,「成都太古裡裸眼3D屏」、「廣州北京路8K超高清裸眼3D曲面屏」、「重慶觀音橋裸眼3D屏」等多起經典案例,同樣來自於REESTAR。
  • 裸眼3D成像原理,教大家正確觀看3D宅舞!
    而視頻中給出的裸眼3D視頻觀影技巧,也是讓很多小夥伴們頭疼,一直找不到「入門」的方法。本文,P君將科普一波,告訴大家用什麼方法去看這個視頻,才能讓視頻變得「凹凸有致」,順便幫大家區分一下我們日常所遇到的「裸眼3D」。
  • 怪物襲來|亞洲首家裸眼3D酒吧
    先來作個說明,什麼是裸眼3D?3D特效,相信大家都很熟悉了,現在看電影,電視很多都是3D的,但觀眾都需要帶眼鏡(電子快門或偏振式),才能獲得3D的視覺感受。裸眼3D顧名思義,就是觀眾不用佩戴帶眼鏡等設備即可獲得3D的視覺體驗感受。先來一個動圖,讓大家對號稱即將稱霸整個上海灘的SOMA吧檯有個第一印象,震撼吧!
  • 還在戴3D眼鏡?最新的裸眼3D屏幕來啦!
    大家在看3D電影的時候,有沒有被3D眼鏡壓得鼻子疼眼睛酸的經歷呢,無論是3D電影還是VR遊戲裡的3D效果,想要影像達到3D的效果都必須通過3D或者VR眼鏡這種外部工具才能實現。但最近在屏幕顯示技術一直處於領軍地位的索尼公司卻發布了一款「裸眼3D」顯示屏,解放你被壓疼的鼻梁,讓你不用3D眼鏡就能直接看到立體的效果!
  • compose怎麼記
    compose這麼記碎碎念:com,包含兩者或以上的人或事物,更多例子比如:combat, commence, commemorate, etc. pose,姿勢、姿態、擺姿勢。compose,擺弄多個物品、作曲、寫詩、寫書、排版、組成、構成。擺弄音符、文字、詩句的位置就是在作曲、寫書、排版、寫詩對吧?正是不斷地擺弄構成了一個整體(曲子、書、詩等)。這就是compose的意思啦~ 造句:The composer composed this beautiful music.
  • 【帶你看】富士康的裸眼3D手機要開售了!
    【帶你看】富士康的裸眼3D手機要開售了!InFocus裸眼3D手機M550即將開售了!
  • 3d手機原理及發展趨勢介紹分析【圖文】
    今天就來為大家介紹一款智慧型手機界燃起的新星——3d手機,本期小編將帶領認識一下裸眼3D技術、3d手機的發展趨勢、產品簡介以及案例分析,希望大家在了解相關信息的同時能夠有所幫助。  PPTV手機最近使用裸眼3D成像技術——反狹縫微控投射技術。這種技術是液晶光柵技術的改進型技術,用透光反射柱狀膜做狹縫屏障。對比與傳統的視差屏障技術,由於透光反射膜本身透光,所以亮度損失很小。此外,該技術採用的是日本進口3D原材料。反狹縫微控投射技術擁有零串擾、低摩爾紋、高亮度、低反射率、多視角等技術特點。
  • 答疑解惑 編輯現場體驗影馳裸眼3D平板
    但由於實際體驗效果和3D引擎技術不夠成熟,加上無法還原真實的3D場景,因此大部分消費者都止步於體驗階段,裸眼3D技術並沒有進入普及化,大家依然更願意選擇影院裡的眼鏡式3D。  不得不承認,裸眼3D的普及是必然趨勢,仍然是未來屏幕顯示技術的發展方向,曇花一現的3D技術遇到的諸多瓶頸,需要突破和解決,儘管體驗影馳NOAH前筆者帶著不少的擔心和疑慮,但仍舊持看好態度和更多好奇感。
  • 開啟裸眼3D視界 觀3D V5手機全面評測
    但是短短幾年後,康得新將這一效果移植到了手機屏幕上,裸眼3D再也不需要用戶佩戴笨重的眼鏡,可謂在如今功能單一同質化嚴重的手機市場開闢了一條新的道路,今天評測的就是有著裸眼3D功能的智慧型手機「觀3D V5手機(以下簡稱V5)」,型號K3DX-V5G,由中興製造康得新提供裸眼3D解決方案。
  • 大陸集團、HERE和Leia聯手打造裸眼3D汽車導航
    通過這種方式,三家公司將共同為安全、直觀的車內用戶體驗助力,並帶來驚豔的效果。HERE通過3D技術描繪出的建築物和地形通過Leia的光場技術來進行顯示。這種聯合解決方案可以實現3D地圖的可視化,而無需佩戴自適應眼鏡或眼動傳感器。光場技術甚至可以使3D效果從不同角度可見。因此,駕駛員和乘客都可以看到3D圖形。
  • 科普:裸眼3D
    這一認識被廣泛應用於網頁或其他應用中對按鈕、3d線條的繪製。比如要繪製的3d文字,即在原始位置顯示高亮度顏色,而在左下或右上等位置用低亮度顏色勾勒出其輪廓,這樣在視覺上便會產生3d文字的效果。具體實現時,可用完全一樣的字體在不同的位置分別繪製兩個不同顏色的2d文字,只要使兩個文字的坐標合適,就完全可以在視覺上產生出不同效果的3d文字。
  • 裸眼3D飛船科幻巨幕成網紅打卡地亮相重慶,微美全息詮釋高仿真AI...
    重慶觀音橋商圈一棟大樓3788平方米的巨幕LED屏上出現了一座「未來城市」,圍觀的市民不需要任何設備,用裸眼就能感受到逼真震撼的3D太空飛船視覺效果。視頻刷爆朋友圈之後也引起了很多網友的圍觀,有網友表示「重慶也太炫酷了,周末想要再打一次卡」…………