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 相关文章推荐
列表内容的选择
Jun 30 Javascript
javascript 数组的方法集合
Jun 05 Javascript
百度留言本js 大家可以参考下
Oct 13 Javascript
监控 url fragment变化的js代码
Apr 19 Javascript
浅析jQuery EasyUI中的tree使用指南
Dec 18 Javascript
JavaScript模板引擎用法实例
Jul 10 Javascript
js淡入淡出焦点图幻灯片效果代码分享
Sep 08 Javascript
jQuery实现横向带缓冲的水平运动效果(附demo源码下载)
Jan 29 Javascript
JS中使用apply、bind实现为函数或者类传入动态个数的参数
Apr 26 Javascript
Node.js中sequelize时区的配置方法
Dec 10 Javascript
详解vue服务端渲染浏览器端缓存(keep-alive)
Oct 12 Javascript
Nuxt.js nuxt-link与router-link的区别说明
Nov 06 Javascript
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实现链结人气统计
2006/10/09 PHP
PHP+MYSQL开发工具及资源收藏
2007/01/02 PHP
js innerHTML 的一些问题的解决方法
2008/06/22 Javascript
IE Firefox 使用自定义标签的区别
2009/10/15 Javascript
javascript与CSS复习(《精通javascript》)
2010/06/29 Javascript
在Ajax中使用Flash实现跨域数据读取的实现方法
2010/12/02 Javascript
JavaScript 计算图片加载数量的代码
2011/01/01 Javascript
基于jquery的拖动布局插件
2011/11/25 Javascript
点击弹出层外区域关闭弹出层jquery特效示例
2013/08/25 Javascript
JavaScript中的公有、私有、特权和静态成员用法分析
2014/11/20 Javascript
javascript入门教程基础篇
2015/11/16 Javascript
jQuery EasyUI框架中的Datagrid数据表格组件结构详解
2016/06/09 Javascript
关于input全选反选恶心的异常情况
2016/07/24 Javascript
Bootstrap框架安装使用详解
2017/01/21 Javascript
vue子组件使用自定义事件向父组件传递数据
2017/05/27 Javascript
vue渲染时闪烁{{}}的问题及解决方法
2018/03/28 Javascript
vue路由组件按需加载的几种方法小结
2018/07/12 Javascript
详解Vue、element-ui、axios实现省市区三级联动
2019/05/07 Javascript
Vue + element 实现多选框组并保存已选id集合的示例代码
2020/06/03 Javascript
详解JavaScript中new操作符的解析和实现
2020/09/04 Javascript
关于angular 8.1使用过程中的一些记录
2020/11/25 Javascript
[03:10]超级美酒第四天 fy拉比克秀 大合集
2018/06/05 DOTA
深入理解python try异常处理机制
2016/06/01 Python
python如何去除字符串中不想要的字符
2020/07/05 Python
使用OpenCV circle函数图像上画圆的示例代码
2019/12/27 Python
对tensorflow 中tile函数的使用详解
2020/02/07 Python
Django查询优化及ajax编码格式原理解析
2020/03/25 Python
接口中的方法可以是abstract的吗
2015/07/23 面试题
优秀党员获奖感言
2014/02/18 职场文书
广告创意求职信
2014/03/17 职场文书
2014年电话客服工作总结
2014/12/09 职场文书
关于战胜挫折的名言警句大全!
2019/07/05 职场文书
不会写演讲稿,快来看看这篇文章!
2019/08/06 职场文书
Python基础之tkinter图形化界面学习
2021/04/29 Python
Java 中的 Unsafe 魔法类的作用大全
2021/06/26 Java/Android
深入浅析python3 依赖倒置原则(示例代码)
2021/07/09 Python