Three.js进行模型剖切,剖切面颜色可控。
用three.js自带的.clippingPlanes可以对模型进行剖切,通过GUI可以控制剖切面的移动。为了看到剖切面,一般使用THREE.Plane制作一个可视化平面。这里由于我们需要对剖切面进行贴纹理之类的操作,于是放弃了使用Plane,选择自己画一个BufferGeometry,使其跟随剖切面移动,并且将顶点颜色通过剖切面所在高度来确定,最后通过插值获得渐变的颜色。为了方便,中间被剖切的模型只画了一个平面。
代码可能有些乱,没整理也没注释,凑合看,准备放到项目中再优化。
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>cloudchart</title> <script src="../build/three.js"></script> <script src="../examples/js/controls/OrbitControls.js"></script> <script src="../examples/js/libs/dat.gui.min.js"></script> </head> <body> <script type="module"> // import * as THREE from "/build/Three" // import { OrbitControls } from "/examples/js/controls/Orbitcontrols" let scene = new THREE.Scene(); let camera = new THREE.PerspectiveCamera(60, window.innerWidth / window.innerHeight, 1, 1000); camera.position.set(100, 100, 100); camera.lookAt(scene.position); let pointLight = new THREE.PointLight(0xffffff); pointLight.position.set(100, 100, 100); scene.add(pointLight); let ambientLight = new THREE.AmbientLight(0x444444); scene.add(ambientLight); let geometry0 = new THREE.BufferGeometry(); let geometry1 = new THREE.BufferGeometry(); let vertices0 = new Float32Array([ 25, 25, 0, 25, -25, 0, -25, -25, 0, 25, 25, 0, -25, -25, 0, -25, 25, 0, ]); let vertices1 = new Float32Array([ 50, 0, 50, -50, 0, 50, -50, 0, -50, 50, 0, 50, -50, 0, -50, 50, 0, -50, ]); geometry0.setAttribute("position", new THREE.BufferAttribute(vertices0, 3)); geometry1.setAttribute("position", new THREE.BufferAttribute(vertices1, 3)); let colors0 = new Float32Array([ 0.3, 0.3, 0.3, Math.random(), Math.random(), Math.random(), 0.7, 0.7, 0.7, 0.3, 0.3, 0.3, 0.7, 0.7, 0.7, Math.random(), Math.random(), Math.random(), ]); const colors1 = (parms) => { return (new Float32Array([ 0.3, 0.3, 0.3, Math.random() * parms / 50, Math.random() * parms / 50, Math.random() * parms / 50, 0.7, 0.7, 0.7, 0.3, 0.3, 0.3, 0.7, 0.7, 0.7, Math.random() * parms / 50, Math.random() * parms / 50, Math.random() * parms / 50, ])) } geometry0.attributes.color = new THREE.BufferAttribute(colors0, 3); geometry1.attributes.color = new THREE.BufferAttribute(colors1(0), 3); let params = { planeY: { constant: 0 } }; let planes = [new THREE.Plane(new THREE.Vector3(0, 1, 0), 0)]; console.log(params); let material0 = new THREE.MeshBasicMaterial({ vertexColors: THREE.VertexColors, side: THREE.DoubleSide, clippingPlanes: planes, clipIntersection: true }); let material1 = new THREE.MeshBasicMaterial({ vertexColors: THREE.VertexColors, side: THREE.DoubleSide, }) let mesh0 = new THREE.Mesh(geometry0, material0); let mesh1 = new THREE.Mesh(geometry1, material1); // console.log('diatance', planes[0].constant); // mesh1.position.y = data1; // console.log('data1', data1); // console.log('y', mesh1.position.y); scene.add(mesh0); scene.add(mesh1); let axesHelper = new THREE.AxesHelper(100); scene.add(axesHelper); let renderer = new THREE.WebGLRenderer(); renderer.setSize(window.innerWidth, window.innerHeight); renderer.setClearColor(0x000000); document.body.appendChild(renderer.domElement); let gui = new dat.GUI(); gui.add(params.planeY, 'constant').min(-50).max(50).onChange( (parms) => { planes[0].constant = -parms; mesh1.position.y = parms; geometry1.attributes.color = new THREE.BufferAttribute(colors1(parms), 3); } ); // let helper = new THREE.PlaneHelper(planes[0], 100, 0x323fff); // scene.add(helper); // renderer.clippingPlanes = planes; renderer.localClippingEnabled = true; function animate() { renderer.render(scene, camera); requestAnimationFrame(animate); } animate(); function createControls() { } let controls = new THREE.OrbitControls(camera, renderer.domElement); // controls.addEventListener("change", render); </script> </body> </html>