前言
threejs实现obj模型的多面实心剖切
效果
代码
let DOM,width,height;
let animationEvent;
let center = new THREE.Vector3();
let group = new THREE.Group();
// 暂停tween.js动画
let tween;
let camera, scene, renderer, object,object2,object3, stats;
let planes, planeObjects=[],planeObjects2=[],planeObjects3=[], displayHelper;
let params = {planeX: {constant: 0,negated: false,displayHelper: false},planeY: {constant: 0,negated: false,displayHelper: false},};
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() {
DOM= document.getElementById('three1')
width = DOM.offsetWidth; //宽度
height = DOM.offsetHeight; //高度
scene = new THREE.Scene();
camera = new THREE.PerspectiveCamera( 36, width / height, 1, 100000 );
camera.position.set( 0, 0, 20 );
planes = [new THREE.Plane( new THREE.Vector3( 0,- 1, 0 ), 0 ),new THREE.Plane( new THREE.Vector3( -1,0, 0 ), 0 )];
displayHelper = planes.map( p => new THREE.PlaneHelper( p, 10, 0xffffff ) );
displayHelper.forEach( ph => {ph.visible = false; scene.add( ph );} );
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_loader.load( '/zeng/实体.mtl', function (materials ) {
materials.preload();
obj_loader.setMaterials(materials);
obj_loader.load( '/zeng/实体.obj', function (obj ) {
obj.scale.set(0.01,0.01,0.01);
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.MeshBasicMaterial({
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 );
for ( let i = 0; i < 2; i ++ ) {
var poGroup = new THREE.Group();
var plane = planes[ i ];
for (var w = 0; w < obj.children.length; w++) {
var geometry0 = object.children[0].children[w].geometry.clone();
geometry0.translate(x/0.01, y/0.01, z/0.01);
var stencilGroup = createPlaneStencilGroup(geometry0, plane, i+ 1);
stencilGroup.scale.set(0.01,0.01,0.01)
object.add(stencilGroup);
}
var planeMat =new THREE.MeshBasicMaterial( {
color: 0x3B4600,
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 = i + 1.1;
poGroup.add( po );
planeObjects2.push( po );
poGroup.scale.set(1,1,1)
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.setClearColor(0xb9d3ff, 0.1); //设置背景颜色
renderer.setPixelRatio( window.devicePixelRatio );
renderer.setSize( width, height );
window.addEventListener( 'resize', onWindowResize, false );
DOM.appendChild(renderer.domElement);
renderer.localClippingEnabled = true;
var controls = new OrbitControls( camera, renderer.domElement );controls.update();
// GUI
const gui = new GUI();
gui.add( params, 'animate' );
const planeX = gui.addFolder( 'planeX' );
planeX.add( params.planeX, 'displayHelper' ).onChange( v => displayHelper[ 0 ].visible = v );
planeX.add( params.planeX, 'constant' ).min( - 3 ).max( 3 ).onChange( d => planes[ 0 ].constant = d );
planeX.add( params.planeX, 'negated' ).onChange( () => { planes[ 0 ].negate(); params.planeX.constant = planes[ 0 ].constant; } );
planeX.open();
const planeY = gui.addFolder( 'planeY' );
planeY.add( params.planeY, 'displayHelper' ).onChange( v => displayHelper[ 1 ].visible = v );
planeY.add( params.planeY, 'constant' ).min( - 15 ).max( 15 ).onChange( d => planes[ 1 ].constant = d );
planeY.add( params.planeY, 'negated' ).onChange( () => { planes[ 1 ].negate(); params.planeY.constant = planes[ 1 ].constant; } );
planeY.open();
}
function onWindowResize() {
camera.aspect = width / height;
camera.updateProjectionMatrix();
renderer.setSize( width, height );
}
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();
}