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 相关文章推荐
[原创]后缀就扩展名为js的文件是什么文件
Dec 06 Javascript
jquery如何获取复选框的值
Dec 12 Javascript
基于JQuery实现的图片自动进行缩放和裁剪处理
Jan 31 Javascript
轻松学习Javascript闭包函数
Dec 15 Javascript
Bootstrap学习笔记之css样式设计(1)
Jun 07 Javascript
jquery与ajax获取特殊字符实例详解
Jan 08 Javascript
浅析JS中的 map, filter, some, every, forEach, for in, for of 用法总结
Mar 29 Javascript
vue-cli如何快速构建vue项目
Apr 26 Javascript
微信小程序实现天气预报功能
Jul 18 Javascript
JS实现判断图片是否加载完成的方法分析
Jul 31 Javascript
vue基础之v-bind属性、class和style用法分析
Mar 11 Javascript
JavaScript日期库date-fn.js使用方法解析
Sep 09 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实现word转html的方法
2016/01/22 PHP
PHP基于curl后台远程登录正方教务系统的方法
2016/10/14 PHP
redis+php实现微博(三)微博列表功能详解
2019/09/23 PHP
Jquery常用技巧收集整理篇
2010/11/14 Javascript
extjs tabpanel限制选项卡数量实现思路及代码
2013/04/02 Javascript
Script标签与访问HTML页面详解
2014/01/10 Javascript
用jQuery模拟select下拉框的简单示例代码
2014/01/26 Javascript
判断iframe里的页面是否加载完成
2014/06/06 Javascript
可编辑下拉框的2种实现方式
2014/06/13 Javascript
js图片翻书效果代码分享
2015/08/20 Javascript
vue数据双向绑定原理解析(get &amp; set)
2017/03/08 Javascript
利用pm2部署多个node.js项目的配置教程
2017/10/22 Javascript
js实现复制功能(多种方法集合)
2018/01/06 Javascript
详解react-refetch的使用小例子
2019/02/15 Javascript
swiper实现异形轮播效果
2019/11/28 Javascript
通过实例解析javascript Date对象属性及方法
2020/11/04 Javascript
微信小程序实现首页弹出广告
2020/12/03 Javascript
[02:19]DOTA2女子战队FOX视频专访:希望更多美眉一起加入
2013/10/15 DOTA
[40:05]LGD vs Winstrike 2018国际邀请赛小组赛BO2 第二场 8.17
2018/08/18 DOTA
python访问系统环境变量的方法
2015/04/29 Python
Django + Uwsgi + Nginx 实现生产环境部署的方法
2018/06/20 Python
详解Python的循环结构知识点
2019/05/20 Python
python实现QQ邮箱发送邮件
2020/03/06 Python
django实现模型字段动态choice的操作
2020/04/01 Python
python保留格式汇总各部门excel内容的实现思路
2020/06/01 Python
python 将Excel转Word的示例
2021/03/02 Python
Fossil美国官网:Fossil手表、手袋、珠宝及配件
2017/02/01 全球购物
男女时尚与复古风格在线购物:RoseGal(全球免费送货)
2017/07/19 全球购物
工作中的自我评价如何写好
2013/10/28 职场文书
物业管理专业个人的自我评价
2013/11/19 职场文书
酒店管理毕业生自荐信
2014/05/25 职场文书
专科生就业求职信
2014/06/22 职场文书
推广活动策划方案
2014/08/23 职场文书
见习报告的格式
2014/10/31 职场文书
离职报告范文
2014/11/04 职场文书
医药公司采购员岗位职责
2015/04/03 职场文书