本文转载自csdn的暮志未晚Webgl博主的内容,并在文末对npm下安装threebsp进行了补充:
简介
之前我们一直使用Three.js默认提供的几何体,今天我们使用ThreeBSP库,可以将现有的模型组合出更多个性的模型来使用。我们可以使用ThreeBSP库里面的三个函数进行现有模型的组合,分别是:差集(相减)、并集(组合、相加)、交集(两几何体重合的部分)。下面我们介绍一下三个函数,并提供每个方法的简单案例。
相关函数
名称 | 描述 |
---|---|
intersect(交集) | 使用该函数可以基于两个现有几何体的重合的部分定义此几何体的形状。 |
union(并集) | 使用该函数可以将两个几何体联合起来创建出一个新的几何体。 |
subtract(差集) | 使用该函数可以在第一个几何体中移除两个几何体重叠的部分来创建新的几何体。 |
使用intersect(交集)创建新几何体
首先,需要先把库文件引入(此版本适用于 threejs 123版本)
<script src="http://cdn.5imoban.net/threejs/ThreeBSP/ThreeBSP-v1.6.3.js"></script>
然后创建两个几何体,一个球形sphere一个立方体cube。
//创建球形几何体 var sphereGeometry = new THREE.SphereGeometry(50, 20, 20); var sphere = createMesh(sphereGeometry); //创建立方体几何体 var cubeGeometry = new THREE.BoxGeometry(30, 30, 30); var cube = createMesh(cubeGeometry); cube.position.x = -50; scene.add(sphere); scene.add(cube);
两个立方体的效果就是这样,有一部分重叠。
我们就创建出重叠的这一部分的图形,具体代码是这样的
//创建球形几何体 var sphereGeometry = new THREE.SphereGeometry(50, 20, 20); var sphere = createMesh(sphereGeometry); //创建立方体几何体 var cubeGeometry = new THREE.BoxGeometry(30, 30, 30); var cube = createMesh(cubeGeometry); cube.position.x = -50; //生成ThreeBSP对象 var sphereBSP = new ThreeBSP(sphere); var cubeBSP = new ThreeBSP(cube); //进行并集计算 var resultBSP = sphereBSP.intersect(cubeBSP); //从BSP对象内获取到处理完后的mesh模型数据 var result = resultBSP.toMesh(); //更新模型的面和顶点的数据 result.geometry.computeFaceNormals(); result.geometry.computeVertexNormals(); //重新赋值一个纹理 var material = new THREE.MeshPhongMaterial({color: 0x00ffff}); result.material = material; //将计算出来模型添加到场景当中 scene.add(result);
按上面的步骤,我们就可以获得交集的模型了。
使用union(并集)创建新几何体
代码和上面交集的方法一样的,只是改成了并集计算
var resultBSP = sphereBSP.union(cubeBSP);
就实现了如下的效果。
使用subtract(差集)创建新几何体
如上,直接把调用方法改掉即可
var resultBSP = sphereBSP.subtract(cubeBSP);
以下是整个项目的代码
<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>Title</title> <style type="text/css"> html, body { margin: 0; height: 100%; } canvas { display: block; } </style> </head> <body onload="draw();"> </body> <script src="https://johnson2heng.github.io/three.js-demo/lib/three.js"></script> <script src="https://johnson2heng.github.io/three.js-demo/lib/threebsp.js"></script> <script src="https://johnson2heng.github.io/three.js-demo/lib/js/controls/OrbitControls.js"></script> <script src="https://johnson2heng.github.io/three.js-demo/lib/js/libs/stats.min.js"></script> <script src="https://johnson2heng.github.io/three.js-demo/lib/js/libs/dat.gui.min.js"></script> <script> var renderer; function initRender() { renderer = new THREE.WebGLRenderer({antialias: true}); //renderer.setClearColor(new THREE.Color(0xEEEEEE, 1.0)); //设置背景颜色 renderer.setSize(window.innerWidth, window.innerHeight); document.body.appendChild(renderer.domElement); } var camera; function initCamera() { camera = new THREE.PerspectiveCamera(45, window.innerWidth / window.innerHeight, 1, 10000); camera.position.set(0, 200, 500); } var scene; function initScene() { scene = new THREE.Scene(); } var light; function initLight() { scene.add(new THREE.AmbientLight(0x404040)); light = new THREE.DirectionalLight(0xffffff); light.position.set(1, 1, 1); scene.add(light); } function initModel() { //轴辅助 (每一个轴的长度) var object = new THREE.AxesHelper(500); scene.add(object); //创建球形几何体 var sphereGeometry = new THREE.SphereGeometry(50, 20, 20); var sphere = createMesh(sphereGeometry); //创建立方体几何体 var cubeGeometry = new THREE.BoxGeometry(30, 30, 30); var cube = createMesh(cubeGeometry); cube.position.x = -50; //生成ThreeBSP对象 var sphereBSP = new ThreeBSP(sphere); var cubeBSP = new ThreeBSP(cube); //进行并集计算 var resultBSP = sphereBSP.subtract(cubeBSP); //从BSP对象内获取到处理完后的mesh模型数据 var result = resultBSP.toMesh(); //更新模型的面和顶点的数据 result.geometry.computeFaceNormals(); result.geometry.computeVertexNormals(); //重新赋值一个纹理 var material = new THREE.MeshPhongMaterial({color: 0x00ffff}); result.material = material; //将计算出来模型添加到场景当中 scene.add(sphere); scene.add(cube); scene.add(result); } //生成模型 function createMesh(geom) { //设置当前的模型矩阵沿xy轴偏移,让图片处于显示中心 //geom.applyMatrix(new THREE.Matrix4().makeTranslation(-250, -100, 0)); // 创建法向量纹理 var meshMaterial = new THREE.MeshNormalMaterial({ flatShading: THREE.FlatShading, transparent: true, opacity: 0.9 }); // 创建一个线框纹理 var wireFrameMat = new THREE.MeshBasicMaterial({opacity: 0.5, wireframeLinewidth: 0.5}); wireFrameMat.wireframe = true; // 创建模型 var mesh = new THREE.Mesh(geom, wireFrameMat); return mesh; } //初始化性能插件 var stats; function initStats() { stats = new Stats(); document.body.appendChild(stats.dom); } //用户交互插件 鼠标左键按住旋转,右键按住平移,滚轮缩放 var controls; function initControls() { controls = new THREE.OrbitControls(camera, renderer.domElement); // 如果使用animate方法时,将此函数删除 //controls.addEventListener( 'change', render ); // 使动画循环使用时阻尼或自转 意思是否有惯性 controls.enableDamping = true; //动态阻尼系数 就是鼠标拖拽旋转灵敏度 //controls.dampingFactor = 0.25; //是否可以缩放 controls.enableZoom = true; //是否自动旋转 controls.autoRotate = false; //设置相机距离原点的最远距离 controls.minDistance = 20; //设置相机距离原点的最远距离 controls.maxDistance = 10000; //是否开启右键拖拽 controls.enablePan = true; } //生成gui设置配置项 var gui; function initGui() { //声明一个保存需求修改的相关数据的对象 gui = { }; var datGui = new dat.GUI(); //将设置属性添加到gui当中,gui.add(对象,属性,最小值,最大值) } function render() { renderer.render(scene, camera); } //窗口变动触发的函数 function onWindowResize() { camera.aspect = window.innerWidth / window.innerHeight; camera.updateProjectionMatrix(); render(); renderer.setSize(window.innerWidth, window.innerHeight); } function animate() { //更新控制器 controls.update(); render(); //更新性能插件 stats.update(); requestAnimationFrame(animate); } function draw() { initRender(); initScene(); initCamera(); initLight(); initModel(); initControls(); initStats(); initGui(); animate(); window.onresize = onWindowResize; } </script> </html>
注:
如果使用的是npm形式安装的threejs,如:
npm install three@0.123.0 --save
则不能使用上面的引入方式,可以用npm来安装ThreeBSP:
npm i --save three-js-csg
引入ThreeBSP方法:
import * as THREE from 'three' const ThreeBSP = require('three-js-csg')(THREE)
使用方法同上