一、挖空原理說明
subtract 用牆面減去與門重疊的部分,產生一個新的對象,導入材質安裝門即可
//參與減去幾何體 //平行於x軸門 var meshH4Door = new ThreeBSP( meshHDoor ); //平行x軸橫牆面 var meshWall4 = new ThreeBSP( meshH4 ); //平行x軸橫牆面meshWall4對象 減去與meshH4Door門重疊部分 var subtract_bsp = meshWall4.subtract( meshH4Door ); var result = subtract_bsp.toMesh( new THREE.MeshLambertMaterial({ shading: THREE.SmoothShading, map: THREE.ImageUtils.loadTexture('./img/floor-1.jpg'), color: 0xff0000}) ); result.geometry.computeVertexNormals(); //添加至場景中 scene.add( result );
效果圖
源代碼如下
<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>threejs中挖空解決閃爍bug</title> <style> #canvas-frame { width: 100%; height: 450px; } </style> </head> <body onload="threeStart()"> <div id="canvas-frame" ></div> </body> <script type="text/javascript" src="./lib/three.js" ></script> <!-- 運算挖門 解決閃爍bug --> <script type="text/javascript" src="lib/ThreeCSG.js"></script> <script type="text/javascript"> var renderer, //渲染器 width = document.getElementById('canvas-frame').clientWidth, //畫布寬 height = document.getElementById('canvas-frame').clientHeight; //畫布高 //照相機配置 var fov = 45,//拍攝距離 視野角值越大,場景中的物體越小 near = 1,//最小范圍 far = 1000;//最大范圍 //DOM對象 var canvas = null; //初始化DOM對象 function initDOM(){ canvas = document.getElementById("canvas-frame"); } //初始化渲染器 function initThree(){ renderer = new THREE.WebGLRenderer({ antialias : true //canvas: document.getElementById('canvas-frame') }); renderer.setSize(width, height); renderer.setClearColor(0xFFFFFF, 1.0); document.getElementById('canvas-frame').appendChild(renderer.domElement); renderer.setClearColor(0xFFFFFF, 1.0); } //初始化場景 var scene; function initScene(){ scene = new THREE.Scene(); } var camera; function initCamera() { //透視相機 camera = new THREE.PerspectiveCamera(fov, width/height , near, far); camera.position.x = 150; camera.position.y = 150; camera.position.z =450; camera.up.x = 0; camera.up.y = 1; //相機朝向--相機上方為y軸 camera.up.z = 0; camera.lookAt({ //相機的中心點 x : 0, y : 0, z : 0 }); } function initLight(){ // light--這里使用環境光 //var light = new THREE.DirectionalLight(0xffffff); /*方向性光源*/ //light.position.set(600, 1000, 800); var light = new THREE.AmbientLight(0xffffff); //模擬漫反射光源 light.position.set(600, 1000, 800); //使用Ambient Light時可以忽略方向和角度,只考慮光源的位置 scene.add(light); } function initObject(){ //初始化對象 //初始化地板 initFloor(); initWall(); } function initGrid(){ //輔助網格 var helper = new THREE.GridHelper( 1000, 50 ); helper.setColors( 0x0000ff, 0x808080 ); scene.add( helper ); } function initFloor(){ //導入材質 var texture = THREE.ImageUtils.loadTexture('img/floor-1.jpg', {}, function() { renderer.render(scene, camera); }); /** * 關於material材料注意點說明 * MeshBasicMaterial:對光照無感,給幾何體一種簡單的顏色或顯示線框。 * MeshLambertMaterial:這種材質對光照有反應,用於創建暗淡的不發光的物體。 * MeshPhongMaterial:這種材質對光照也有反應,用於創建金屬類明亮的物體。 */ var material = new THREE.MeshLambertMaterial({ map: texture }); //創建一個立方體 var geometry = new THREE.BoxGeometry(400, 20, 400); for ( var i = 0; i < geometry.faces.length; i += 2 ) { var hex = Math.random() * 0xffffff; geometry.faces[ i ].color.setHex( hex ); geometry.faces[ i + 1 ].color.setHex( hex ); } //var material = new THREE.MeshBasicMaterial( { vertexColors: THREE.FaceColors} ); //將material材料添加到幾何體geometry var mesh = new THREE.Mesh(geometry, material); mesh.position = new THREE.Vector3(0,0,0); scene.add(mesh); } //牆面 function initWall(){ //導入牆面材質(后面牆面共用) var texture = THREE.ImageUtils.loadTexture('img/floor-1.jpg', {}, function() { renderer.render(scene, camera); }); /** * 關於material材料注意點說明 * MeshBasicMaterial:對光照無感,給幾何體一種簡單的顏色或顯示線框。 * MeshLambertMaterial:這種材質對光照有反應,用於創建暗淡的不發光的物體。 * MeshPhongMaterial:這種材質對光照也有反應,用於創建金屬類明亮的物體。 */ var material = new THREE.MeshLambertMaterial({ map: texture }); /*--------平行z軸橫牆面3、x軸為牆面的厚度、 z軸為牆面長度、y軸為牆面高度--------------------*/ //平行z軸橫牆面1 x軸為牆面厚度 var geometryH1 = new THREE.BoxGeometry(10, 65, 360); /*var materialH1 = new THREE.MeshBasicMaterial( { color:0xFF0000 } );*/ //將material材料添加到幾何體geometry var meshH1 = new THREE.Mesh(geometryH1, material); meshH1.position.x = 180; meshH1.position.y = 45; //scene.add(meshH1); var meshWall1 = new ThreeBSP( meshH1 ); var geometryHDoor1 = new THREE.BoxGeometry(10, 56, 35); var materialHDoor1 = new THREE.MeshBasicMaterial( { color:0x00BBAA} ); //將material材料添加到幾何體geometry var meshHDoor1 = new THREE.Mesh(geometryHDoor1, materialHDoor1); meshHDoor1.position.x = 180; meshHDoor1.position.y = 45; meshHDoor1.position.z = 0; //scene.add(meshHDoor2); var meshHDoor1 = new ThreeBSP( meshHDoor1 ); //牆面減去重疊的門 subtractMesh(meshHDoor1, meshWall1); //為牆面1安裝門 var geometryHDoor1 = new THREE.BoxGeometry(10, 56, 35); //加載材質 var textureDoor1 = THREE.ImageUtils.loadTexture('img/door.png', {}, function() { renderer.render(scene, camera); }); var materialDoor1 = new THREE.MeshBasicMaterial({ map: textureDoor1 }); //var materialHDoor2 = new THREE.MeshBasicMaterial( { color:0x00BBAA} ); //將material材料添加到幾何體geometry var meshHDoor1 = new THREE.Mesh(geometryHDoor1, materialDoor1); meshHDoor1.position.x = 180; meshHDoor1.position.y = 45; meshHDoor1.position.z = 0; scene.add(meshHDoor1); //平行z軸橫牆面2 x軸為牆面厚度 var geometryH2 = new THREE.BoxGeometry(10, 65, 360); var materialH2 = new THREE.MeshBasicMaterial( { color:0xFF00FF } ); //將material材料添加到幾何體geometry var meshH2 = new THREE.Mesh(geometryH2, materialH2); meshH2.position.x = -180; meshH2.position.y = 45; var meshWall2 = new ThreeBSP( meshH2 ); //scene.add(meshH2); var geometryHDoor2 = new THREE.BoxGeometry(10, 56, 35); var materialHDoor2 = new THREE.MeshBasicMaterial( { color:0x00BBAA} ); //將material材料添加到幾何體geometry var meshHDoor2 = new THREE.Mesh(geometryHDoor2, materialHDoor2); meshHDoor2.position.x = -180; meshHDoor2.position.y = 45; meshHDoor2.position.z = 0; var meshHDoor2 = new ThreeBSP( meshHDoor2 ); //scene.add(meshHDoor2); //牆面減去重疊的門 subtractMesh(meshHDoor2, meshWall2); //為牆面2安裝門 var geometryHDoor2 = new THREE.BoxGeometry(10, 56, 35); //加載材質 var textureDoor2 = THREE.ImageUtils.loadTexture('img/door.png', {}, function() { renderer.render(scene, camera); }); var materialDoor2 = new THREE.MeshBasicMaterial({ map: textureDoor2 }); //var materialHDoor2 = new THREE.MeshBasicMaterial( { color:0x00BBAA} ); //將material材料添加到幾何體geometry var meshHDoor2 = new THREE.Mesh(geometryHDoor2, materialDoor2); meshHDoor2.position.x = -180; meshHDoor2.position.y = 45; meshHDoor2.position.z = 0; scene.add(meshHDoor2); /*--------平行z軸橫牆面3、x軸為牆面的厚度、 z軸為牆面長度、y軸為牆面高度--------------------*/ /*--------平行x軸橫牆面3、x軸為牆面長度、 z軸為牆面厚度、y軸為牆面高度--------------------*/ //平行x軸橫牆面3 z軸為牆面厚度 var geometryH3 = new THREE.BoxGeometry(365, 65, 10); var materialH3 = new THREE.MeshBasicMaterial( { color:0x808080 } ); //將material材料添加到幾何體geometry var meshH3 = new THREE.Mesh(geometryH3, material); meshH3.position.x = 0; meshH3.position.y = 45; meshH3.position.z = -180; var meshWall3 = new ThreeBSP( meshH3 ); //scene.add(meshH3); //平行x軸橫重疊門3 z軸為牆面厚度 var geometryHDoor = new THREE.BoxGeometry(35, 50, 10); var materialHDoor = new THREE.MeshBasicMaterial( { color:0x00BBAA} ); //將material材料添加到幾何體geometry var meshHDoor = new THREE.Mesh(geometryHDoor, materialHDoor); meshHDoor.position.x = 0; meshHDoor.position.y = 45; meshHDoor.position.z = -180; var meshHDoor3 = new ThreeBSP( meshHDoor ); //scene.add(meshHDoor); //牆面減去重疊的門 subtractMesh(meshHDoor3, meshWall3); //平行x軸橫牆面3安裝門 var geometryDoor3 = new THREE.BoxGeometry(35, 50, 10); //加載材質 var textureDoor3 = THREE.ImageUtils.loadTexture('img/door.png', {}, function() { renderer.render(scene, camera); }); var materialDoor3 = new THREE.MeshBasicMaterial({ map: textureDoor3 }); door3 = new THREE.Mesh( geometryDoor3,materialDoor3); door3.position.x = 0; door3.position.y = 45; door3.position.z = -180; scene.add(door3); /*--------平行x軸橫牆面3、 z軸為牆面厚度、y軸為牆面高度--------------------*/ /*--------平行x軸橫牆面4、 z軸為牆面厚度、y軸為牆面高度--------------------*/ //平行x軸橫牆面4 z軸為牆面厚度 var geometryH4 = new THREE.BoxGeometry(365, 65, 10); var materialH4 = new THREE.MeshBasicMaterial( { color:0x00AABB, wireframe: true} ); //將material材料添加到幾何體geometry var meshH4 = new THREE.Mesh(geometryH4, materialH4); meshH4.position.x = 0; meshH4.position.y = 45; meshH4.position.z = 180; //平行x軸橫牆面4 挖出一道門 var meshWall4 = new ThreeBSP( meshH4 ); //scene.add(meshH4); //平行x軸橫重疊門4 z軸為牆面厚度 var geometryHDoor = new THREE.BoxGeometry(35, 50, 10); var materialHDoor = new THREE.MeshBasicMaterial( { color:0x00BBAA} ); //將material材料添加到幾何體geometry var meshHDoor = new THREE.Mesh(geometryHDoor, materialHDoor); meshHDoor.position.x = 0; meshHDoor.position.y = 45; meshHDoor.position.z = 180; //scene.add(meshHDoor); //重疊門 var meshHDoor4 = new ThreeBSP( meshHDoor ); //牆面減去重疊的門 subtractMesh(meshHDoor4, meshWall4); //平行x軸橫牆面4安裝門 var geometryDoor4 = new THREE.BoxGeometry(35, 50, 10); //加載材質 var textureDoor4 = THREE.ImageUtils.loadTexture('img/door.png', {}, function() { renderer.render(scene, camera); }); var materialDoor4 = new THREE.MeshBasicMaterial({ map: textureDoor4 }); door4 = new THREE.Mesh( geometryDoor4,materialDoor4); door4.position.x = 0; door4.position.y = 45; door4.position.z = 180; scene.add(door4); /*--------平行x軸橫牆面3、x軸為牆面長度、 z軸為牆面厚度、y軸為牆面高度-------------------*/ } //運算減去 /* * meshDoor 門面 * meshWall 牆面 */ function subtractMesh(meshDoor,meshWall){ //平行x軸橫牆面4減去與meshHDoor門重疊部分 var subtract_bsp = meshWall.subtract( meshDoor ); var result = subtract_bsp.toMesh( new THREE.MeshLambertMaterial({ shading: THREE.SmoothShading, map: THREE.ImageUtils.loadTexture('./img/floor-1.jpg') })); result.geometry.computeVertexNormals(); scene.add( result ); } //初始化頁面加載 function threeStart(){ //初始化DOM對象 initDOM(); //初始化渲染器 initThree(); //初始化場景 initScene(); //初始透視化相機 initCamera(); //初始化光源 initLight(); //模型對象 initObject(); //初始化網格輔助線 initGrid(); //渲染 //renderer.render(scene, camera); //實時動畫 animation(); //監聽鼠標滾動事件 canvas.addEventListener('mousewheel', mousewheel, false); } function animation(){ //相機圍繞y軸旋轉,並且保持場景中的物體一直再相機的視野中 //實時渲染成像 var timer = Date.now()*0.0001; camera.position.x = Math.cos(timer)*400; camera.position.z = Math.sin(timer)*400; camera.lookAt(scene.position); renderer.render(scene, camera); requestAnimationFrame(animation); } //鼠標滑輪-鼠標上下滑輪實現放大縮小效果 function mousewheel(e) { e.preventDefault(); //e.stopPropagation(); if (e.wheelDelta) { //判斷瀏覽器IE,谷歌滑輪事件 if (e.wheelDelta > 0) { //當滑輪向上滾動時 fov -= (near < fov ? 1 : 0); } if (e.wheelDelta < 0) { //當滑輪向下滾動時 fov += (fov < far ? 1 : 0); } } else if (e.detail) { //Firefox滑輪事件 if (e.detail > 0) { //當滑輪向上滾動時 fov -= 1; } if (e.detail < 0) { //當滑輪向下滾動時 fov += 1; } } //改變fov值,並更新場景的渲染 camera.fov = fov; camera.updateProjectionMatrix(); renderer.render(scene, camera); //updateinfo(); } </script> </html>