使用three.js创建楼层布局图
最近大半年一直在做三维部分的工作,之前做三维楼层都是外部加载使用建模工具创建的模型,但是渲染不够灵活、无法绑定房间信息,所以决定来使用three.js来创建楼层布局。
CSDN下载地址https://download.csdn.net/download/u014529917/85431289
1.调整光源
灯光有SpotLight、AmbientLight、DirectionalLight等、实际项目一般都是多个灯光组合的方式来创建光源。这里我使用的是DirectionalLight+AmbientLight的方式。
var ambientLight = new THREE.AmbientLight( 0xffffff, 0.8 ); //环境光
scene.add( ambientLight );
var directionalLight = new THREE.DirectionalLight( 0xffffff, 0.3 ); //直射光
directionalLight.position.set( 1, 1, 0 ).normalize();
scene.add( directionalLight );
2.创建地板、房间
网络上查的资料,别人都是以boxGeometry的方式创建房间和地板,但实际中这些不一定是盒子形状,所以我根据底部顶点+高度获取顶部顶点,再根据各顶点计算和指定三角面,最终创建任意形状的盒子模型。
Floor.prototype.getGeometry = function(points,height){
var topPoints = [];
for(var i=0;i<points.length;i++){
var vertice = points[i];
topPoints.push([vertice[0],vertice[1]+height,vertice[2]]);
}
var totalPoints = points.concat(topPoints);
var vertices =[]; //所有的顶点
for(var i=0;i<totalPoints.length;i++){
vertices.push(new THREE.Vector3(totalPoints[i][0],totalPoints[i][1],totalPoints[i][2]))
}
var length = points.length;
var faces = [];
for(var j=0;j<length;j++){ //侧面生成三角形
if(j!=length-1){
faces.push(new THREE.Face3(j,j+1,length+j+1));
faces.push(new THREE.Face3(length+j+1,length+j,j));
}else{
faces.push(new THREE.Face3(j,0,length));
faces.push(new THREE.Face3(length,length+j,j));
}
}
var data=[];
for(var i=0;i<length;i++){
data.push(points[i][0],points[i][2]);
}
var triangles = Earcut.triangulate(data);
if(triangles && triangles.length != 0){
for(var i=0;i<triangles.length;i++){
var tlength = triangles.length;
if(i%3==0 && i < tlength-2){
faces.push(new THREE.Face3(triangles[i],triangles[i+1],triangles[i+2])); //底部的三角面
faces.push(new THREE.Face3(triangles[i]+length,triangles[i+1]+length,triangles[i+2]+length)); //顶部的三角面
}
}
}
var geometry = new THREE.Geometry();
geometry.vertices = vertices;
geometry.faces = faces;
geometry.computeFaceNormals(); //自动计算法向量
return geometry;
}
3.指定材质
为了使房间看起来更清晰一点,我们顶部指定材质不受光照影响,侧面加入光源变化效果。于是创建两种材质,创建三角面的时候指定面的材质。
var material = [
new THREE.MeshLambertMaterial({color:colorConst[colorIndex].fill,side:THREE.DoubleSide}), //受光照影响
new THREE.MeshBasicMaterial({color:colorConst[colorIndex].fill,side:THREE.DoubleSide}) //不受光照影响
];
topface.materialIndex = 1; //顶部的三角面 指定材质序号为1,其他默认为0
4.创建盒子顶部的边界线
我们需要添加顶部面界线,来使各个盒子之间分界看起来清晰一点,于是我们根据顶部的坐标创建一条线,添加盒子的同时添加这条线。
//生成顶部的线
Floor.prototype.getBorderGeometry = function(points,color){
var geometry = new THREE.Geometry();
for(var i=0;i<points.length;i++){
var point = points[i];
geometry.vertices.push(new THREE.Vector3(point[0],point[1],point[2]));
if(i== point.length-1){
geometry.vertices.push(new THREE.Vector3(point[0][0],point[0][1],point[0][2]));
}
}
return geometry;
}
5.创建标注
见我的另一篇笔记:使用three.js开发3d地图初探_凡事有果必有因-CSDN博客 第3、4点。
6.选中效果
raycaster类用于在3d中被鼠标选中的物体,这同样可以选中mesh对象,于是用此方法模拟设备的点击。其中floorGroup是保存所有楼层mesh的object3d对象。
function onDocumentMouseClick(event){
var vector = new THREE.Vector3();//三维坐标对象
vector.set(
( event.clientX / container.clientWidth ) * 2 - 1,
- ( event.clientY / container.clientHeight ) * 2 + 1,
0.5 );
vector.unproject( camera );
var raycaster = new THREE.Raycaster(camera.position, vector.sub(camera.position).normalize());
var intersects = raycaster.intersectObjects(floorGroup.children); //楼层中的元素
if (intersects.length > 0) {
var item = intersects[0].object;
item.material = new THREE.MeshBasicMaterial({color: "#f86332",side:THREE.DoubleSide}); //选中的样式
}
}
更多推荐
所有评论(0)