前言
构建 3D 的场景除了创建模型,对模型设置颜色和贴图外,还需要有灯光的效果才能更逼真的反映真实世界的场景。这个例子我觉得既美观又代表性很强,所以拿出来给大家分享一下。
本例地址:http://www.hightopo.com/guide/guide/core/lighting/examples/example_flowing.html
例子动图:

上面场景中主要的知识点包括:3D 灯光以及 3D 模型的流动。
1. 场景搭建
整个场景中包括 2D 场景(也就是鹰眼部分)以及 3D 场景:
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()); window.addEventListener('resize', function(e) { g3d.invalidate();}, false);g2d = new ht.graph.GraphView(dm);g2d.setAutoScrollZone(-1); g2d.getView().className = 'g2d';g2d.setEditable(true); document.body.appendChild(g2d.getView());ht.Default.callLater(g2d.fitContent, g2d, [true, 50, true]); g3d.setHeadlightRange(2000);
所有HT组件最根层都为一个 div 组件,可通过组件的 getView() 函数获得,这里就是利用这种方法将 3D 和 2D 组件添加进 body 体中的。只要 3D 和 2D 共用同一个数据容器,那么数据容器中的图元都是共用的,也就是说只要我们排布好 2D 或者 3D 中的图元,那么剩下的那个组件中图元的排布以及样式都是根据排布好的组件来排布的。
2. 添加灯光
场景中出现的灯光,除了会旋转的灯光,还有就是两个静止的红灯和黄灯,当旋转的灯光照向其他地方的时候看得比较清楚:
redLight = new ht.Light(); redLight.p3(0, 0, -175); redLight.s({ 'light.color': 'red', 'light.range': 400});dm.add(redLight); rotateLight = new ht.Light();rotateLight.s({ 'light.color': 'green', 'light.type': 'spot'});dm.add(rotateLight);yellowLight = new ht.Light();yellowLight.p3(0, 0, 60);yellowLight.s({ 'light.color': 'yellow', 'light.range': 200});dm.add(yellowLight);
3. 场景中模型的构建
首先是地板的创建,地板是一个圆形的地板,通过设置样式 shape3d 为 cylinder,剩下的只要设置好大小、位置以及样式等等即可:
floor = new ht.Node(); floor.s3(1100, 10, 1100);floor.p3(0, -100, -110);floor.s({ 'shape3d': 'cylinder', 'shape3d.side': 100, 'shape3d.color': 'white', '3d.selectable': false, '2d.visible': false});dm.add(floor);
接着添加地板外围的 8 根圆柱:
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);}
还有就是这些“箭头”作为贴图的模型,各种各样的,这里我就只解析一个,比较靠前的“波动”部分,具体的多边形的描述请参考形状手册:

其中 image 的部分是通过 ht.Default.setImage 函数来创建的名为 arrow 的贴图。
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] });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, 3, 3, 3, 3]);shape3.p3(-100, 0, 100);shape3.setRotationZ(-Math.PI/2);
4. 设置定时器使各个模型中的图片“流动”以及旋转灯光的旋转
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 }); shape2.s({ 'front.uv.offset': uvOffset }); shape3.s({ 'front.uv.offset': uvOffset }); shape4.s({ 'front.uv.offset': uvOffset }); shape5.s({ 'shape3d.uv.offset': uvOffset, 'shape3d.top.uv.offset': uvOffset, 'shape3d.bottom.uv.offset': uvOffset }); cylinder.s({ 'shape3d.uv.offset': uvOffset }); torus.s({ 'shape3d.uv.offset': uvOffset });}, 200);
总结
整个例子结束,感觉就是“小代码大效果”,代码量少而且简单,效果又非常不错,大家有兴趣可以去官网或者手册中查看其它的例子。