您现在的位置是:首页 > 技术教程 正文

WEB 3D技术 three.js 包围盒

admin 阅读: 2024-03-31
后台-插件-广告管理-内容页头部广告(手机)

本文 我们来说 包围盒

如下图所示 就是一个方框 框住我们整个物体
在这里插入图片描述
它的作用 比较明显的就是 当用户点击某个物体 我们用包围盒套住 用户能够很直观的知道自己当前选中的物体是哪一个
还有就是 比如 我们物体做的比较复杂 是非常多顶点构建的 那么 我们判断它有没有和其他物体接触就很麻烦 但 有了包围盒 我们只需要判断包围盒有没有接触即可

然后 我们官网搜索 BufferGeometry
在这里插入图片描述
包围盒是所有几何体都有的属性

这里 我们有两个 一个是 包围盒 另一个是 包围圈
简单说 一个是包围成立方体 另一个是成球形包围
在这里插入图片描述
默认情况 例如我们自己创建的几何体 是不会有这个属性的 我们需要自己通过 computeBoundingBox 去计算
在这里插入图片描述
我这里 先写成这样的代码

import './style.css' import * as THREE from "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 = new THREE.PerspectiveCamera( 45, //视角 视角越大 能看到的范围就越大 window.innerWidth / window.innerHeight,//相机的宽高比 一般和画布一样大最好 0.1, 1000 ); const scene = new THREE.Scene(); const gltfLoader = new GLTFLoader(); 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 = new THREE.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 = new OrbitControls(camera, renderer.domElement); let rgbeloader = new RGBELoader(); rgbeloader.load("/xhdr/Alex_Hart-Snow_Pano_2k.hdr",(texture) =>{ scene.background = texture; texture.mapping = THREE.EquirectangularReflectionMapping; }) function animate() { controls.update(); requestAnimationFrame(animate); /*cube.rotation.x += 0.01; cube.rotation.y += 0.01;*/ renderer.render(scene, camera); } animate();
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60

这里 就是简单引入了 hdr场景贴图 和一个 glb 车的3D元素
在这里插入图片描述
那么 现在 我们要给这台车 做一个包围盒

首先 我们需要拿到它的几何体对象 先在代码中 控制台打印gltf对象下面的 scene
在这里插入图片描述
然后 下面有两个比较重要的内容 它的name 和 id
在这里插入图片描述
getObjectById 通过id获取元素对象
getObjectByName 通过name属性获取元素对象
我们肯定是用name 会更方便一点

我们的name 叫 webvrmodel_Scene
我们改写代码如下

const gltfLoader = new GLTFLoader(); 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); } )
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20

通过 getObjectByName 寻找name 为 webvrmodel_Scene的对象
然后 下面用console.log 输出在控制台上

运行结果如下
在这里插入图片描述
这里 虽然拿到了 但其实 我们也不需要这么麻烦
可以直接这样改

const gltfLoader = new GLTFLoader(); 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); } );
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19

拿到 geometry 几何体对象字段
然后 通过对象 调用 computeBoundingBox计算出 包围盒对象
然后 通过 geometry.boundingBox 获取他的包围盒对象 并在控制台打印
这里正常的几何体对象都可以调用computeBoundingBox 取 boundingBox
是因为 我们这是导入的gltf资源 所以还要想办法去拿这个几何体的对象

运行如下
在这里插入图片描述
包围盒对象 给了两个属性 max和min
两个三维向量 但是 两个形成一个包围盒 这是为什么呢?

它的两个向量 其实就是两个点的坐标
因为 他是一个很规整的立方体 包围盒 所以 它只需要如下图的两位点的位置 就可以拉出一个立方体
在这里插入图片描述
那么 既然已经拿到最小和最大两个值 那么 我们就可以拉出这样一个包围盒工具
我们可以将代码改成这样

const gltfLoader = new GLTFLoader(); 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 = new THREE.Box3Helper(geometry.boundingBox, 0xffff00); scene.add(boxHelper); } }); scene.add(gltf.scene); } );
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19

THREE.Box3Helper 需要两个参数 第一个是 需要处理的包围盒对象 就是我们从gltf几何体对象上拿到的 boundingBox属性 第二个为一个颜色属性
然后将这个包围盒对象 add到场景中

运行代码如下
在这里插入图片描述
我们外面这个包围盒的线就出来了

几何体 则更简单 我们编写代码如下

import './style.css' import * as THREE from "three"; import { OrbitControls } from "three/examples/jsm/controls/OrbitControls.js"; import { RGBELoader } from "three/examples/jsm/loaders/RGBELoader.js"; //创建相机 const camera = new THREE.PerspectiveCamera( 45, //视角 视角越大 能看到的范围就越大 window.innerWidth / window.innerHeight,//相机的宽高比 一般和画布一样大最好 0.1, 1000 ); const scene = new THREE.Scene(); let uvTexture = new THREE.TextureLoader().load("/textUv.jpg"); const geometry = new THREE.BufferGeometry(); // 创建顶点数据 const vertices = new Float32Array([ -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", new THREE.BufferAttribute(vertices, 3)); const indices = new Uint16Array([0 ,1 ,2, 0, 3, 2]); const material = new THREE.MeshBasicMaterial({ map: uvTexture, side: THREE.DoubleSide }) const uv = new Float32Array([ 0, 0, 1, 0, 1, 1, 0, 1 ]) geometry.setAttribute("uv", new THREE.BufferAttribute(uv, 2)); const normals = new Float32Array([ 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1 ]) geometry.setAttribute("normal", new THREE.BufferAttribute(normals, 3)); geometry.setIndex(new THREE.BufferAttribute(indices, 1)); console.log(geometry); const cube = new THREE.Mesh(geometry, material); scene.add(cube) //c创建一个canvas容器 并追加到 body上 const renderer = new THREE.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 = new OrbitControls(camera, renderer.domElement); let rgbeloader = new RGBELoader(); rgbeloader.load("/xhdr/Alex_Hart-Snow_Pano_2k.hdr",(texture) =>{ scene.background = texture; texture.mapping = THREE.EquirectangularReflectionMapping; material.envMap = texture; }) function animate() { controls.update(); requestAnimationFrame(animate); /*cube.rotation.x += 0.01; cube.rotation.y += 0.01;*/ renderer.render(scene, camera); } animate();
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72

在这里插入图片描述
然后添加代码

geometry.computeBoundingBox() let boxHelper = new THREE.Box3Helper(geometry.boundingBox, 0xffff00); scene.add(boxHelper);
  • 1
  • 2
  • 3

在这里插入图片描述
我们外面的包围盒就出来了
在这里插入图片描述

标签:
声明

1.本站遵循行业规范,任何转载的稿件都会明确标注作者和来源;2.本站的原创文章,请转载时务必注明文章作者和来源,不尊重原创的行为我们将追究责任;3.作者投稿可能会经我们编辑修改或补充。

在线投稿:投稿 站长QQ:1888636

后台-插件-广告管理-内容页尾部广告(手机)
关注我们

扫一扫关注我们,了解最新精彩内容

搜索