一、挖空原理說明
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>
