基于WebGL(ThingJS)的家具城 商场 3D展示 3D可视化 DEMO
本文将模拟一个家具城,让大家足不出户在家里就能更加直观立体的挑选家具。
第一步,利用CampusBuilder搭建模拟场景。CampusBuilder的模型库有各种各样的模型,使我们搭建出的场景更逼真。使用CampusBuilde创建层级,之后再给层级加外立面就出现了当前的效果。这次我们其实只是需要一个楼层,所以我们就把上次使用的过的场景拿来改造一下。详情移步:CampusBuilder3D场景制作工具
点击查看demo
//加载场景代码 var app = new THING.App({ // 场景地址 "url": "http://www.thingjs.com/./uploads/wechat/oLX7p05lsWJZUIxnIWsNXAzJ40X8/scene/家具城", //背景设置 "skyBox": "BlueSky" });
第二步,开启层级切换。因为我们模拟的“宜家”是某建筑中的一层,所以这里要开启层级切换以便进入家具城。
app.on('load', function (ev) { //开启层级切换 app.level.change(ev.campus); });
同时给家具城创建一个广告牌,防止我们在第一人称下行走会“迷路”。贴图可以自行上传。
//创建广告牌 var advertisingSign = app.create({ type: 'Box', width: 15.0, // 宽度 height: 5.0, // 高度 depth: 0.5, // 深度 widthSegments: 1.0, //宽度上的节数 heightSegments: 1.0, // 高度上的节数 depthSegments: 1.0, // 深度上的节数 center: 'Bottom', // 中心点 style: { color: '#ffffff', opacity: 2, image: '/uploads/wechat/oLX7p05lsWJZUIxnIWsNXAzJ40X8/file/家具展销/欧派.jpg' }, parent: app.query('building_01')[0], }); advertisingSign.position = [50.957, 15.883, -16];
这里给我们给整个场景用抽象物体围起来了,以免第一人称控件开启时会造成无碰撞体系坠落出场景。记得要给他们组合并命名为‘碰撞盒’,在场景加载完成后将他们“隐藏”起来。
app.on('load', function (ev) { //开启层级切换 app.level.change(ev.campus); //将碰撞盒的透明度设置为0,并且将他们的pickable属性设置为false,不可被选中。 var crashBox = app.query('碰撞盒')[0]; crashBox.style.opacity = 0; crashBox.pickable = false; });
第三步,添加第一人称控件。
先创建两个按钮来控制第一人称控件。
new THING.widget.Button('第一人称', add_control); new THING.widget.Button('自由视角', remove_control);
添加第一人称控件
//第一人称组件 var ctrl = null; function add_control() { if (app.level.current.name == 'Campus') { app.camera.position = [75.28812158204005, 1.8016147124541857, 29.699063489018236]; app.camera.target = [53.32909358623788, 4.541642332131091, -9.470748625431646]; } if (app.level.current.name != 'Campus') { app.level.change(app.query('新楼层')[0]); app.camera.flyTo({ 'position': [41.05650213795261, 1.3469938677565356, -18.6143831867287], 'target': [38.982251559488404, 0.7081383467333933, -23.867802267306008], 'time': 2000, 'complete': function () { } }); } if (ctrl) return; ctrl = app.addControl( new THING.WalkControl({ walkSpeed: 0.02, turnSpeed: 0.25, gravity: 30, eyeHeight: 1.7, jumpSpeed: 0, enableKeyRotate: false, useCollision: true,//app.scene useGravity: true, groundObjects: [app.scene] //把整个场景都添加,可把楼层或其他需要检测的添加进入碰撞体系里 | 默认值 园区地板 }) ); }
移除第一人称控件
function remove_control() { if (!ctrl) return; app.removeControl(ctrl); ctrl = null; }
第四步,创建界面panel用于显示家居的详细信息。
添加界面
var panel = null; function add_panel(title, total, goodsInfo) { panel = new THING.widget.Panel({ titleText: '商品名称:' + title, closeIcon: true, // 是否有关闭按钮 dragable: false, // 是否可以拖拽 retractable: true, opacity: 0.9, // 透明度 hasTitle: true }); panel.position = [1000, 0]; var dataObj = { total: total, goodsInfo: goodsInfo }; var total = panel.addString(dataObj, 'total').caption('总价'); var goodsInfo = panel.addString(dataObj, 'goodsInfo').caption('商品介绍'); }
移除界面
function remove_panel() { if (panel) { panel.destroy(); panel = null; } }
最后一步,为商品和大楼添加点击事件。这里我们也要卸载双击事件,因为鼠标双击时会聚焦当前物体,与我们的业务逻辑有冲突所以这里给他卸载掉。首先是普通的点击事件,鼠标左键点击时会出现商品的信息。右键点击时,会移除第一人称控件。
//鼠标点击事件 app.on('click', function (ev) { if (ev.button == 2) { remove_control(); return; } remove_panel(); switch (ev.object.name) { case "桌椅组合1": add_panel('自然风格餐桌系列', "2598.00", " 简约的圆桌设计,微冷的现代居室围成一桌大自然的感觉。自然本色,简介的设计,彰显质朴、实用、少即是多的线代生活哲学。"); break; case "桌椅组合2": add_panel('线代都市餐桌系列', "2198.00", " 利落线条,刻画几何形底座。自然致简的浅木色橡木拼花,带有淡淡的手工白蜡处理,搭配内敛的深灰色线条,形成微妙平衡,线代感呼之欲出。"); break; case "桌椅组合3": add_panel('紧凑家庭餐桌系列', "1998.00", " 紧凑家庭餐厅,享四人围坐的宽适与惬意。精巧的尺寸,圆融包容的圆桌设计,即便是紧凑的客餐厅一体空间,也能欢畅小谈。"); break; case "沙发组合1": add_panel('本色笔记组合沙发', "2598.00", " 简约的圆桌设计,微冷的现代居室围成一桌大自然的感觉。自然本色,简介的设计,彰显质朴、实用、少即是多的线代生活哲学。"); break; case "沙发组合2": add_panel('云海阑珊组合沙发', "8888.00", " 全家人围坐的恬淡时刻,更多一份舒适。借一抹海天的蓝,再偷来云朵的舒软,只为全家围坐的时刻,尽享舒适怡然。"); break; case "沙发组合3": add_panel('商务舒适组合沙发', "8598.00", " 简约的圆桌设计,微冷的现代居室围成一桌大自然的感觉。自然本色,简介的设计,彰显质朴、实用、少即是多的线代生活哲学。"); break; case "沙发组合4": add_panel('自然风格餐桌系列', "5508.00", " 简约的圆桌设计,微冷的现代居室围成一桌大自然的感觉。自然本色,简介的设计,彰显质朴、实用、少即是多的线代生活哲学。"); break; case "沙发组合5": add_panel('自然风格餐桌系列', "2578.00", " 简约的圆桌设计,微冷的现代居室围成一桌大自然的感觉。自然本色,简介的设计,彰显质朴、实用、少即是多的线代生活哲学。"); break; } }); app.off('dblclick');
代码块 => 层级 => 触发 => 修改进入层级操作
这里我们将进入层级的操作改为直接进入我们的家具城这一层“新楼层”。
//修改singleClick点击之后进入级的操作 app.on(THING.EventType.SingleClick, function (ev) { var object = ev.object; if (object.name == "building_01") { app.level.change(app.query('新楼层')[0]); app.camera.flyTo({ 'position': [41.05650213795261, 1.3469938677565356, -18.6143831867287], 'target': [38.982251559488404, 0.7081383467333933, -23.867802267306008], 'time': 2000, complete: function () { console.log("我已经进来了" + app.level.current.name); } }); } return; }, 'customLevelEnterMethod');
小结:
第一人称控件的问题,Campus => 新楼层 ,如果不设置摄像机飞到一合理位置,摄像机将脱离楼层,因为进入楼层的时候摄像机的默认位置不在楼层上,所以每次在楼层内添加第一人称控件时我们必须要将摄像机放到一个合理的位置。
全部代码:
//加载场景代码 var app = new THING.App({ // 场景地址 "url": "http://www.thingjs.com/./uploads/wechat/oLX7p05lsWJZUIxnIWsNXAzJ40X8/scene/家具城", //背景设置 "skyBox": "BlueSky" }); app.on('load', function (ev) { app.level.change(ev.campus); var crashBox = app.query('碰撞盒')[0]; crashBox.style.opacity = 0; crashBox.pickable = false; new THING.widget.Button('第一人称', add_control); new THING.widget.Button('自由视角', remove_control); }); //修改singleClick点击之后进入级的操作 app.on(THING.EventType.SingleClick, function (ev) { var object = ev.object; if (object.name == "building_01") { app.level.change(app.query('新楼层')[0]); app.camera.flyTo({ 'position': [41.05650213795261, 1.3469938677565356, -18.6143831867287], 'target': [38.982251559488404, 0.7081383467333933, -23.867802267306008], 'time': 2000, complete: function () { console.log("我已经进来了" + app.level.current.name); } }); } return; }, 'customLevelEnterMethod'); //鼠标点击事件 app.on('click', function (ev) { if (ev.button == 2) { remove_control(); } if (typeof (ev.object) == undefined) return; remove_panel(); switch (ev.object.name) { case "桌椅组合1": add_panel('自然风格餐桌系列', "2598.00", " 简约的圆桌设计,微冷的现代居室围成一桌大自然的感觉。自然本色,简介的设计,彰显质朴、实用、少即是多的线代生活哲学。"); break; case "桌椅组合2": add_panel('线代都市餐桌系列', "2198.00", " 利落线条,刻画几何形底座。自然致简的浅木色橡木拼花,带有淡淡的手工白蜡处理,搭配内敛的深灰色线条,形成微妙平衡,线代感呼之欲出。"); break; case "桌椅组合3": add_panel('紧凑家庭餐桌系列', "1998.00", " 紧凑家庭餐厅,享四人围坐的宽适与惬意。精巧的尺寸,圆融包容的圆桌设计,即便是紧凑的客餐厅一体空间,也能欢畅小谈。"); break; case "沙发组合1": add_panel('本色笔记组合沙发', "2598.00", " 简约的圆桌设计,微冷的现代居室围成一桌大自然的感觉。自然本色,简介的设计,彰显质朴、实用、少即是多的线代生活哲学。"); break; case "沙发组合2": add_panel('云海阑珊组合沙发', "8888.00", " 全家人围坐的恬淡时刻,更多一份舒适。借一抹海天的蓝,再偷来云朵的舒软,只为全家围坐的时刻,尽享舒适怡然。"); break; case "沙发组合3": add_panel('商务舒适组合沙发', "8598.00", " 简约的圆桌设计,微冷的现代居室围成一桌大自然的感觉。自然本色,简介的设计,彰显质朴、实用、少即是多的线代生活哲学。"); break; case "沙发组合4": add_panel('自然风格餐桌系列', "5508.00", " 简约的圆桌设计,微冷的现代居室围成一桌大自然的感觉。自然本色,简介的设计,彰显质朴、实用、少即是多的线代生活哲学。"); break; case "沙发组合5": add_panel('自然风格餐桌系列', "2578.00", " 简约的圆桌设计,微冷的现代居室围成一桌大自然的感觉。自然本色,简介的设计,彰显质朴、实用、少即是多的线代生活哲学。"); break; } }); //卸载双击事件 app.off('dblclick'); // 界面组件 var panel = null; function add_panel(title, total, goodsInfo) { panel = new THING.widget.Panel({ titleText: '商品名称:' + title, closeIcon: true, // 是否有关闭按钮 dragable: false, // 是否可以拖拽 retractable: true, opacity: 0.9, // 透明度 hasTitle: true }); panel.position = [1000, 0]; var dataObj = { total: total, goodsInfo: goodsInfo }; var total = panel.addString(dataObj, 'total').caption('总价'); var goodsInfo = panel.addString(dataObj, 'goodsInfo').caption('商品介绍'); } function remove_panel() { if (panel) { panel.destroy(); panel = null; } } //创建广告牌 var advertisingSign = app.create({ type: 'Box', width: 15.0, // 宽度 height: 5.0, // 高度 depth: 0.5, // 深度 widthSegments: 1.0, //宽度上的节数 heightSegments: 1.0, // 高度上的节数 depthSegments: 1.0, // 深度上的节数 center: 'Bottom', // 中心点 style: { color: '#ffffff', opacity: 2, image: '/uploads/wechat/oLX7p05lsWJZUIxnIWsNXAzJ40X8/file/家具展销/欧派.jpg' }, parent: app.query('building_01')[0], }); advertisingSign.position = [50.957, 15.883, -16]; //第一人称组件 var ctrl = null; function add_control() { if (app.level.current.name == 'Campus') { app.camera.position = [75.28812158204005, 1.8016147124541857, 29.699063489018236]; app.camera.target = [53.32909358623788, 4.541642332131091, -9.470748625431646]; } if (app.level.current.name != 'Campus') { app.level.change(app.query('新楼层')[0]); app.camera.flyTo({ 'position': [41.05650213795261, 1.3469938677565356, -18.6143831867287], 'target': [38.982251559488404, 0.7081383467333933, -23.867802267306008], 'time': 2000, 'complete': function () { } }); } if (ctrl) return; ctrl = app.addControl( new THING.WalkControl({ walkSpeed: 0.02, turnSpeed: 0.25, gravity: 30, eyeHeight: 1.7, jumpSpeed: 0, enableKeyRotate: false, useCollision: true,//app.scene useGravity: true, groundObjects: [app.scene] //把整个场景都添加,可把楼层或其他需要检测的添加进入碰撞体系里 | 默认值 园区地板 }) ); } function remove_control() { if (!ctrl) return; app.removeControl(ctrl); ctrl = null; }