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 相关文章推荐
为jquery.ui.dialog 增加“自动记住关闭时的位置”的功能
Nov 24 Javascript
jquery 检测元素是否存在的实例代码
Nov 19 Javascript
jquery图片切换实例分析
Apr 15 Javascript
javascript删除元素节点removeChild()用法实例
May 26 Javascript
JQuery入门基础小实例(1)
Sep 17 Javascript
利用Javascript仿Excel的数据透视分析功能
Sep 07 Javascript
js点击任意区域弹出层消失实现代码
Dec 27 Javascript
解决vue-cli创建项目的loader问题
Mar 13 Javascript
javacript replace 正则取字符串中的值并替换【推荐】
Sep 13 Javascript
vue.js中proxyTable 转发请求的实现方法
Sep 20 Javascript
JS使用百度地图API自动获取地址和经纬度操作示例
Apr 16 Javascript
微信小程序中weui用法解析
Oct 21 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
session 的生命周期是多长
2006/10/09 PHP
Blitz templates 最快的PHP模板引擎
2010/04/06 PHP
php验证手机号码(支持归属地查询及编码为UTF8)
2013/02/01 PHP
php 伪静态之IIS篇
2014/06/02 PHP
PHP支付系统设计与典型案例分享
2016/08/02 PHP
PHP实现用户异地登录提醒功能的方法【基于thinkPHP框架】
2018/03/15 PHP
PHP实现给定一列字符,生成指定长度的所有可能组合示例
2019/06/22 PHP
ThinkPHP5.1+Ajax实现的无刷新分页功能示例
2020/02/10 PHP
ExtJS PropertyGrid中使用Combobox选择值问题
2010/06/13 Javascript
Eval and new funciton not the same thing
2012/12/27 Javascript
JSON取值前判断
2014/12/23 Javascript
深入学习jQuery Validate表单验证
2016/01/18 Javascript
JS区分浏览器页面是刷新还是关闭
2016/04/17 Javascript
js友好的时间返回函数
2016/08/24 Javascript
基于JS实现限时抢购倒计时间表代码
2017/05/09 Javascript
分享ES6的7个实用技巧
2018/01/18 Javascript
微信小程序自定义导航栏
2018/12/31 Javascript
在vue项目中引入highcharts图表的方法
2019/01/21 Javascript
详解vue-cli+element-ui树形表格(多级表格折腾小计)
2019/04/17 Javascript
JS实现随机抽选获奖者
2019/11/07 Javascript
vue ajax 拦截原理与实现方法示例
2019/11/29 Javascript
在Angular项目使用socket.io实现通信的方法
2021/01/05 Javascript
Python使用sftp实现上传和下载功能(实例代码)
2017/03/14 Python
Python获取当前公网ip并自动断开宽带连接实例代码
2018/01/12 Python
Python cookbook(数据结构与算法)字典相关计算问题示例
2018/02/18 Python
Python 实现在文件中的每一行添加一个逗号
2018/04/29 Python
利用Django-environ如何区分不同环境
2018/08/26 Python
强悍的Python读取大文件的解决方案
2019/02/16 Python
Django上使用数据可视化利器Bokeh解析
2019/07/31 Python
python2和python3实现在图片上加汉字的方法
2019/08/22 Python
常用UNIX 命令(Linux的常用命令)
2015/12/26 面试题
五分钟演讲稿
2014/04/30 职场文书
关于读书的演讲稿600字
2014/08/27 职场文书
医院领导班子查摆问题对照检查材料思想汇报
2014/10/08 职场文书
2014年民主评议党员工作总结
2014/12/02 职场文书
部分武汉产收音机展览
2022/04/07 无线电