Three.js实现简单3D房间布局


Posted in Javascript onDecember 30, 2018

本文实例为大家分享了Three.js实现简单3D房间布局的具体代码,供大家参考,具体内容如下

废话不说了,直接上成果图。

Three.js实现简单3D房间布局

 代码如下

<!doctype html>
<html lang="en">
<head>
<title>房间布局</title>
<meta charset="utf-8">
<meta name="viewport"
 content="width=device-width, user-scalable=no, minimum-scale=1.0, maximum-scale=1.0">
</head>
<body>
 
 
 <script src="js/jquery-1.9.1.js"></script>
 <script src="js/Three.min.js"></script>
 <script src="js/OrbitControls.js"></script>
 <script src="js/ThreeBSP.js"></script>
 <script src="js/Detector.js"></script>
 <script src="js/Stats.js"></script>
 
 
 <script src="js/THREEx.KeyboardState.js"></script>
 <script src="js/THREEx.FullScreen.js"></script>
 <script src="js/THREEx.WindowResize.js"></script>
 
 
 <!-- people -->
 <script src="people/js/three.js"></script>
 <script src="people/js/DDSLoader.js"></script>
 <script src="people/js/MTLLoader.js"></script>
 <script src="people/js/OBJLoader.js"></script>
 <script src="people/js/Detector.js"></script>
 <script src="people/js/stats.min.js"></script>
 <script src="people/js/PathControls.js"></script>
 <script src="people/js/Tween.js"></script>
 <script src="people/js/RequestAnimationFrame.js"></script>
 
 
 <div id="ThreeJS" style="position: absolute; left: 0px; top: 0px"></div>
 
 
 <script>
 // 设置全局变量
 var scene, camera, renderer, controls, tween, door;
 var keyboard = new THREEx.KeyboardState();//保持键盘的当前状态,可以随时查询
 var clock = new THREE.Clock();
 var SCREEN_WIDTH = window.innerWidth, SCREEN_HEIGHT = window.innerHeight;
 //var VIEW_ANGLE = 45, ASPECT = SCREEN_WIDTH / SCREEN_HEIGHT, NEAR = 0.1, FAR = 20000;
 var VIEW_ANGLE = 75, ASPECT = SCREEN_WIDTH / SCREEN_HEIGHT, NEAR = 0.1, FAR = 10000;
 var materialArrayA = [];
 var materialArrayB = [];
 var matArrayA = [];//内墙
 var matArrayB = [];//外墙
 var dummy = new THREE.Object3D();//仿制品
 init();
 animate();
 
 //1.场景   
 function initScene() {
 scene = new THREE.Scene();
 }
 
 //2.相机
 function initCamera() {
 camera = new THREE.PerspectiveCamera(VIEW_ANGLE, ASPECT, NEAR, FAR);
 camera.position.set(0, 1000, 1800);
 camera.lookAt(scene.position);
 camera.lookAt(0, 0, 0);
 scene.add(camera);
 }
 
 //3.渲染器
 function initRender() {
 if (Detector.webgl)
 renderer = new THREE.WebGLRenderer({
  antialias : true
 });
 else
 renderer = new THREE.CanvasRenderer();
 //设置渲染器的大小为窗口的内宽度,也就是内容区的宽度。
 renderer.setSize(SCREEN_WIDTH, SCREEN_HEIGHT);
 container = document.getElementById('ThreeJS');
 container.appendChild(renderer.domElement);
 renderer.setClearColor(0x4682B4, 1.0);
 }
 
 //4.事件
 function initEvent() {
 THREEx.WindowResize(renderer, camera);
 THREEx.FullScreen.bindKey({
 charCode : 'm'.charCodeAt(0)
 });
 }
 
 //5.控制
 function initControls() {
 controls = new THREE.OrbitControls(camera, renderer.domElement);
 }
 
 //6.光源
 function initLight() {
 // 位置不同,方向光作用于物体的面也不同,看到的物体各个面的颜色也不同 
 // A start, 第二个参数是光源强度
 var directionalLight = new THREE.DirectionalLight(0xffffff, 1);//模拟远处类似太阳的光源
 directionalLight.position.set(0, 100, 0).normalize();
 scene.add(directionalLight);
 //A end
 var ambient = new THREE.AmbientLight(0xffffff, 1); //AmbientLight,影响整个场景的光源
 ambient.position.set(0, 0, 0);
 scene.add(ambient);
 //var pointlight = new THREE.PointLight(0x000000,1.5,2000);
 //scene.add(pointlight); 
 }
 
 //创建地板 
 function createFloor() {
 var loader = new THREE.TextureLoader();
 loader.load("images/floor.jpg", function(texture) {
 texture.wrapS = texture.wrapT = THREE.RepeatWrapping;
 texture.repeat.set(10, 10);
 var floorGeometry = new THREE.BoxGeometry(1600, 1100, 1);
 var floorMaterial = new THREE.MeshBasicMaterial({
  map : texture,
  side : THREE.DoubleSide
 });
 var floor = new THREE.Mesh(floorGeometry, floorMaterial);
 floor.position.y = -0.5;
 floor.rotation.x = Math.PI / 2;
 scene.add(floor);
 });
 
 //茶色:0x58ACFA 透明玻璃色:0XECF1F3
 var glass_material = new THREE.MeshBasicMaterial({
 color : 0XECF1F3
 });
 glass_material.opacity = 0.4;
 glass_material.transparent = true;
 
 var left_wall = returnWallObject(20, 200, 1100, 0, matArrayB, -801,
  100, 0);
 var left_cube = returnWallObject(20, 110, 1100, 0, matArrayB, -801,
  100, 0);
 createResultBsp(left_wall, left_cube, 1);
 createCubeWall(1, 110, 1100, 0, glass_material, -801, 100, 0);
 
 var right_wall = returnWallObject(20, 200, 1100, 1, matArrayB, 801,
  100, 0);
 var right_cube = returnWallObject(20, 110, 1100, 0, matArrayB, 801,
  100, 0);
 createResultBsp(right_wall, right_cube, 1);
 createCubeWall(1, 110, 1100, 0, glass_material, 801, 100, 0);
 }
 
 //墙上挖门,通过两个几何体生成BSP对象
 function createResultBsp(bsp, less_bsp, mat) {
 switch (mat) {
 case 1:
 var material = new THREE.MeshPhongMaterial({
  color : 0x9cb2d1,
  specular : 0x9cb2d1,
  shininess : 30,
  transparent : true,
  opacity : 1
 });
 break;
 case 2:
 var material = new THREE.MeshPhongMaterial({
  color : 0xafc0ca,
  specular : 0xafc0ca,
  shininess : 30,
  transparent : true,
  opacity : 1
 });
 break;
 default:
 }
 
 var sphere1BSP = new ThreeBSP(bsp);
 var cube2BSP = new ThreeBSP(less_bsp);//0x9cb2d1 淡紫,0xC3C3C3 白灰 , 0xafc0ca灰
 var resultBSP = sphere1BSP.subtract(cube2BSP);
 var result = resultBSP.toMesh(material);
 result.material.flatshading = THREE.FlatShading;
 result.geometry.computeFaceNormals(); //重新计算几何体侧面法向量
 result.geometry.computeVertexNormals();
 result.material.needsUpdate = true; //更新纹理
 result.geometry.buffersNeedUpdate = true;
 result.geometry.uvsNeedUpdate = true;
 scene.add(result);
 }
 
 //创建墙
 function createCubeWall(width, height, depth, angle, material, x, y, z) {
 var cubeGeometry = new THREE.BoxGeometry(width, height, depth);
 var cube = new THREE.Mesh(cubeGeometry, material);
 cube.position.x = x;
 cube.position.y = y;
 cube.position.z = z;
 cube.rotation.y += angle * Math.PI; //-逆时针旋转,+顺时针
 scene.add(cube);
 }
 
 //返回墙对象
 function returnWallObject(width, height, depth, angle, material, x, y,
 z) {
 var cubeGeometry = new THREE.BoxGeometry(width, height, depth);
 var cube = new THREE.Mesh(cubeGeometry, material);
 cube.position.x = x;
 cube.position.y = y;
 cube.position.z = z;
 cube.rotation.y += angle * Math.PI;
 return cube;
 }
 
 //创建墙纹理
 function createWallMaterail() {
 matArrayA.push(new THREE.MeshPhongMaterial({
 color : 0xafc0ca
 })); //前 0xafc0ca :灰色
 matArrayA.push(new THREE.MeshPhongMaterial({
 color : 0xafc0ca
 })); //后 
 matArrayA.push(new THREE.MeshPhongMaterial({
 color : 0xd6e4ec
 })); //上 0xd6e4ec: 偏白色
 matArrayA.push(new THREE.MeshPhongMaterial({
 color : 0xd6e4ec
 })); //下 
 matArrayA.push(new THREE.MeshPhongMaterial({
 color : 0xafc0ca
 })); //左 0xafc0ca :灰色
 matArrayA.push(new THREE.MeshPhongMaterial({
 color : 0xafc0ca
 })); //右
 
 matArrayB.push(new THREE.MeshPhongMaterial({
 color : 0xafc0ca
 })); //前 0xafc0ca :灰色
 matArrayB.push(new THREE.MeshPhongMaterial({
 color : 0x9cb2d1
 })); //后 0x9cb2d1:淡紫
 matArrayB.push(new THREE.MeshPhongMaterial({
 color : 0xd6e4ec
 })); //上 0xd6e4ec: 偏白色
 matArrayB.push(new THREE.MeshPhongMaterial({
 color : 0xd6e4ec
 })); //下 
 matArrayB.push(new THREE.MeshPhongMaterial({
 color : 0xafc0ca
 })); //左 0xafc0ca :灰色
 matArrayB.push(new THREE.MeshPhongMaterial({
 color : 0xafc0ca
 })); //右
 
 }
 
 //创建房间布局
 function createLayout() {
 
 // 墙面1 立方体比较长的面 左一
 createCubeWall(10, 200, 900, 0, matArrayB, -651, 100, 0);
 // 墙面2 立方体比较长的面 右一
 createCubeWall(10, 200, 900, 1, matArrayB, 651, 100, 0);
 // 墙面3 门对面的墙 立方体比较短的面 
 createCubeWall(10, 200, 1310, 1.5, matArrayB, 0, 100, -451);
 
 // 墙面4 带门的面 
 var wall = returnWallObject(1310, 200, 10, 0, matArrayB, 0, 100,
  455);
 // 门框 
 var door_cube = returnWallObject(100, 180, 10, 0, matArrayB, 0, 90,
  455);
 createResultBsp(wall, door_cube, 1);
 
 //为墙面安装门,右门
 var loader = new THREE.TextureLoader();
 loader.load("images/door_right.png", function(texture) {
 var doorgeometry = new THREE.BoxGeometry(100, 180, 2);
 var doormaterial = new THREE.MeshBasicMaterial({
  map : texture,
  color : 0xffffff
 });
 doormaterial.opacity = 1.0;
 doormaterial.transparent = true;
 door = new THREE.Mesh(doorgeometry, doormaterial);
 door.position.set(-50, 0, 0);
 var door1 = door.clone();
 door1.position.set(50, 0, 0);
 door1.visible = false;
 dummy.add(door);
 dummy.add(door1);
 dummy.position.set(50, 90, 451)
 scene.add(dummy);
 });
 
 // 房间A:隔墙1 
 createCubeWall(10, 200, 250, 0, matArrayA, -151, 100, 325);
 //房间A:隔墙2 无门
 createCubeWall(10, 200, 220, 0.5, matArrayA, -256, 100, 201);
 // 厨房:隔墙3 
 createCubeWall(350, 200, 10, 0, matArrayA, 481, 100, 131);
 // 厨房:隔墙4 无门
 createCubeWall(10, 200, 200, 0, matArrayA, 301, 100, 225);
 // 房间B 
 createCubeWall(350, 200, 10, 0, matArrayA, -471, 100, -50);
 //房间B 无门
 createCubeWall(200, 200, 10, 0.5, matArrayA, 0, 100, -350);
 // 房间C
 createCubeWall(220, 200, 10, 0, matArrayA, 540, 100, -50);
 //房间C 无门
 createCubeWall(200, 200, 10, 0.5, matArrayA, 250, 100, -350);
 //厕所
 var cube = returnWallObject(10, 200, 260, 0.5, matArrayA, 125, 100,
  -250);
 //厕所门框
 var door_cube1 = returnWallObject(10, 160, 80, 0.5, matArrayA, 155,
  90, -250);
 createResultBsp(cube, door_cube1, 2);
 
 //茶色:0x58ACFA 透明玻璃色:0XECF1F3
 var glass_material = new THREE.MeshBasicMaterial({
 color : 0x58ACFA
 });
 glass_material.opacity = 0.6;
 glass_material.transparent = true;
 createCubeWall(1, 180, 80, 0.5, glass_material, 155, 90, -250);
 }
 
 //7.初始化OBJ对象
 function initObject() {
 //墙纹理
 createWallMaterail();
 createFloor();
 createLayout();
 }
 
 //初始化函数
 function init() {
 initScene();
 initCamera();
 initRender();
 initEvent();
 initControls();
 initLight();
 initObject();
 //监听键盘按键
 document.addEventListener("keydown", onkeyDown, false);
 }
 
 var door_state = true;//默认是门是关闭的
 //Enter=13,Space=32;
 function onkeyDown(event) {
 switch (event.keyCode) {
 case 13:
 console.log(event.keyCode);
 if (door_state) {
  dummy.rotation.y += 0.5 * Math.PI;
  door_state = false;
 } else {
  dummy.rotation.y -= 0.5 * Math.PI;
  door_state = true;
 }
 break;
 default:
 console.log(event.keyCode);
 break;
 }
 }
 
 function animate() {
 requestAnimationFrame(animate);
 renderer.render(scene, camera);
 TWEEN.update();
 update();
 }
 
 function update() {
 var delta = clock.getDelta();
 var moveDistance = 200 * delta;
 var rotateAngle = Math.PI / 2 * delta;
 controls.update();
 }
 </script>
</body>
</html>

通过Enter键可控制开门和关门动作。门的旋转是通过,把门克隆一份,把克隆的那个设置为不可见,然后把两个门打个组 ,这个时候中旋转组就可以了。

 此时的旋转中心实际是在组的中心,但设置一半不可见 ,看起来就像是门在旋转了。注意的是,组内的东西的坐标是相对于组的组内,两个门的坐标应该分别是x轴的正负轴上,整个组的位置应该是原来门应该在的位置。

这也是我向一位大神请教的,真的很感谢他那么耐心的教我。

运行方式:

在支持webgl的浏览器上打开room.html,即可看到效果图。如果加载不出来,打开Chrome快捷方式的属性中设置:右击Chrome浏览器快捷方式, 选择“属性”,在“目标”中加上"--allow-file-access-from-files",注意前面有个空格。修改完成,点击应用,确定后,关闭所有chrome上的窗口,重启chrome。再找到该资源room.html文件,以Google Chrome浏览器方式打开即可。

Three.js实现简单3D房间布局

错误解决。

如果出现地板和门的两张图片加载不出来时,提示已被跨源资源共享策略阻止加载。解决办法第一种是如上图所示在Chrome的属性加"--allow-file-access-from-files";第二种就是把图片位置的相对路径改成绝对路径。

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

Javascript 相关文章推荐
Highslide.js是一款基于js实现的网页中图片展示插件
Mar 30 Javascript
基于jquery的图片幻灯展示源码
Jul 15 Javascript
用js获取电脑信息(是使用与IE浏览器)
Jan 15 Javascript
Vuejs第一篇之入门教程详解(单向绑定、双向绑定、列表渲染、响应函数)
Sep 09 Javascript
javascript 数组去重复(在线去重工具)
Dec 17 Javascript
详解Python中logging日志模块在多进程环境下的使用
Dec 26 Javascript
JS实现汉字与Unicode码相互转换的方法详解
Apr 28 Javascript
Material(包括Material Icon)在Angular2中的使用详解
Feb 11 Javascript
vue数组对象排序的实现代码
Jun 20 Javascript
微信小程序实现手指触摸画板
Jul 09 Javascript
新年快乐! javascript实现超级炫酷的3D烟花特效
Jan 30 Javascript
vue简单封装axios插件和接口的统一管理操作示例
Feb 02 Javascript
JavaScript数组特性与实践应用深入详解
Dec 30 #Javascript
微信小程序实现通过双向滑动缩放图片大小的方法
Dec 30 #Javascript
微信小程序使用setData修改数组中单个对象的方法分析
Dec 30 #Javascript
微信小程序提交form操作示例
Dec 30 #Javascript
bootstrap下拉分页样式 带跳转页码
Dec 29 #Javascript
详解vue 兼容IE报错解决方案
Dec 29 #Javascript
玩转Koa之koa-router原理解析
Dec 29 #Javascript
You might like
PHP操作数组的一些函数整理介绍
2011/07/17 PHP
使用php+Ajax实现唯一校验实现代码[简单应用]
2011/11/29 PHP
PHP对象转换为数组函数(递归方法)
2012/02/04 PHP
php设置编码格式的方法
2013/03/05 PHP
把textarea中字符串里含有的回车换行替换成&amp;lt;br&amp;gt;的javascript代码
2007/04/20 Javascript
JavaScript 学习小结(适合新手参考)
2009/07/30 Javascript
JavaScript isArray()函数判断对象类型的种种方法
2010/10/11 Javascript
JavaScript arguments 多参传值函数
2010/10/24 Javascript
jquery.artwl.thickbox.js  一个非常简单好用的jQuery弹出层插件
2012/03/01 Javascript
jquery实现excel导出的方法
2013/04/04 Javascript
JavaScript中一个奇葩的IE浏览器判断方法
2014/04/16 Javascript
简介JavaScript中search()方法的使用
2015/06/06 Javascript
jqGrid翻页时数据选中丢失问题的解决办法
2017/02/13 Javascript
Node.js连接mongodb实例代码
2017/06/06 Javascript
vue 2.0项目中如何引入element-ui详解
2017/09/06 Javascript
JS实现静态页面搜索并高亮显示功能完整示例
2017/09/19 Javascript
原生JavaScript实现Ajax异步请求
2017/11/19 Javascript
es6新特性之 class 基本用法解析
2018/05/05 Javascript
vue 项目打包时样式及背景图片路径找不到的解决方式
2019/11/12 Javascript
python中getaddrinfo()基本用法实例分析
2015/06/28 Python
用python3 返回鼠标位置的实现方法(带界面)
2019/07/05 Python
python操作excel让工作自动化
2019/08/09 Python
CSS3 Flexbox中flex-shrink属性的用法示例介绍
2013/12/30 HTML / CSS
波兰最大的度假胜地和城市公寓租赁运营商:Sun & Snow
2018/10/18 全球购物
新西兰最大的连锁超市:Countdown
2020/06/04 全球购物
JS原生实现轮播图的几种方法
2021/03/23 Javascript
财务管理专业应届毕业生求职信
2013/09/22 职场文书
新闻专业本科生的自我评价分享
2013/11/20 职场文书
秋季运动会广播稿
2014/02/22 职场文书
啦啦队口号大全
2014/06/16 职场文书
司法局群众路线教育实践活动整改措施
2014/09/17 职场文书
党员对照检查材料
2014/09/22 职场文书
2014年房地产工作总结范文
2014/11/19 职场文书
关于考试抄袭的检讨书
2019/11/02 职场文书
简述python四种分词工具,盘点哪个更好用?
2021/04/13 Python
Java基于字符界面的简易收银台
2021/06/26 Java/Android