首頁  >  文章  >  web前端  >  基於HTML5和WebGL的碰撞效果實現

基於HTML5和WebGL的碰撞效果實現

一个新手
一个新手原創
2017-10-20 10:44:211422瀏覽

這是公司大神寫的一個放官網上給用戶學習的例子,我一開始真的不知道這是在幹嘛,就只是將三個形狀圖元組合在一起,然後可以同時旋轉、放大縮小這個三個圖形,點擊「Animate」就能讓中間的那一個圖元單獨繞著某一個點旋轉,表單最上方的「Axis」真的完全不知道拿來幹嘛用的,覺得好累贅,而且是官網的demo,也沒有解釋。 。 。所以我今天得任務就是完全剖析這個例子!

首先讓我們來看下這個案例:

我們來看看如何操作這個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元件的最根層都是一個p,是透過元件的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();

這邊比較有趣的有幾點:

1. 這邊用了node.getCorners()這個方法,這個是取得四個點,對於2d來說就是左上、右上、右下、左下四個點;對3d來說就是直接取得底面的四個「左上、右上、右下、左下」點,這個我反應了好一會兒才反應過來。 。 。並以這四點為基礎作為shape的points。

2. 這邊也用了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]);

以上是基於HTML5和WebGL的碰撞效果實現的詳細內容。更多資訊請關注PHP中文網其他相關文章!

陳述:
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn