您好,登錄后才能下訂單哦!
本文實例為大家分享了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" ></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";第二種就是把圖片位置的相對路徑改成絕對路徑。
以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支持億速云。
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。