WEB 3D技术 three.js 包围盒

作者 : admin 本文共5600个字,预计阅读时间需要14分钟 发布时间: 2024-01-6 共1人阅读

本文 我们来说 包围盒

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

然后 我们官网搜索 BufferGeometry
WEB 3D技术 three.js 包围盒插图(1)
包围盒是所有几何体都有的属性

这里 我们有两个 一个是 包围盒 另一个是 包围圈
简单说 一个是包围成立方体 另一个是成球形包围
WEB 3D技术 three.js 包围盒插图(2)
默认情况 例如我们自己创建的几何体 是不会有这个属性的 我们需要自己通过 computeBoundingBox 去计算
WEB 3D技术 three.js 包围盒插图(3)
我这里 先写成这样的代码

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();

这里 就是简单引入了 hdr场景贴图 和一个 glb 车的3D元素
WEB 3D技术 three.js 包围盒插图(4)
那么 现在 我们要给这台车 做一个包围盒

首先 我们需要拿到它的几何体对象 先在代码中 控制台打印gltf对象下面的 scene
WEB 3D技术 three.js 包围盒插图(5)
然后 下面有两个比较重要的内容 它的name 和 id
WEB 3D技术 three.js 包围盒插图(6)
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);
}
)

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

运行结果如下
WEB 3D技术 three.js 包围盒插图(7)
这里 虽然拿到了 但其实 我们也不需要这么麻烦
可以直接这样改

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);
}
);

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

运行如下
WEB 3D技术 three.js 包围盒插图(8)
包围盒对象 给了两个属性 max和min
两个三维向量 但是 两个形成一个包围盒 这是为什么呢?

它的两个向量 其实就是两个点的坐标
因为 他是一个很规整的立方体 包围盒 所以 它只需要如下图的两位点的位置 就可以拉出一个立方体
WEB 3D技术 three.js 包围盒插图(9)
那么 既然已经拿到最小和最大两个值 那么 我们就可以拉出这样一个包围盒工具
我们可以将代码改成这样

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);
}
);

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

运行代码如下
WEB 3D技术 three.js 包围盒插图(10)
我们外面这个包围盒的线就出来了

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

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();

WEB 3D技术 three.js 包围盒插图(11)
然后添加代码

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

WEB 3D技术 three.js 包围盒插图(12)
我们外面的包围盒就出来了
WEB 3D技术 three.js 包围盒插图(13)

本站无任何商业行为
个人在线分享 » WEB 3D技术 three.js 包围盒
E-->