1. 程式人生 > 實用技巧 >ThingJS利用js語法開發3D模型物體物件控制 原創

ThingJS利用js語法開發3D模型物體物件控制 原創

3D塌陷等於PS裡的合併圖層,塌陷之後就無法用之前一層層的編輯器去編輯了,ThingJS利用js語法開發3D模型物體物件控制。

今天來講講如何基於js語法來開發一個物體模型拆解展開的效果,專業名稱叫“物體爆炸圖”,標準ThingJS體系模型出於互動模型效能考慮,都要求在模型上傳前做塌陷,這種建模細節對於提升3D開發效率很有必要,目的是減少模型對記憶體的佔用。

在3D開發之前,模型本身會重疊很多命令,佔用很大一部分記憶體和CPU,拖慢電腦,所以針對模型進行塌陷後(指的是把很多個物體合併成一個,轉換為一個命令可編輯多邊形或可編輯網格),就會去除這些多餘的命令引數,不再花時間記錄和儲存,從而加快執行速度。

製作物體模型時,根據爆炸圖中各個零件的拆分需要,針對子模型或子節點定義並命名物體子物件,在3DMAX等建模軟體裡就能建立子物件。這些子物件在ThingJS線上開發中可作為模型子節點來控制,能夠像單獨模型物件物體一樣進行移動、新增事件等操作。

拆分後磨性子節點如果有多材質或點數超過上限,那在ThingJS開發中會繼續拆分,並在子節點中被命名成組,組內繼續拆分“01”、“02”等物件。例如:3dmax命名, 一個子節點名字為“box”,由於該子節點使用了多種材質,該子節點在線上開發中會被命名成組,組內會被拆分並命名為“box_0”,“box_1”等物件。

注意經塌陷的模型不再有子節點保留,只有上述分項控制模型區域性要求,保留已命名的子物件資訊,最大程度上提高開發效能,又滿足模型拆分的特殊需要。

官方示例請各位看官參考:

// 載入場景程式碼 
var app = new THING.App({ 
    url: '/api/scene/406e419fae9000a47a4a8899'
});

// 發電機模型節點資料
var nodeObjData = {
    '1': {name: '機座', offset: [0, 0, -1]},
    '2': {name: '保護裝置', offset: [0, -1, 0]},
    '3': {name: '電瓶', offset: [0, -1, 0]},
    '4': {name: '排氣口', offset: [0, 0, 1]},
    '5_0': {name: '過濾器', offset: [0, 0, 1]},
    '5_1': {name: '過濾網', offset: [0.5, 0, 1]},
    '6': {name: '供給裝置', offset: [0, 0, 1]},
    '7': {name: '煙囪', offset: [-1, 0, 0]},
    '8': {name: '發電機'},
    '9': {name: '控制器', offset: [0, 1, 0]}
}
// 發電機模型節點物件
var nodeJsonData = null;
// 發電機物件
var generatorObj = null;
// 發電機展開狀態
var expandState = false;
// 發電機展開次數
var expandCount = 0;

// 場景載入完成後執行
app.on('load', function (ev) {
    // 查詢發電機物件
    generatorObj = app.query('#generator')[0]
    // 獲取發電機模型節點物件
    nodeJsonData = getNode(generatorObj);

    // 建立測試按鈕
    new THING.widget.Button('展開', expandObj);
    new THING.widget.Button('還原', unexpandObj);
    new THING.widget.Button('頂牌顯示', createAllPanel);
    new THING.widget.Button('頂牌隱藏', hiddenAllPanel);
})

/**
 * 說明:顯示所有頂牌
 */
function createAllPanel(){
    for (let key in nodeObjData) {
        nodeJsonData[key].name = nodeObjData[key].name;
        createPanel(nodeJsonData[key]);
    }
}

/**
 * 說明:隱藏所有頂牌
 */
function hiddenAllPanel(){
    for (let key in nodeObjData) {
        hiddenPanel(nodeJsonData[key]);
    }
}

/**
 * 說明:展開物體
 */
function expandObj() {
    // 防止發電機在執行一次展開過程中多次點選
    if (expandState) {
        return;
    }
    expandState = true;
    expandCount++;
    for (let key in nodeObjData) {
        // 各子節點進行偏移
        objOffset(nodeJsonData[key], nodeObjData[key].offset);
    }
}

/**
 * 說明:還原物體
 */
function unexpandObj() {
    // 展開次數為0,代表未展開
    if (expandCount == 0) {
        return;
    }
    for (let key in nodeObjData) {
        if(nodeObjData[key].offset){
            // 計算還原時子節點需要進行的偏移量,數值為 -1 * 展開次數 * nodeObjData中定義的該子節點對應的偏移量
            let offsetValue = [-1 * expandCount * nodeObjData[key].offset[0], -1 * expandCount * nodeObjData[key].offset[1], -1 * expandCount * nodeObjData[key].offset[2]]
            objOffset(nodeJsonData[key], offsetValue);
        }
    }
    expandCount = 0;
}

/**
 * 說明:獲取節點物件
 */
function getNode(obj) {
    let nodeJson = {};
    // obj.subNodes 即可獲取到一個物體的所有子節點
    for (let i = 0; i < obj.subNodes.length; i++) {
        let subnode = obj.subNodes[i];
        // 獲取物體子節點物件中node屬性的type值,只有當type值為Mesh時,才能對物體新增事件
        let type = subnode.node.type;
        if(type == 'Mesh'){
            nodeJson[subnode.name] = subnode;
        }
    }
    return nodeJson;
}

/**
 * 說明:物體偏移
 */
function objOffset(obj, value) {
    if (!value) {
        return;
    }
    // 物體移動
    obj.moveTo({
        offsetPosition: value,  // 自身座標系下的相對位置
        time: 500,  // 移動完成需要的時間
        complete: function () {
            expandState = false;
        }
    });
}

/**
 * 說明:建立面板
 */
function createPanel(obj) {
    // 判斷是否已經建立過面板,如果已建立,顯示,否則建立面板
    var panel = obj.getAttribute('panel');
    if (panel != null) {
        panel.visible = true;
        return;
    }
    // 建立panel
    panel = new THING.widget.Panel({
        // 設定面板寬度
        width: '100px',
        // 沒有角標 none ,沒有線的角標 noline ,折線角標 polyline
        cornerType: 'polyline'

    })
    // 繫結物體身上相應的屬性資料
    panel.addString(obj, 'name').caption('');
    // 建立UIAnchor面板
    var uiAnchor = app.create({
        // 型別
        type: 'UIAnchor',
        // 設定父物體
        parent: obj,
        // 要繫結的dom元素物件
        element: panel.domElement,
        // 設定 localPosition 為 [0, 0, 0]
        localPosition: [0, 0, 0],
        // 相對於面板左上角的偏移畫素值,當前用值是角標的中心點
        pivotPixel: [-16, 109]
    });
    // 更改面板文字樣式
    $('.ThingJS_wrap .main .ThingJS_UI .ThingJS_string-value').css('text-align', 'center');
    obj.setAttribute('panel', uiAnchor);
}

/**
 * 說明:隱藏面板
 */
function hiddenPanel(obj) {
    var panel = obj.getAttribute('panel');
    if (panel != null) {
        panel.visible = false;
    }
}

僅有一年JS開發基礎就可以順手使用ThingJS進行3D模型開發控制了。

推薦:鋅媒體