前言
threejs实现一个多层模型的剖分,剖分出来的是实心的
效果
代码
var planes, planeObjects=[],planeObjects2=[], planeObjects3=[], planeHelpers;
var params = {planeY: {constant: 0,negated: false,displayHelper: false},};
init();
animate();
function createPlaneStencilGroup( geometry, plane, renderOrder ) {
var group = new THREE.Group();
var baseMat = new THREE.MeshBasicMaterial();
baseMat.depthWrite = false;
baseMat.depthTest = false;
baseMat.colorWrite = false;
baseMat.stencilWrite = true;
baseMat.stencilFunc = THREE.AlwaysStencilFunc;
var mat0 = baseMat.clone();
mat0.side = THREE.BackSide;
mat0.clippingPlanes = [ plane ];
mat0.stencilFail = THREE.IncrementWrapStencilOp;
mat0.stencilZFail = THREE.IncrementWrapStencilOp;
mat0.stencilZPass = THREE.IncrementWrapStencilOp;
var mesh0 = new THREE.Mesh( geometry, mat0 );
mesh0.renderOrder = renderOrder;
group.add( mesh0 );
var mat1 = baseMat.clone();
mat1.side = THREE.FrontSide;
mat1.clippingPlanes = [ plane ];
mat1.stencilFail = THREE.DecrementWrapStencilOp;
mat1.stencilZFail = THREE.DecrementWrapStencilOp;
mat1.stencilZPass = THREE.DecrementWrapStencilOp;
var mesh1 = new THREE.Mesh( geometry, mat1 );
mesh1.renderOrder = renderOrder;
group.add( mesh1 );
return group;
}
function init() {
scene = new THREE.Scene();
camera = new THREE.PerspectiveCamera( 36, window.innerWidth / window.innerHeight, 1, 100000 );
camera.position.set( 0, 0, 20 );
let ambientLight = new THREE.AmbientLight(0xcccccc,0.6);
scene.add(ambientLight);
var dirLight = new THREE.DirectionalLight( 0xffffff, 1 );
scene.add( dirLight );
planes = [new THREE.Plane( new THREE.Vector3( - 1,0, 0 ), 0 ),];
scene.add(new THREE.AmbientLight(0xffffff,1));
object = new THREE.Group();
object2 = new THREE.Group();
object3 = new THREE.Group();
scene.add( object );
scene.add( object2 );
scene.add( object3 );
var obj_loader = new OBJLoader();
var mtl_loader=new MTLLoader();
var obj_loader2 = new OBJLoader();
var mtl_loader2 =new MTLLoader();
var obj_loader3 = new OBJLoader();
var mtl_loader3 =new MTLLoader();
mtl_loader2.load( '/zeng/box.mtl', function (materials ) {
materials.preload();
obj_loader2.setMaterials(materials);
obj_loader2.load( '/zeng/box.obj', function (obj ) {
obj.scale.set(0.0001,0.0001,0.0001);
let bbox = new THREE.Box3().setFromObject(obj);
var x=-(bbox.max.x+bbox.min.x)/2;
var y=-(bbox.max.y+bbox.min.y)/2;
var z= -(bbox.max.z+bbox.min.z)/2;
obj.position.set(-(bbox.max.x+bbox.min.x)/2,-(bbox.max.y+bbox.min.y)/2,-(bbox.max.z+bbox.min.z)/2);
obj.traverse(function(child){
if (child instanceof THREE.Mesh) {
child.material = new THREE.MeshStandardMaterial({
color: child.material.color,
metalness: 0.1,
roughness: 0.75,
clippingPlanes: planes,
clipShadows: true,
shadowSide: THREE.DoubleSide,
side: THREE.DoubleSide,
});
child.castShadow = true;
child.renderOrder = 6;
}
})
object2.add(obj);
var planeGeom = new THREE.PlaneGeometry( 4000, 4000 );
var poGroup = new THREE.Group();
var plane = planes[ 0 ];
for (var w = 0; w < obj.children.length; w++) {
var geometry0 = object2.children[0].children[w].geometry.clone();
geometry0.translate(x/0.0001, y/0.0001, z/0.0001);
var stencilGroup = createPlaneStencilGroup(geometry0, plane, 1);
stencilGroup.scale.set(0.0001,0.0001,0.0001)
object2.add(stencilGroup);
}
var planeMat =new THREE.MeshBasicMaterial( {
color: 0x4B580C,
metalness: 0.1, //金属度属性
roughness: 0.75, //粗糙度
clippingPlanes: planes.filter( p => p !== plane ),
stencilWrite: true,
stencilRef: 0,
stencilFunc: THREE.NotEqualStencilFunc,
stencilFail: THREE.ReplaceStencilOp,
stencilZFail: THREE.ReplaceStencilOp,
stencilZPass: THREE.ReplaceStencilOp,
} );
var po = new THREE.Mesh( planeGeom, planeMat );
po.onAfterRender = function ( renderer ) {renderer.clearStencil();};
po.renderOrder = 1.1;
poGroup.add( po );
planeObjects2.push( po );
scene.add( poGroup );
});
})
mtl_loader.load( '/zeng/box.mtl', function (materials ) {
console.log(materials,'materials')
materials.preload();
obj_loader.setMaterials(materials);
obj_loader.load( '/zeng/box.obj', function (obj ) {
console.log(obj,'obj')
obj.position.y =40
obj.scale.set(0.0001,0.0001,0.0001);
let bbox = new THREE.Box3().setFromObject(obj);
var x=-(bbox.max.x+bbox.min.x)/2;
var y=-(bbox.max.y+bbox.min.y)/2;
var z= -(bbox.max.z+bbox.min.z)/2;
obj.position.set(-(bbox.max.x+bbox.min.x)/2,-(bbox.max.y+bbox.min.y)/2,-(bbox.max.z+bbox.min.z)/2);
obj.traverse(function(child){
if (child instanceof THREE.Mesh) {
child.material = new THREE.MeshStandardMaterial({
color: child.material.color,
metalness: 0.1,
roughness: 0.75,
clippingPlanes: planes,
clipShadows: true,
shadowSide: THREE.DoubleSide,
side: THREE.DoubleSide,
});
child.castShadow = true;
child.renderOrder = 6;
}
})
object.add(obj);
var planeGeom = new THREE.PlaneGeometry( 4000, 4000 );
var poGroup = new THREE.Group();
var plane = planes[ 0 ];
for (var w = 0; w < obj.children.length; w++) {
var geometry0 = object.children[0].children[w].geometry.clone();
geometry0.translate(x/0.0001, y/0.0001, z/0.0001);
var stencilGroup = createPlaneStencilGroup(geometry0, plane, 2);
stencilGroup.scale.set(0.0001,0.0001,0.0001)
object.add(stencilGroup);
}
var planeMat =new THREE.MeshBasicMaterial( {
color: 0x1C1C1C,
metalness: 0.1, //金属度属性
roughness: 0.75, //粗糙度
clippingPlanes: planes.filter( p => p !== plane ),
stencilWrite: true,
stencilRef: 0,
stencilFunc: THREE.NotEqualStencilFunc,
stencilFail: THREE.ReplaceStencilOp,
stencilZFail: THREE.ReplaceStencilOp,
stencilZPass: THREE.ReplaceStencilOp,
} );
var po = new THREE.Mesh( planeGeom, planeMat );
po.onAfterRender = function ( renderer ) {renderer.clearStencil();};
po.renderOrder = 2.1;
poGroup.add( po );
planeObjects.push( po );
scene.add( poGroup );
});
})
mtl_loader3.load( '/zeng/box.mtl', function (materials ) {
materials.preload();
obj_loader3.setMaterials(materials);
obj_loader3.load( '/zeng/box.obj', function (obj ) {
obj.position.y = 80
obj.scale.set(0.0001,0.0001,0.0001);
let bbox = new THREE.Box3().setFromObject(obj);
var x=-(bbox.max.x+bbox.min.x)/2;
var y=-(bbox.max.y+bbox.min.y)/2;
var z= -(bbox.max.z+bbox.min.z)/2;
obj.position.set(-(bbox.max.x+bbox.min.x)/2,-(bbox.max.y+bbox.min.y)/2,-(bbox.max.z+bbox.min.z)/2);
obj.traverse(function(child){
if (child instanceof THREE.Mesh) {
child.material = new THREE.MeshStandardMaterial({
color: child.material.color,
metalness: 0.1, //金属度属性
roughness: 0.75, //粗糙度
clippingPlanes: planes,
clipShadows: true,
shadowSide: THREE.DoubleSide,
side: THREE.DoubleSide,
});
child.castShadow = true;
child.renderOrder = 6;
}
})
object3.add(obj);
var planeGeom = new THREE.PlaneGeometry( 4000, 4000 );
var poGroup = new THREE.Group();
var plane = planes[ 0 ];
for (var w = 0; w < obj.children.length; w++) {
var geometry0 = object3.children[0].children[w].geometry.clone();
geometry0.translate(x/0.0001, y/0.0001, z/0.0001);
var stencilGroup = createPlaneStencilGroup(geometry0, plane, 3);
stencilGroup.scale.set(0.0001,0.0001,0.0001)
object3.add(stencilGroup);
}
var planeMat =new THREE.MeshBasicMaterial( {
color: 0x00B000,
metalness: 0.1, //金属度属性
roughness: 0.75, //粗糙度
clippingPlanes: planes.filter( p => p !== plane ),
stencilWrite: true,
stencilRef: 0,
stencilFunc: THREE.NotEqualStencilFunc,
stencilFail: THREE.ReplaceStencilOp,
stencilZFail: THREE.ReplaceStencilOp,
stencilZPass: THREE.ReplaceStencilOp,
} );
var po = new THREE.Mesh( planeGeom, planeMat );
po.onAfterRender = function ( renderer ) {renderer.clearStencil();};
po.renderOrder = 3.1;
poGroup.add( po );
planeObjects3.push( po );
scene.add( poGroup );
});
})
var ground = new THREE.Mesh(new THREE.PlaneGeometry( 9, 9, 1, 1 ),new THREE.ShadowMaterial( { color: 0, opacity: 0.25, side: THREE.DoubleSide } ));
ground.rotation.x = - Math.PI / 2;
ground.position.y = - 1;ground.receiveShadow = true;
scene.add( ground );
stats = new Stats();
document.body.appendChild( stats.dom );
renderer = new THREE.WebGLRenderer( { antialias: true } );
renderer.shadowMap.enabled = true;
renderer.setPixelRatio( window.devicePixelRatio );
renderer.setSize( window.innerWidth, window.innerHeight );
renderer.setClearColor( 0x263238 );
window.addEventListener( 'resize', onWindowResize, false );
document.body.appendChild( renderer.domElement );
renderer.localClippingEnabled = true;
var controls = new OrbitControls( camera, renderer.domElement );controls.update();
var gui = new GUI();
var planeY = gui.addFolder( 'planeY' );
planeY.add( params.planeY, 'displayHelper' ).onChange( v => planeHelpers[ 1 ].visible = v );
planeY.add( params.planeY, 'constant' ).min( -300 ).max( 300 ).onChange( d => planes[ 0 ].constant = d );
// planeY.add( params2.planeY, 'constant' ).min( -300 ).max( 300 ).onChange( d => planes[ 0 ].constant = d );
// planeY.add( params3.planeY, 'constant' ).min( -300 ).max( 300 ).onChange( d => planes[ 0 ].constant = d );
planeY.add( params.planeY, 'negated' ).onChange( () => {planes[ 0 ].negate();params.planeY.constant = planes[ 0 ].constant;} );planeY.open();}
function onWindowResize() {
camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();
renderer.setSize( window.innerWidth, window.innerHeight );
}
function animate() {
requestAnimationFrame( animate );
for ( var i = 0; i < planeObjects.length; i ++ ) {
var plane = planes[ i ];
var po = planeObjects[ i ];
plane.coplanarPoint( po.position );
po.lookAt(po.position.x - plane.normal.x,po.position.y - plane.normal.y,po.position.z - plane.normal.z,);
}
for ( var i = 0; i < planeObjects2.length; i ++ ) {
var plane = planes[ i ];
var po = planeObjects2[ i ];
plane.coplanarPoint( po.position );
po.lookAt(po.position.x - plane.normal.x,po.position.y - plane.normal.y,po.position.z - plane.normal.z,);
}
for ( var i = 0; i < planeObjects3.length; i ++ ) {
var plane = planes[ i ];
var po = planeObjects3[ i ];
plane.coplanarPoint( po.position );
po.lookAt(po.position.x - plane.normal.x,po.position.y - plane.normal.y,po.position.z - plane.normal.z,);
}
stats.begin();
renderer.render( scene, camera );
stats.end();
}