本文 我们来说 包围盒
如下图所示 就是一个方框 框住我们整个物体
它的作用 比较明显的就是 当用户点击某个物体 我们用包围盒套住 用户能够很直观的知道自己当前选中的物体是哪一个
还有就是 比如 我们物体做的比较复杂 是非常多顶点构建的 那么 我们判断它有没有和其他物体接触就很麻烦 但 有了包围盒 我们只需要判断包围盒有没有接触即可
然后 我们官网搜索 BufferGeometry
包围盒是所有几何体都有的属性
这里 我们有两个 一个是 包围盒 另一个是 包围圈
简单说 一个是包围成立方体 另一个是成球形包围
默认情况 例如我们自己创建的几何体 是不会有这个属性的 我们需要自己通过 computeBoundingBox 去计算
我这里 先写成这样的代码
import'./style.css'import*asTHREEfrom"three";import{ OrbitControls }from"three/examples/jsm/controls/OrbitControls.js";import{ RGBELoader }from"three/examples/jsm/loaders/RGBELoader.js";import{ GLTFLoader }from"three/examples/jsm/loaders/GLTFLoader.js";//创建相机const camera =newTHREE.PerspectiveCamera(45,//视角 视角越大 能看到的范围就越大
window.innerWidth / window.innerHeight,//相机的宽高比 一般和画布一样大最好0.1,1000);const scene =newTHREE.Scene();const gltfLoader =newGLTFLoader();
gltfLoader.load(// 模型路径"/gltf/scene.gltf",// 加较完成同调(gltf)=>{
gltf.scene.traverse((child)=>{if(child.isMesh){
child.frustumCulled =false;
child.castShadow =true;
child.material.emissive = child.material.color;
child.material.emissiveMap = child.material.map;}});
scene.add(gltf.scene);})//c创建一个canvas容器 并追加到 body上const renderer =newTHREE.WebGLRenderer(0);
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);//设置相机位置 这里 我们设置Z轴 大家可以试试 S Y 和 Z 都是可以的
camera.position.z =5;//设置相机默认看向哪里 三个 0 代表 默认看向原点
camera.lookAt(0,0,0);//将内容渲染到元素上
renderer.render(scene, camera);const controls =newOrbitControls(camera, renderer.domElement);let rgbeloader =newRGBELoader();
rgbeloader.load("/xhdr/Alex_Hart-Snow_Pano_2k.hdr",(texture)=>{
scene.background = texture;
texture.mapping =THREE.EquirectangularReflectionMapping;})functionanimate(){
controls.update();requestAnimationFrame(animate);/*cube.rotation.x += 0.01;
cube.rotation.y += 0.01;*/
renderer.render(scene, camera);}animate();
这里 就是简单引入了 hdr场景贴图 和一个 glb 车的3D元素
那么 现在 我们要给这台车 做一个包围盒
首先 我们需要拿到它的几何体对象 先在代码中 控制台打印gltf对象下面的 scene
然后 下面有两个比较重要的内容 它的name 和 id
getObjectById 通过id获取元素对象
getObjectByName 通过name属性获取元素对象
我们肯定是用name 会更方便一点
我们的name 叫 webvrmodel_Scene
我们改写代码如下
const gltfLoader =newGLTFLoader();
gltfLoader.load(// 模型路径"/gltf/scene.gltf",// 加较完成同调(gltf)=>{
gltf.scene.traverse((child)=>{if(child.isMesh){
child.frustumCulled =false;
child.castShadow =true;
child.material.emissive = child.material.color;
child.material.emissiveMap = child.material.map;}});
scene.add(gltf.scene);let webvrmodel = gltf.scene.getObjectByName("webvrmodel_Scene");
console.log(webvrmodel);})
通过 getObjectByName 寻找name 为 webvrmodel_Scene的对象
然后 下面用console.log 输出在控制台上
运行结果如下
这里 虽然拿到了 但其实 我们也不需要这么麻烦
可以直接这样改
const gltfLoader =newGLTFLoader();
gltfLoader.load("/gltf/scene.gltf",(gltf)=>{
gltf.scene.traverse((child)=>{if(child.isMesh){
child.frustumCulled =false;
child.castShadow =true;
child.material.emissive = child.material.color;
child.material.emissiveMap = child.material.map;const geometry = child.geometry;
geometry.computeBoundingBox()let duckBox = geometry.boundingBox;
console.log(duckBox);}});
scene.add(gltf.scene);});
拿到 geometry 几何体对象字段
然后 通过对象 调用 computeBoundingBox计算出 包围盒对象
然后 通过 geometry.boundingBox 获取他的包围盒对象 并在控制台打印
这里正常的几何体对象都可以调用computeBoundingBox 取 boundingBox
是因为 我们这是导入的gltf资源 所以还要想办法去拿这个几何体的对象
运行如下
包围盒对象 给了两个属性 max和min
两个三维向量 但是 两个形成一个包围盒 这是为什么呢?
它的两个向量 其实就是两个点的坐标
因为 他是一个很规整的立方体 包围盒 所以 它只需要如下图的两位点的位置 就可以拉出一个立方体
那么 既然已经拿到最小和最大两个值 那么 我们就可以拉出这样一个包围盒工具
我们可以将代码改成这样
const gltfLoader =newGLTFLoader();
gltfLoader.load("/gltf/scene.gltf",(gltf)=>{
gltf.scene.traverse((child)=>{if(child.isMesh){
child.frustumCulled =false;
child.castShadow =true;
child.material.emissive = child.material.color;
child.material.emissiveMap = child.material.map;const geometry = child.geometry;
geometry.computeBoundingBox()let boxHelper =newTHREE.Box3Helper(geometry.boundingBox,0xffff00);
scene.add(boxHelper);}});
scene.add(gltf.scene);});
THREE.Box3Helper 需要两个参数 第一个是 需要处理的包围盒对象 就是我们从gltf几何体对象上拿到的 boundingBox属性 第二个为一个颜色属性
然后将这个包围盒对象 add到场景中
运行代码如下
我们外面这个包围盒的线就出来了
几何体 则更简单 我们编写代码如下
import'./style.css'import*asTHREEfrom"three";import{ OrbitControls }from"three/examples/jsm/controls/OrbitControls.js";import{ RGBELoader }from"three/examples/jsm/loaders/RGBELoader.js";//创建相机const camera =newTHREE.PerspectiveCamera(45,//视角 视角越大 能看到的范围就越大
window.innerWidth / window.innerHeight,//相机的宽高比 一般和画布一样大最好0.1,1000);const scene =newTHREE.Scene();let uvTexture =newTHREE.TextureLoader().load("/textUv.jpg");const geometry =newTHREE.BufferGeometry();// 创建顶点数据const vertices =newFloat32Array([-1.0,-1.0,0.0,1.0,-1.0,0.0,1.0,1.0,0.0,-1.0,1.0,0.0])
geometry.setAttribute("position",newTHREE.BufferAttribute(vertices,3));const indices =newUint16Array([0,1,2,0,3,2]);const material =newTHREE.MeshBasicMaterial({map: uvTexture,side:THREE.DoubleSide
})const uv =newFloat32Array([0,0,1,0,1,1,0,1])
geometry.setAttribute("uv",newTHREE.BufferAttribute(uv,2));const normals =newFloat32Array([0,0,1,0,0,1,0,0,1,0,0,1])
geometry.setAttribute("normal",newTHREE.BufferAttribute(normals,3));
geometry.setIndex(newTHREE.BufferAttribute(indices,1));
console.log(geometry);const cube =newTHREE.Mesh(geometry, material);
scene.add(cube)//c创建一个canvas容器 并追加到 body上const renderer =newTHREE.WebGLRenderer(0);
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);//设置相机位置 这里 我们设置Z轴 大家可以试试 S Y 和 Z 都是可以的
camera.position.z =5;//设置相机默认看向哪里 三个 0 代表 默认看向原点
camera.lookAt(0,0,0);//将内容渲染到元素上
renderer.render(scene, camera);const controls =newOrbitControls(camera, renderer.domElement);let rgbeloader =newRGBELoader();
rgbeloader.load("/xhdr/Alex_Hart-Snow_Pano_2k.hdr",(texture)=>{
scene.background = texture;
texture.mapping =THREE.EquirectangularReflectionMapping;
material.envMap = texture;})functionanimate(){
controls.update();requestAnimationFrame(animate);/*cube.rotation.x += 0.01;
cube.rotation.y += 0.01;*/
renderer.render(scene, camera);}animate();
然后添加代码
geometry.computeBoundingBox()let boxHelper =newTHREE.Box3Helper(geometry.boundingBox,0xffff00);
scene.add(boxHelper);
我们外面的包围盒就出来了
版权归原作者 瑞晟技术服务中心-耿瑞 所有, 如有侵权,请联系我们删除。