欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

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

程序员文章站 2023-02-21 16:21:53
本文实例为大家分享了three.js实现简单3d房间布局的具体代码,供大家参考,具体内容如下 废话不说了,直接上成果图。  代码如下 <...

本文实例为大家分享了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";第二种就是把图片位置的相对路径改成绝对路径。

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