three.js搭建室内场景教程


Posted in Javascript onDecember 30, 2018

公司做商城、消防、用电等项目,需要实现楼层和设备的可视化,以前都是使用其他建模工具创建的整体模型,再使用three.js的加载器加载到场景中,但是这样的加载存在缺陷,比如不能给模型的元素赋属性、不能单个点击元素、渲染单调等。所以本次参考了一些资料,不使用模型倒入,完全使用three.js搭建场景,代码有些粗燥勿怪。

three.js搭建室内场景教程

1.创建地板

地板是一个类似盒子,有顶部有底部有侧面,但是不一定是规则的盒子,因此我放弃了常用的BoxGeometry的方式,改用顶点+面的形式创建任意多边形地板,已知多边形底部坐标,底部坐标加上高度得到顶部坐标,通过Earcut可以计算出底部和顶部的三角面,侧面的三角面可以直接通过坐标序号得到,由此可以创建一个通用的Geometry。

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;
}

效果:

three.js搭建室内场景教程

2.创建墙体

墙体我使用了BoxGeometry,墙体上的窗户的洞、门洞,我们可以使用ThreeBSP库中差集函数来进行模型相减来实现。

Floor.prototype.addWall = function(size,position,rotation,holes){
 var geometry = new THREE.BoxGeometry(size[0], size[1], size[2]);
 var materials = new THREE.MeshLambertMaterial({color: 0xb0cee0,side:THREE.DoubleSide})
 var result = new THREE.Mesh(geometry,materials);
 if(holes){
  result = cube;
  for(var i=0;i<holes.length;i++){
   var totalBSP = new ThreeBSP(result);
   var hole = holes[i];
   var holeGeometry = new THREE.BoxGeometry(hole.size[0], hole.size[1], hole.size[2]);
   var holeCube = new THREE.Mesh( holeGeometry); 
   holeCube.position.x = hole.position[0];
   holeCube.position.y = hole.position[1] + hole.size[1]/2;
   holeCube.position.z = hole.position[2];
   var clipBSP = new ThreeBSP(holeCube);
   var resultBSP = totalBSP.subtract(clipBSP);
   result = resultBSP.toMesh();
  }
  result.material = materials;
 }
 this.container.add(result); //添加填充
}

效果:

three.js搭建室内场景教程

3.门框

在添加门之前,为了更加形象一点,我添加了门框。先使用墙体减去门框的洞,再添加减去门洞的门框,跟前面类似,具体代码不放了。

效果:

three.js搭建室内场景教程

4.门、窗、主机、显示屏、桌子

门、窗、主机、显示屏、桌子 我都是使用BoxGeometry的形式,再给相应的面贴纹理,跟前面类似,效果如下:

three.js搭建室内场景教程

5.盆栽

盆栽的盆体可以使用CylinderBufferGeometry来创建顶部大于底部的圆台,盆栽的叶子是使用多个PlaneGeometry贴上植物纹理以不同的角度展示,代码如下:

//盆栽
Floor.prototype.addPlant = function(position,scale){
 var plant = new THREE.Object3D();
 var geometry = new THREE.CylinderBufferGeometry( 0.15, 0.1, 0.4, 22 );
 var material = new THREE.MeshLambertMaterial( {color: 0xffffff} );
 
 var cylinder = new THREE.Mesh( geometry, material );
 cylinder.position.x = 0;
 cylinder.position.y = 0.2;
 cylinder.position.z = 0;
 plant.add( cylinder );
 
 var leafTexture = new THREE.TextureLoader().load('meeting/plant.png');
 var leafMaterial = new THREE.MeshBasicMaterial({map:leafTexture,side:THREE.DoubleSide,transparent:true});
 var geom = new THREE.PlaneGeometry(0.4, 0.8);
 for(var i=0;i<4;i++){
  var leaf = new THREE.Mesh( geom, leafMaterial );
  leaf.position.y = 0.8;
  leaf.rotation.y = -Math.PI/(i+1);
  plant.add(leaf);
 }
 plant.position.x = position[0];
 plant.position.y = position[1];
 plant.position.z = position[2];
 this.container.add(plant);
}

效果(很粗燥):

three.js搭建室内场景教程

6.椅子

椅子的模型有点复杂,因为这个差点放弃用three创建椅子,但看到一个同行完全用three创建的minicity,又有了信心和勇气。于是:4条椅子腿定位+旋转、椅子面、2条靠背腿定位+旋转、靠背定位+旋转,最终创建完成,代码太丑陋就不上了。效果:

three.js搭建室内场景教程

7.开门动画

开门动画我使用了TWEEN库,Tween.js是一个包含各种经典动画算法的JS资源,动态改变门在z轴方向上的值。

if(status == "close"){
 status = "open";
 var desRotation = Math.PI/2;
 new TWEEN.Tween(door.rotation).to({
  y: desRotation
 }, 10000).easing(TWEEN.Easing.Elastic.Out).onComplete(function(){
 }).start();
}else{
 status = "close";
 new TWEEN.Tween(door.rotation).to({
  y: 0
 }, 10000).easing(TWEEN.Easing.Elastic.Out).onComplete(function(){
 }).start();
}

效果:

three.js搭建室内场景教程

8.行走动画

行走动画我使用了three的animation模块,导入带动画的fbx模型,关于模型动画的制作很复杂,我们可以在网络上下载。导入动画之后播放动画。

var Mixers = [];
var animation;
var walkingMan;

var loader = new THREE.FBXLoader();
loader.load('file/walkingman.fbx', function ( object ) { //Samba Dancing.fbx
 object.mixer = new THREE.AnimationMixer( object );
 Mixers.push( object.mixer );            //AnimationMixer
 animation = object.mixer.clipAction( object.animations[ 0 ] );   //AnimationAction AnimationClip
 walkingMan = object;
 walkingMan.scale.x = walkingMan.scale.y = walkingMan.scale.z = 0.8;
 walkingMan.position.x = firstPoint[0];
 walkingMan.position.y = firstPoint[1];
 walkingMan.position.z = firstPoint[2];
 walkingMan.rotation.y = rotation;  //角度 根据当前点和下一个点计算 
 scene.add( walkingMan );
 animation.play();
});

function updateWalkingMan(){
 if ( Mixers.length > 0 ) {
  for ( var i = 0; i < Mixers.length; i ++ ) {
   Mixers[ i ].update(clock.getDelta());//clock.getDelta()
  }
 }
}

function render() {
 updateWalkingMan();
 requestAnimationFrame(render);
 renderer.render(scene, camera);
}

效果:

three.js搭建室内场景教程

在播放动画的同时,我们可以更改人物模型的位置、角度,达到在场景中走动的效果:

three.js搭建室内场景教程

会议室建模告一段落,这也是一次探索吧。后续的目标是封装常用的模型、在web中建立用户交互的建模方式,更加标准、快速的搭建室内场景。

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持三水点靠木。

Javascript 相关文章推荐
基于jQuery的图片剪切插件
Aug 03 Javascript
javascript学习笔记(一)基础知识
Sep 30 Javascript
AngularJS转换响应内容
Jan 27 Javascript
JS功能代码集锦
May 04 Javascript
NPM 安装cordova时警告:npm WARN deprecated minimatch@2.0.10: Please update to minimatch 3.0.2 or higher to
Dec 20 Javascript
微信小程序上滑加载下拉刷新(onscrollLower)分批加载数据(一)
May 11 Javascript
jquery实现侧边栏左右伸缩效果的示例
Dec 19 jQuery
详解微信图片防盗链“此图片来自微信公众平台 未经允许不得引用”的解决方案
Apr 04 Javascript
Koa从零搭建到Api实现项目的搭建方法
Jul 30 Javascript
VueJS实现用户管理系统
May 29 Javascript
利用Vue实现简易播放器的完整代码
Dec 30 Vue.js
vue.js watch经常失效的场景与解决方案
Jan 07 Vue.js
Three.JS实现三维场景
Dec 30 #Javascript
Three.js实现简单3D房间布局
Dec 30 #Javascript
JavaScript数组特性与实践应用深入详解
Dec 30 #Javascript
微信小程序实现通过双向滑动缩放图片大小的方法
Dec 30 #Javascript
微信小程序使用setData修改数组中单个对象的方法分析
Dec 30 #Javascript
微信小程序提交form操作示例
Dec 30 #Javascript
bootstrap下拉分页样式 带跳转页码
Dec 29 #Javascript
You might like
PHP生成带有雪花背景的验证码
2008/09/28 PHP
ASP.NET jQuery 实例14 在ASP.NET form中校验时间范围
2012/02/03 Javascript
JavaScript面向对象(极简主义法minimalist approach)
2012/07/17 Javascript
Highcharts 非常实用的Javascript统计图demo示例
2013/07/03 Javascript
对table和ul实现js分页示例分享
2014/02/24 Javascript
jQuery实现列表内容的动态载入特效
2015/08/08 Javascript
jquery实现无刷新验证码的简单实例
2016/05/19 Javascript
Vue-cli Eslint在vscode里代码自动格式化的方法
2018/02/23 Javascript
Vue开发之封装分页组件与使用示例
2019/04/25 Javascript
Vue 数据响应式相关总结
2021/01/28 Vue.js
python 运算符 供重载参考
2009/06/11 Python
python字符串加密解密的三种方法分享(base64 win32com)
2014/01/19 Python
Python类属性的延迟计算
2016/10/22 Python
基于Python列表解析(列表推导式)
2018/06/23 Python
mvc框架打造笔记之wsgi协议的优缺点以及接口实现
2018/08/01 Python
Python面向对象之类的定义与继承用法示例
2019/01/14 Python
Python中Numpy ndarray的使用详解
2019/05/24 Python
关于python 跨域处理方式详解
2020/03/28 Python
Django 用户认证Auth组件的使用
2020/11/30 Python
python爬虫调度器用法及实例代码
2020/11/30 Python
Python创建自己的加密货币的示例
2021/03/01 Python
澳大利亚拥有最好的家具和家居用品在线目的地:Nestz
2019/02/23 全球购物
Quiksilver美国官网:始于1969年的优质冲浪服和滑雪板外套
2020/04/20 全球购物
Urban Decay官方网站:美国化妆品品牌
2020/06/04 全球购物
俄罗斯厨房产品购物网站:COOK HOUSE
2021/03/15 全球购物
2019年c语言经典面试题目
2016/08/17 面试题
岗位竞聘演讲稿
2014/01/10 职场文书
酒店个人求职信范文
2014/01/25 职场文书
青春奉献演讲稿
2014/05/08 职场文书
行政管理专业求职信
2014/07/06 职场文书
警察群众路线整改措施
2014/09/26 职场文书
2014年安全员工作总结
2014/11/13 职场文书
企业介绍信范文
2015/01/30 职场文书
525心理健康活动总结
2015/05/08 职场文书
2015年小学财务工作总结
2015/07/20 职场文书
教你怎么用python爬取爱奇艺热门电影
2021/05/20 Python