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浏览器方式打开即可。
错误解决。
如果出现地板和门的两张图片加载不出来时,提示已被跨源资源共享策略阻止加载。解决办法第一种是如上图所示在chrome的属性加"--allow-file-access-from-files";第二种就是把图片位置的相对路径改成绝对路径。
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持。
上一篇: JavaScript ES6中的简写语法总结与使用技巧
下一篇: dotNet中的反射用法入门教程