基於 HTML5 Canvas 的 3D 碰撞檢測
這是公司大神寫的一個放官網上給使用者學習的例子,我一開始真的不知道這是在幹嘛,就只是將三個形狀圖元組合在一起,然後可以同時旋轉、放大縮小這個三個圖形,點選“Animate”就能讓中間的那一個圖元單獨繞著某一個點旋轉,表單最上方的“Axis”真的完全不知道拿來幹嘛用的,覺得好累贅,而且是官網的 Demo,也沒有解釋。。。所以我今天得任務就是完全剖析這個例子!奮鬥
本文例子:http://www.hightopo.cn/demo/3drotate/3d-rotate.html
首先讓我們來看下這個案例:
我們來看看如何操作這個 3d 互動模型,可以直接滑動“Rotation”的滑動條,你會看到 3d 和左下角的 2d 上的圖元都會旋轉,接著點選“Axis”中的任意一個值,然後點選“Animate”,你會看到中間這個圖元會旋轉,同時滑動“Range”的滑動條,這是控制你旋轉的幅度的,如果你調到“0”,那麼就不會旋轉,調到“30”就會旋轉30度,以此類推。接著調整“Reset”你會發現,不是完全重新整理這個介面,而是區域性重新整理兩邊的圓柱,根據這兩個圓柱與中間節點之間的關聯而重置的。
左下角的是整個 3d 場景內的俯檢視,這樣我們可以非常直觀地看清圖元的移動方向和位置。
可能你會好奇這個是怎麼俯檢視是怎麼放上去的?如果 3d 中的圖元變化,這個俯檢視中的圖元也會跟著變化麼?如何把右上角的 form 表單和左下角的檢視又是怎麼放的?如何只移動 3d 二把這兩個固定在這邊?或者你可能還有別的問題,在這裡我會盡量清楚地解答,實在找不到答案可以去官網 HT for Web 查詢你的問題。
好了,基礎就是先佈局,布 3d 場景,HT 在提供方法方面算是非常細緻的了,平時我們生成網格可能就要花費一段時間,又是基礎程式碼,新手開發人員都能很快上手呢~短短几行程式碼就能建立一個 3d 場景,簡直太快。。。
dm = new ht.DataModel();
g3d = new ht.graph3d.Graph3dView(dm);
g3d.setGridVisible(true);//設定網格可視
g3d.setGridSize(m);//設定網格大小
g3d.setGridGap(w);//設定網格間距
g3d.setEye([-200, 150, 200]);//設定camera位置
g3d.getView().className = 'main';
document.body.appendChild(g3d.getView());
由於 HT 預設將所有元件都設定了 style “position:absolute”,所以當我們初始化這個元件之後,一定要在 style 中寫上位置,並且將這個元件新增進你想要新增進的標籤中,這個例子中,form 表單、2d 元件和3d 元件都互不依附,所以我們直接將這三個都新增進 body 中即可,還有一點值得注意的,所有 HT 元件的最根層都是一個 div,是通過元件的 getView() 函式獲得的。所以我們如果要新增進 HTML 標籤中,肯定也要是 HTML 標籤才行。
然後再介面的右上角放上 form 表單,放到右上角就直接設定 style 中的“top”“bottom”“left”“right”即可,2d 圖同理:
formPane = new ht.widget.FormPane();
formPane.setLabelAlign('right');
formPane.getView().className = 'formpane';
document.body.appendChild(formPane.getView());
formPane.addRow(['Rotation:', {
id: 'rotation',
slider: {
min: -180,
max: 180,
value: 0,
step: 1,
onValueChanged: function(e){
node.setRotation(this.getValue() * Math.PI / 180);
}
}
}], [60, 0.1]);
因為這個例子的 form 表單中的行數和內容比較多,所以我這邊就只取了一個 form 表單自定義行的例子。這邊的“id”只是為了能快速查詢到這個元素,slider 是 HT form 表單自定義的一個方法,滑動條功能,設定了該屬性後 HT 將根據屬性值自動構建 ht.widger.Slider 物件,具體引數可以參考 HT for Web 表單手冊。
至於左下角的 2d 俯檢視,這是通過跟 3d 共享同一個 dataModel 資料模型,只要我們繪製好了圖形,然後新增進 dataModel 中去,不管是什麼元件,只要呼叫了這個 dataModel 的都可以擁有dataModel 中的所有資料:
g2d = new ht.graph.GraphView(dm);
g2d.getView().className = 'g2d';
g2d.setEditable(true);
document.body.appendChild(g2d.getView());
ht.Default.callLater(g2d.fitContent, g2d, [true, 50, true]);
ht.Default.callLater(func, scope, args, delay) 獲取全域性下一個編號,其中 func 指的是回撥函式,scope 指的是函式域,args 指的是函式引數列表,delay 則是延遲時間(毫秒)。這個函式可以在頁面開啟時回撥 g2d.fitContent 函式,這個函式的作用域僅在 g2d 中,引數列表是 fitContent(anim, padding, notZoomIn) 函式的引數,這三個引數分別代表“是否使用動畫”,“縮放後圖元區域與拓撲邊緣的距離”,以及“是否將最小縮放值限定為 1”。
接著將 3d 中的圖元新增進去,這裡我不擷取全部程式碼,只取一個比較特別的有趣的圖元,中間外層的透明圖元:
shape = new ht.Shape();
shape.s({
'all.reverse.cull': true,
'all.color': 'rgba(0, 255, 0, 0.5)',
'all.transparent': true
});
shape.setThickness(2);
dm.add(shape);
var resetShape = function() {
var cs = node.getCorners(10, 10);
cs.push(cs[0]);
shape.setPoints(cs);
g3d.setBoundaries(ht.Default.toBoundaries(cs));
};
resetShape();
程式碼中有比較有趣的幾點:
這邊用了 node.getCorners() 這個方法,這個是獲取四個點,對於 2d 來說就是左上、右上、右下、左下四個點;對於 3d 來說就是直接獲取底面的四個“左上、右上、右下、左下”點,這個我反應了好一會兒才反應過來。。。並以這四個點為基礎作為 shape 的 points。
這邊還用了 setBoundaries(boundaries) 函式,借用 ht.Default.toBoundaries 函式來將不符合 setBoundaries 函式引數的格式轉換成它需要的引數格式。雖然我認為這一行在這個例子中沒有什麼作用,但是還是讓我好好學習了一把碰撞測試。
我們在碰撞測試的時候經常要設定 g3d.setNear 函式,我實在沒搞懂這個函式是拿來幹嘛的,結果這個例子讓我注意到,如果“我”的視線的近端截面位置也就是 setNear(1),那麼我能看到的就是比表面跟進 1 的距離,這個函式預設設定為 10,就算我們不設定這個值我們也能在 3d 中看到圖元的內部去,剛剛我們介紹的 getCorners() 函式,其實它還有兩個引數 xpadding 和 ypadding,分別代表“水平方向 padding”“垂直方向 padding”,也就是說,在我們獲取四個角的同時,我們還能設定這四個角和邊之間的 padding。只要將這個值設定得比 setNear 設定的大,我們就不會看到 3d 圖元的內部中去了。
我們還注意到似乎是“廢程式碼”的一行: cs.push(cs[0])。這個完全不是廢程式碼啊,幫了很大忙呢!在 HT 中,用 ht.Shape 建立的圖元,只要你不手動設定繪製關閉,那麼就會停留在你最終繪製的位置,所以我把最後的一個點又和第一個點連起來,那麼就是一個封閉的圖形了,否則你會看到後面缺了一部分,像這樣:
我在其他文章中也提到過 HT 封裝了一些很方便的方法和事件,比如 dataModel#md,監聽資料的屬性的變化,這邊我們用了 md 方法來判斷只有中間這個 node 能夠繞著一個點旋轉,具體參考 HT for Web 資料模型手冊:
dm.md(function(e){
if(e.data === node){
if(e.property === 'rotation'){
formPane.v('rotation', 180 / Math.PI * e.newValue);
}
resetShape();
}
});
這邊我想要說一下“繞著一個點旋轉”的功能,這邊沒有用我們自定義的 anchor 錨點,但是功能類似,通過獲取 form 表單上選擇的“left、right、front、back”來設定旋轉中心點,HT 中 form 表單通過 getValue(id) 簡寫成 v(id) 根據 id 獲取對應 item 元素值:
formPane.addRow([
{
button: {
label: 'Animate',
onClicked: function(){
var dx = 0,
dy = 0,
range = formPane.v('range') * Math.PI / 180;
if(formPane.v('left')){
dx = -node.getWidth()/2;
}
if(formPane.v('right')){
dx = node.getWidth()/2;
}
if(formPane.v('back')){
dy = -node.getHeight()/2;
}
if(formPane.v('front')){
dy = node.getHeight()/2;
}
animate(node, range, dx, dy);
}
}
},
{
button: {
label: 'Reset',
onClicked: function(){
node.setRotation(0);
}
}
}
], [0.1, 0.1]);
看到這邊你還是沒懂?快去我們官網上從 beginners 重頭開始學習吧!
相關文章
- Html5 Canvas動畫基礎(碰撞檢測)HTMLCanvas動畫
- 基於 HTML5 Canvas 的 3D 機房建立HTMLCanvas3D
- 基於 HTML5 Canvas 的 3D 熱力雲圖效果HTMLCanvas3D
- 基於 HTML5 Canvas 的 3D 模型貼圖問題HTMLCanvas3D模型
- 基於HTML5 Canvas的3D動態Chart圖表HTMLCanvas3D
- 基於 HTML5 Canvas 的 3D 壓力器反序列化HTMLCanvas3D
- 碰撞檢測
- 基於 HTML5 Canvas 的簡易 2D 3D 編輯器HTMLCanvas3D
- 基於 Canvas 的 HTML5 文字動畫特效CanvasHTML動畫特效
- 基於HTML5 Canvas 點選新增 2D 3D 機櫃模型HTMLCanvas3D模型
- 基於 HTML5 Canvas 的 3D 渲染引擎構建生產管控系統HTMLCanvas3D
- 7個華麗的基於Canvas的HTML5動畫CanvasHTML動畫
- 基於 HTML5 Canvas 的元素週期表展示HTMLCanvas
- 基於 HTML5 Canvas 的樓宇自控系統HTMLCanvas
- 基於 HTML5 Canvas 實現的文字動畫特效HTMLCanvas動畫特效
- ECharts:基於HTML5 Canvas的JavaScript圖表庫EchartsHTMLCanvasJavaScript
- HTML5實現3D和2D視覺化QuadTree四叉樹碰撞檢測HTML3D視覺化
- 基於 HTML5 Canvas 的元素週期表的展示HTMLCanvas
- 基於 HTML5 WebGL 的 3D 挖掘機HTMLWeb3D
- 基於 HTML5 的 3D 工控隧道案例HTML3D
- 基於 HTML5 WebGL 的 3D 機房HTMLWeb3D
- 基於HTML5及WebGL開發的2D3D第一人稱漫遊進行碰撞檢測HTMLWeb3D
- 基於 HTML5 Canvas 實現文字動畫特效HTMLCanvas動畫特效
- 基於HTML5 Canvas 實現彈出框HTMLCanvas
- 基於 HTML5 Canvas 的拓撲元件 ToolTip 應用HTMLCanvas元件
- 基於 HTML5 Canvas 的可互動旋鈕元件HTMLCanvas元件
- canvas 碰撞反彈Canvas
- 使用canvas檢測HTML5視訊解碼錯誤CanvasHTML
- 基於 HTML5 Canvas 2D 拓撲圖和 3D 機櫃模型的增刪操作HTMLCanvas3D模型
- 基於 HTML5 WebGL 的 3D 科幻風機HTMLWeb3D
- 基於 HTML5 的 WebGL 3D 隧道監控HTMLWeb3D
- 基於ARkit和SceneKit檢測相機位置和設定2個物體碰撞的事件事件
- WPF 2D 碰撞檢測
- javascript矩形碰撞檢測程式碼JavaScript
- python如何檢測pygame中的碰撞PythonGAM
- 基於HTML5 Canvas 實現商場監控HTMLCanvas
- [SceneKit專題]9-Basic-Collision-Detection碰撞檢測基礎
- JS寫的不咋地的碰撞檢測JS