Try   HackMD

透過Three.js製作AI訓練ROS地圖編輯器輸出fbx使用於Unity - 邱文淇,哲佑,李育衡 (AI/AR)

歡迎來到 MOPCON 2023 共筆

Image Not Showing Possible Reasons
  • The image file may be corrupted
  • The server hosting the image is unavailable
  • The image path is incorrect
  • The image format is not supported
Learn More →

共筆入口:https://hackmd.io/@mopcon/2023
手機版請點選上方 按鈕展開議程列表。

簡報在這~

有問題的可以再來詢問我們!

講者資訊

李育衡:hank93513@gmail.com

劉哲佑

前端 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

Image Not Showing Possible Reasons
  • The image file may be corrupted
  • The server hosting the image is unavailable
  • The image path is incorrect
  • The image format is not supported
Learn More →

可以看到 PerspectiveCamera 會有透視的效果
OrthographicCamera 對無論距離遠近的物件,成像大小都相同

選擇相機

因為我們要實作的是 2D Editor
需要使用 OrthographicCamera 來避免 raycast 位置與 滑鼠座標換算差異 的問題

Camera Error Image

renderer

選染器
在更新畫面時,我們需要 call renderer.render 來依據相機場景

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實際更新畫面

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://zh.wikipedia.org/wiki/布雷森漢姆直線演算法

填充工具

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 即可

這邊使用 Vuex 來處理跨 Conpoent 共享狀態的問題

Frontend TODO

有空會嘗試把 使用 Three.js 實作 2D 畫布編輯器 包成 NPM Package !