構建 3D 的場景除了建立模型,對模型設置顏色和貼圖外,還須要有燈光的效果才能更逼真的反映真實世界的場景。這個例子我以爲既美觀又表明性很強,因此拿出來給你們分享一下。本例地址:Light Flowinghtml
例子動圖:數組
上面場景中主要的知識點包括:3D 燈光以及 3D 模型的流動。bash
整個場景中包括 2D 場景(也就是鷹眼部分)以及 3D 場景:app
dm = new ht.DataModel();
g3d = new ht.graph3d.Graph3dView(dm);
g3d.setGridVisible(true); //指定是否顯示網格
g3d.setGridColor('#74AADA'); //指定網格線顏色
g3d.getView().className = 'main'; //設置類名
document.body.appendChild(g3d.getView()); //將3d組件添加進body體中
window.addEventListener('resize', function(e) {
g3d.invalidate();
}, false);
g2d = new ht.graph.GraphView(dm);
g2d.setAutoScrollZone(-1); //設置自動滾動區域大小,當鼠標距離拓撲邊緣小於這個值時,拓撲自動滾動(調整translateX或translateY)
g2d.getView().className = 'g2d';
g2d.setEditable(true); //設置拓撲中的圖元是否可編輯
document.body.appendChild(g2d.getView());
ht.Default.callLater(g2d.fitContent, g2d, [true, 50, true]); //獲取全局下一個id編號
g3d.setHeadlightRange(2000); //燈影響範圍,默認爲0表明可照射到無窮遠處,若是設置了值則光照射效果隨物體遠離光影而衰減複製代碼
全部HT組件最根層都爲一個 div 組件,可經過組件的 getView() 函數得到,這裏就是利用這種方法將 3D 和 2D 組件添加進 body 體中的。只要 3D 和 2D 共用同一個數據容器,那麼數據容器中的圖元都是共用的,也就是說只要咱們排布好 2D 或者 3D 中的圖元,那麼剩下的那個組件中圖元的排布以及樣式都是根據排布好的組件來排布的。ide
場景中出現的燈光,除了會旋轉的燈光,還有就是兩個靜止的紅燈和黃燈,當旋轉的燈光照向其餘地方的時候看得比較清楚:函數
redLight = new ht.Light(); //燈類
redLight.p3(0, 0, -175); //實例變量的位置
redLight.s({
'light.color': 'red', //燈光顏色
'light.range': 400 //燈影響範圍,默認爲0表明可照射到無窮遠處,若是設置了值則光照射效果隨物體遠離光影而衰減
});
dm.add(redLight); //將實例變量添加進數據容量中
rotateLight = new ht.Light();
rotateLight.s({
'light.color': 'green',
'light.type': 'spot' //默認爲point點光燈,可設置爲spot聚光燈,以及directional的方向光類型
});
dm.add(rotateLight);
yellowLight = new ht.Light();
yellowLight.p3(0, 0, 60);
yellowLight.s({
'light.color': 'yellow',
'light.range': 200
});
dm.add(yellowLight);複製代碼
首先是地板的建立,地板是一個圓形的地板,經過設置樣式 shape3d 爲 cylinder,剩下的只要設置好大小、位置以及樣式等等便可:ui
floor = new ht.Node(); //Node 節點類
floor.s3(1100, 10, 1100);
floor.p3(0, -100, -110);
floor.s({
'shape3d': 'cylinder', //設置 3D 模型爲圓形
'shape3d.side': 100, //默認值爲0,決定3d圖形顯示爲幾邊型,爲0時顯示爲平滑的曲面效果
'shape3d.color': 'white', //默認值爲#3498DB,3d圖形總體顏色
'3d.selectable': false, //默認值爲true,控制圖元在Graph3dView上是否可選中
'2d.visible': false //默認值爲true,控制圖元在GraphView上是否可見
});
dm.add(floor);
複製代碼
接着添加地板外圍的 8 根圓柱:spa
for(var i=0; i<8; i++){
var angle = Math.PI*2*i/8;
pillar = new ht.Node();
pillar.s({
'shape3d': 'cylinder',
'shape3d.color': 'white',
'shape': 'circle', //多邊形類型圖元,爲空時顯示爲圖片
'shape.background': 'gray' //多邊形類型圖元背景
});
pillar.s3(50, 180, 50);
pillar.p3(Math.cos(angle)*480, 0, -110+Math.sin(angle)*480);
dm.add(pillar);
}複製代碼
還有就是這些「箭頭」做爲貼圖的模型,各類各樣的,這裏我就只解析一個,比較靠前的「波動」部分,具體的多邊形的描述請參考形狀手冊:3d
其中 image 的部分是經過 ht.Default.setImage 函數來建立的名爲 arrow 的貼圖。code
shape3 = new ht.Shape(); //多邊形類
dm.add(shape3);
shape3.setTall(60); //設置高度
shape3.setThickness(0); //設置厚度
shape3.s({ //設置樣式
'shape.background': null,
'shape.border.width': 10, //多邊形類型圖元邊框寬度
'shape.border.color': 'blue',
'all.visible': false, //六面是否可見
'front.visible': true,
'front.blend': 'blue', //前面染色顏色
'front.reverse.flip': true, //前面的反面是否顯示正面的內容
'front.image': 'arrow', //前面貼圖
'front.uv.scale': [16, 3] //前面貼圖的uv縮放,格式爲[3,2]
});
shape3.setPoints([ //設置點數組
{x: 0, y: 0},
{x: 25, y: -25},
{x: 50, y: 0},
{x: 75, y: 25},
{x: 100, y: 0},
{x: 125, y: -25},
{x: 150, y: 0},
{x: 175, y: 25},
{x: 200, y: 0}
]);
shape3.setSegments([ //描述點鏈接樣式
1, // moveTo
3, // quadraticCurveTo
3, // quadraticCurveTo
3, // quadraticCurveTo
3 // quadraticCurveTo
]);
shape3.p3(-100, 0, 100);
shape3.setRotationZ(-Math.PI/2); //設置圖元在3D拓撲中沿z軸的旋轉角度(弧度制)
複製代碼
offset = 0;
angle = 0;
setInterval(function(){
angle += Math.PI/50;
rotateLight.p3(400*Math.cos(angle), 70, -110+400*Math.sin(angle)); //設置旋轉燈光的座標
offset += 0.1;
uvOffset = [offset, 0];
shape1.s({
'front.uv.offset': uvOffset //前面貼圖的uv縮放,格式爲[3,2]
});
shape2.s({
'front.uv.offset': uvOffset
});
shape3.s({
'front.uv.offset': uvOffset
});
shape4.s({
'front.uv.offset': uvOffset
});
shape5.s({
'shape3d.uv.offset': uvOffset, //決定3d圖形總體貼圖的uv縮放,格式爲[3,2]
'shape3d.top.uv.offset': uvOffset, //決定3d圖形頂面貼圖的uv縮放,格式爲[3,2]
'shape3d.bottom.uv.offset': uvOffset //決定3d圖形底面貼圖的uv縮放,格式爲[3,2]
});
cylinder.s({
'shape3d.uv.offset': uvOffset
});
torus.s({
'shape3d.uv.offset': uvOffset
});
}, 200);複製代碼
整個例子結束,感受就是「小代碼大效果」,代碼量少並且簡單,效果又很是不錯,你們有興趣能夠去官網或者手冊中查看其它的例子。