# 透過Three.js製作AI訓練ROS地圖編輯器輸出fbx使用於Unity - 邱文淇,哲佑,李育衡 (AI/AR) {%hackmd @mopcon/BkMIqw_76 %} [簡報在這~](https://www.canva.com/design/DAFyiB9WgTU/-4uqvwRF-IfkoS-cmIDtOg/view?utm_content=DAFyiB9WgTU&utm_campaign=designshare&utm_medium=link&utm_source=editor) 有問題的可以再來詢問我們! ## 講者資訊 **李育衡**:hank93513@gmail.com **劉哲佑**: - Github: [jason810496](https://github.com/jason810496) - LinkedIn [Liu Zhe You](https://www.linkedin.com/in/zhe-you-liu-85aa13244/) - Mail : f74116720@gs.ncku.edu.tw ## 前端 Note ### 回顧 Map 結構 在本系統中 **地圖** 的儲存分為: - 座標系統 json 檔案 - 地圖相關資訊 #### Map List 後端有對 Map List 做 pagnation 所以先 Get Map List by offset & limit 原本的 Get Map List 只會有 map_id , 還需要前端重新 loop 過所有 map_id 去打 S3 presigned Url 後來改為後端 Get Map List 也會順便回傳 Image 的 presigend Url ### 為 3D 空間中設計 2D 編輯器 #### Why 2D ? 以 UI / UX 角度,比較難在 3D 空間編輯地圖 所以可以在 上視圖 ( 2D ) 會比較好編輯 ### 目標 以滑鼠從 A 拖到 B 點(還沒放開時):顯示 Preview 放開後:再實際畫在地圖中 Features: - 切換筆刷大小 - Undo / Redo 機制 - 畫線 - 畫舉形 - 填充工具 #### 為什麼要有這些 tools ? > 原本掃出來的 Map 是非常破碎的,所以需要這些工具來把地圖完善 Tool: Three.js ! ### Why Three.js ? - 簡單使用 - 擴充性 - 未來可以把 MiniMap 要改成 3D 視窗 > Why Three.js : 擴充性 -> Eg: 未來 MiniMap 要改成 3D 呈現 ### Three.js 基礎概念 #### Object in Three.js 所有看到的 **「東西」** 在 Three.js 都是 **物件** 包括 **輔助網格**、**半透明遮罩**、**畫上去的方塊** 都是一個個 **物件** #### Object 的要素 - 座標 : Geometry - 材質 : MeshBasicMaterial ### renderer 、 scene 與 plane > intro to render 、 scene 與 plane #### scene 場景 我們所有 Three.js 的物件都加在 **場景** 中 在接下來 **renderer** 會用到 #### camera > 也可以想成鏡頭 Three.js 有提供 - PerspectiveCamera - OrthographicCamera #### 相機差異 相機成像的結果來比較: > Camera Scene VS Image > https://medium.com/@gopisaikrishna.vuta/exploring-cameras-in-three-js-32e268a6bebd ![camera-compare](https://miro.medium.com/v2/resize:fit:1400/format:webp/1*1ByGRgA8dxWV4X17iLGQRQ.png) 可以看到 `PerspectiveCamera` 會有透視的效果 而 `OrthographicCamera` 對無論距離遠近的物件,成像大小都相同 #### 選擇相機 因為我們要實作的是 2D Editor 需要使用 `OrthographicCamera` 來避免 **raycast 位置與 滑鼠座標換算差異** 的問題 > Camera Error Image #### renderer 選染器 在更新畫面時,我們需要 call `renderer.render` 來依據**相機** 和 **場景** ```javascript renderer.render(this.scene, this.camera); ``` > 如果 scene 多了 A 方塊,跑完 `renderer.render` 後 > 畫面就會多生成 A 方塊 ### Three.js + Vue = Trois.js Trois.js 是為 Vue 包裝好 Three.js 的 Package 這邊採用 Trois.js 的好處是: - 不用以原生 JS 操作 Dom - Trois.js 透過 props 來初始化 Three.js 的基礎元件 > 接著只需要在 script 中以 ref 來直接引用 ### 畫圖邏輯 #### 目標 以滑鼠從 A 拖到 B 點(還沒放開時):顯示 Preview 放開後:再實際畫在地圖中 Features: - 切換筆刷大小 - Undo / Redo 機制 - 畫線 - 畫舉形 - 填充工具 #### Position startPosition : set when `onMouseDown` currentPosition : set when `onPointerMove` endPosition : set when `onMouseUp` #### render 機制 當遇到以上 3 個 event 時 (`onMouseDown` , `onPointerMove`, `onMouseUp` ) 都會更新畫面中的物件 再 call `render` 來 **實際更新畫面** ```javascript function render() { renderer.render(scene, camera); } ``` #### Preview > Why Preview Utility ? > 一開始沒有預覽功能: 完全不知道畫到哪裡 在一開始有說到 **所有東西** 都是 **Object** 所以我們可以先將 **半透明的預覽方塊** 加入 `previewList` 當要下次要 render 前,先**清除** `previewList` 中的物件 再重新加入該輪新的預覽方塊! #### 如何判斷座標是否已經畫過 這邊是開一個 `Map` ( 這邊叫他 `currentState`) 以 ``{x},{y}`` 作為 Key 如果 ``{x},{y}`` 不是 `None` 代表 `x,y` 座標有物件 #### 實際儲存到 Plane 當遇到 `onMouseUp` 事件 在 pop 出所有 `previewList` 中的物件時 可以順便取得物件的座標,就可以加上實際的方塊 #### Undo / Redo 同樣也是 `onMouseUp` 事件 會把剛剛提到的 `currentState` ( 紀錄座標是否有物件的 `Map` ) 存到 `historyList` 中 ### Other Features - 畫線 - 畫舉形 - 填充工具 #### 畫線 > **By codpilot XD** 要在網格座標中從 A 畫一條直線到 B 可以使用 `Bresenham's line algorithm` 主要是透過計算 A , B 兩點之間的斜率達成 > Bresenham's line algorithm 圖 > ![Bresenham's line algorithm](https://upload.wikimedia.org/wikipedia/commons/thumb/d/d4/Bresenham.png/600px-Bresenham.png) > https://zh.wikipedia.org/wiki/%E5%B8%83%E9%9B%B7%E6%A3%AE%E6%BC%A2%E5%A7%86%E7%9B%B4%E7%B7%9A%E6%BC%94%E7%AE%97%E6%B3%95 #### 填充工具 > GIF of fill tool 要在封閉區塊中填滿方格 可以使用 BFS #### Auto Save By `setTimeout` ### Save 接著會將 plane 中的 **物件** 依據座標建成 List 再向後端更新 > 後端會再向 S3 更新 Map 的 json #### MiniMap 畫面更新 我們同樣是透過 `renderer.render` 來更新畫面的 在更新主要 Editor 畫面時,同時 call MiniMap 的 renderScene #### Save MiniMap Image 那要如何把 MiniMap 的縮圖存成 `png` 打向後端呢? 可以透過 抓到 Three.js 生成的 `canva` 使用 `canvas.toDataURL("image/png");` 再將 URI 轉成 blob 即可 #### SideBar 這邊使用 Vuex 來處理跨 Conpoent 共享狀態的問題 #### Frontend TODO 有空會嘗試把 **使用 Three.js 實作 2D 畫布編輯器** 包成 NPM Package !