數百個 HTML5 例子學習 HT 圖形組件 – 3D 建模篇


http://www.hightopo.com/demo/pipeline/index.html

screen-shot-2016-09-30-at-1-17-33-am

數百個 HTML5 例子學習 HT 圖形組件 – WebGL 3D 篇》里提到 HT 很多情況下不需要借助 3Ds Max 和 Blender 等專業 3D 建模工具也能做出很多效果,例如  http://www.hightopo.com/guide/guide/core/3d/examples/example_3droom.html 這個 3D 電信機房監控例子整個都是通過 HT 提供的 API 構建而成:

screen-shot-2016-09-29-at-11-12-18-pm

不過這個例子中的模型都比較規矩,也就消防栓由一個球 + 圓通構成,其他圖形通過 HT 提供的基本 Node 以及 Shape 對象即可搞定:

screen-shot-2016-09-29-at-11-15-39-pm

但這並不意味着 API 只能做簡單的模型,《HT for Web 建模手冊》中介紹的 HT 建模插件可以讓有想象力的同學做出各種不可思議的效果。例如這個餐座椅的例子:http://www.hightopo.com/guide/guide/plugin/modeling/examples/example_custommodel.html

Screen Shot 2015-01-07 at 11.46.14 PM

對於這個餐座椅的例子,特別是一些不規則的花盆、酒杯、聖誕樹和那顆愛心,很多人好奇我們是怎么搞出來的。其實蠻簡單,就用了《HT for Web 建模手冊》中的 createRingModel 和 createExtrusionModel 兩個構建模型的函數,其中 createRingModel 顧名思義用來構建圍繞一圈的環狀模型,createExtrusionModel 用來構建基於某個形狀的凸出效果,這兩個函數生成的 3D 模型都是靠平面的 2D 圖形衍生而來,都是靠 HT 系統中構建 2D 不規則多邊形時采用的 Points 和 Segments 兩個數組參數搞定, Points 和 Segments 的意義可參考 《HT for Web 形狀手冊》:

可生成不規則的 3D 地板:http://www.hightopo.com/guide/guide/core/shape/examples/example_floor.html

tt

可生成不規則的 3D 管線:http://www.hightopo.com/guide/guide/core/shape/examples/example_polyline.html

bb

這樣大家應該理解了原理,但餐座椅的那幾個不規則形狀的 magic 參數是如果得來的呢,這還是得借助輔助工具:http://www.hightopo.com/demo/3dmodel/index.html

screen-shot-2016-09-30-at-12-12-36-am

screen-shot-2016-09-30-at-12-15-28-am

screen-shot-2016-09-30-at-12-17-49-am

這個工具多年前為寫例子隨意搞的,代碼挺簡單大家直接看 http://www.hightopo.com/demo/3dmodel/index.html 源代碼即可,寫的比較簡陋但挺實用,如何導出?打開控制台,自己打印出 shape 對象的 sements 和 points 參數即可,或等我有空了再來寫個可導入導出更完整的例子,或者 you can you up?

其實也不僅僅也用於 Node 節點類型對象的建模,對於連線其實也可以用模型來搞定,例如 http://www.hightopo.com/guide/guide/plugin/forcelayout/examples/example_forcelayout3.html 這個 3D 彈力拓撲圖例子,很多人已經覺得挺酷炫了,但我一直對這呆板規矩的管道連線很不爽,於是突發奇想搞了個像狗骨頭似的兩頭粗中間細的連線效果,整個 3D 拓撲圖例子一下子高大上了許多:

http://www.hightopo.com/demo/pipeline/index.html

screen-shot-2016-09-30-at-12-26-26-am

這個例子原理是這樣的,將連線 Edge 設置成透明不可見的,然后針對每個 Edge 對應一個 Node 節點,這個節點的形狀就是被拉伸並定位到連線位置替代連線來顯示,而 Node 圖形在還沒拉伸之前長得如下:

screen-shot-2016-09-30-at-12-54-50-am

這里還有個細節是通過 createMatrix 函數,為每個管線設置一個指向兩節點位置的矩陣坐標變換參數到 style 的 mat 屬性上,矩陣預算不理解也沒關系,直接照抄例子中代碼即可,為了方便大家理解我搞了個兩個節點一條連線更簡單的例子供參考:

screen-shot-2016-09-30-at-1-04-12-am

今天只是拋磚引玉,《HT for Web 建模手冊》中還有眾多 API 函數,只要有想象力還可以折騰出無數的花樣,后續有空我再借助 HT for Web 的 WebGL 3D 自定義建模功能多搞些實用的例子。

http://www.hightopo.com/demo/pipeline/index.html

screen-shot-2016-09-30-at-1-20-13-am

 

ht.Default.setShape3dModel(
    'custom', ht.Default.createRingModel(
        [0.5, 0.5, -0.2, 0, 0.5, -0.5], [1, 3]
    )
);

var colorList = ['#FFAFA4', '#B887C5', '#B9EA9C', '#CFD9E7', '#4590B8', '#FF9C30'],
    colorLen = colorList.length;
var randomColor = function() {
    var ran = Math.random() * colorLen;
    return colorList[Math.floor(ran)];
};

var init = function() {
    var dm = new ht.DataModel(),
        g3d = window.g3d = new ht.graph3d.Graph3dView(dm);
    g3d.getBrightness = function() { return null; };
    g3d.isMovable = function(node) { return node.s('shape3d') !== 'custom'; };
    g3d.addToDOM();

    var edgeList = initDataModel(dm),
        forceLayout = new ht.layout.Force3dLayout(g3d);
    forceLayout.onRelaxed = function() {
        edgeList.forEach(updatePipeline);
    };
    forceLayout.start();

    initFormPane(g3d);
};

var initDataModel = function(dm) {
    var root = createNode(dm),
        iNode, jNode, j,
        edgeList = [];
    for (var i = 0; i < 3; i++) {
        iNode = createNode(dm);
        edgeList.push(createEdge(dm, root, iNode));

        for (j = 0; j < 3; j++) {
            jNode = createNode(dm);
            edgeList.push(createEdge(dm, iNode, jNode));
        }
    }
    return edgeList;
};

var createNode = function(dm) {
    var node = new ht.Node();
    node.s({
        'shape3d': 'sphere',
        'shape3d.color': randomColor()
    });
    node.s3(40, 40, 40);
    dm.add(node);
    return node;
};

var createEdge = function(dm, node1, node2) {
    var node = new ht.Node();
    node.s({
        'shape3d': 'custom',
        'shape3d.color': '#ECE0D4',
        'layoutable': false
    });
    dm.add(node);

    var edge = new ht.Edge(node1, node2);
    edge.a('pipeline', node);
    edge.s('edge.color', 'rgba(0, 0, 0, 0)');
    dm.add(edge);

    return edge;
};

var updatePipeline = function(edge) {
    var pipeline = edge.a('pipeline');
    pipeline.s3(1, 1, 1);
    pipeline.p3(0, 0, 0);

    var node1 = edge.getSourceAgent(),
        node2 = edge.getTargetAgent();
    pipeline.s('mat', createMatrix(node1.p3(), node2.p3(), 20));
};

var createMatrix = function(p1, p2, width) {
    var vec = [p2[0]-p1[0], p2[1]-p1[1], p2[2]-p1[2]],
        dist = ht.Default.getDistance(p1, p2);
    return ht.Default.createMatrix({
        s3: [width, dist, width],
        r3: [Math.PI/2 - Math.asin(vec[1]/dist), Math.atan2(vec[0], vec[2]), 0],
        rotationMode: 'xyz',
        t3: [(p1[0]+p2[0])/2, (p1[1]+p2[1])/2, (p1[2]+p2[2])/2]
    });
};

var initFormPane = function(g3d) {
    var formPane = new ht.widget.FormPane();
    formPane.setWidth(230);
    formPane.setHeight(125);
    formPane.addToDOM();

    var view = formPane.getView();
    view.style.background = 'rgba(186, 186, 186, 0.7)';
    view.style.top = '10px';
    view.style.left = 'auto';
    view.style.right = '7px';

    formPane.addRow([{ element: 'Headlight:', font: 'bold 12px arial, sans-serif' }, {
        id: 'disable',
        checkBox: {
            label: 'disable',
            value: g3d.isHeadlightDisabled(),
            onValueChanged: function(oV, nV) {
                g3d.setHeadlightDisabled(nV);
            }
        }
    }], [70, 0.1]);
    formPane.addRow([], [0.1], 1.01, {background: '#43AFF1'});

    ['Color', 'Range', 'Intensity'].forEach(function(name) {
        var obj = { id: name },
            func = function(oV, nV) {
                g3d['setHeadlight' + name](nV);
            };
        if (name === 'Color')
            obj.colorPicker = { 
                instant: true,
                value: g3d['getHeadlight' + name](),
                onValueChanged: func
            };
        else 
            obj.slider = {
                min: 0,
                max: name === 'Range' ? 20000 : 3,
                step: 0.1,
                value: g3d['getHeadlight' + name](),
                onValueChanged: func
            };
        formPane.addRow([ name, obj ], [ 70, 0.1 ]);
    });
};

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM