Three.js杂记(十三)—— 包围盒

news2024/11/25 20:49:01

好久没有学习three.js了,现在再重新巩固并深入学习。荒废学习一年多了,希望现在为时未晚💪

包围盒

包围盒按照字面理解就是包围一个物体的盒子,那就是一个长方形空间。

一般来说,包围盒可以用于:

  • 物体之间的碰撞检测。因为物体大多是不规则的型体,如果按照uv坐标去检测,太过耗费性能,所以直接检测两个物体包围盒是否碰撞。
  • 物体选择:通过鼠标的点击位置和包围盒来对场景中物体进行选择
  • 可视化剔除:在渲染场景时,可以根据相机的位置和视锥体来判断哪些物体在视野内,从而提高渲染性能。

下面以我导入的3D模型为例子,模型的格式为gltf

在这里插入图片描述

这是一个我从爱给网下载的3D模型,可以通过ThreeJs中的GLTFLoader加载器将此3D模型导入进项目当中。

本项目我使用的是Vue3 + Vite的模式,在main.ts中导入ThreeJs的各个需要的模块,然后设置为全局挂载。

在这里插入图片描述

具体到vue组件中,先将需要的渲染器、场景、相机等元素加载进来。根据自己的需求还可以将鼠标控件以及辅助观察的坐标轴添加到场景当中。

以下代码为基础的ThreeJs场景布置效果以及实现代码如下

  • 效果:
    在这里插入图片描述

  • 代码:

<template>
    <!-- <h1>{{ $route.query.name }}</h1> -->
    <div class="ThreeCanvas" id="canvas" ref="canvas"></div>  
</template>

<script setup lang="ts">
    import { ref, reactive, onMounted, getCurrentInstance } from "vue";
    import { setCameraPos } from "@/store";

    const { proxy } = getCurrentInstance() as any;
    const { $THREE : THREE, $OrbitControls, $GLTFLoader: GLTFLoader } = proxy;
    const scene: THREE.Scene = new THREE.Scene(); // 场景
    const camera: THREE.PerspectiveCamera = new THREE.PerspectiveCamera(105, window.innerWidth / window.innerHeight, 0.1, 1000);  //相机
    const render: THREE.WebGLRenderer = new THREE.WebGLRenderer({ antialias: true });  // 渲染器
    let canvas = ref<any>(null);
    const controls = new $OrbitControls(camera, render.domElement);  // 鼠标控件
    // AxesHelper:辅助观察的坐标系
    const axesHelper = new THREE.AxesHelper(40);
    scene.add(axesHelper);
    
    /** 后续对3D模型导入以及包围盒设置区域 
	    ......
    **/
    
    function animate() {
        controls.update(); //鼠标控制
        render.render(scene, camera);
        window.requestAnimationFrame(animate);
    }

    onMounted(()=>{ 
        let { width: canvasW, height: canvasH } = window.getComputedStyle(canvas.value);
        render.setSize(parseFloat(canvasW), parseFloat(canvasH));
        render.setClearColor('rgb(135,206,250)',1.0);
        canvas.value.appendChild(render.domElement);
        setCameraPos(camera, 0, 0, 10);
        animate();
    })
</script>
<style scoped lang="less">
</style>

3D模型导入

然后开始导入3D模型,通过GLTFLoader加载器创建一个实例。
关于引入文件,在vite中可以动态化引入资源,使用URL进行引用,参考文档链接:静态资源处理 | Vite 官方中文文档 (vitejs.cn)

PS:关于资源路径中使用了别名@,并且有中文导致中文被new URL处理后转码,无法找到资源这一问题,我查找了半天都没有找到解决方法。最后只能将路径里的中文名称修改为了英文。
let url = new URL('@/assets/img/module/shaolindashi/少林大师.gltf', import.meta.url);, 提前使用了encodeURI转换也不成功。

动态引入模型代码:

// 实例化加载器 
const gltfLoader = new GLTFLoader();
let url = new URL(`@/assets/img/module/shaolindashi/person.gltf`, import.meta.url);

gltfLoader.load(
	// 模型路径
	url.href,
	(gltf:any)=>{
		let module = gltf.scene;
		scene.add( module );
		module.name = 'shaolin';
	}
)
  • 效果:

在这里插入图片描述


包围盒计算和获取

接下来需要获取包围盒了,可以先打印查看gltfmodule,会发现并没有geometry这个属性。这是因为此3D模型是层级结构

所以接下来需要用到递归遍历方法traverse,可以递归遍历gltf所有的模型节点。

  • 代码:
// 递归遍历层级模型
module.traverse((child:any)=>{
	if (child.isMesh){
		const geometry = child.geometry;
		// 计算包围盒
		geometry.computeBoundingBox();
		// 获取包围盒
		let personBox = geometry.boundingBox;
		console.log(personBox);
	}
})

这里需要注意,在获取包围盒之前,需要先计算一次包围盒属性。方法API地址:BufferGeometry – three.js docs (threejs.org)

可以看到包围盒有maxmin两个属性,通过这两个属性可以得到3维坐标中两个点,然后得到长方形的盒子模型。
![[Vue3学习/ThreeJS 3D学习/img/p5.png]]

那现在就需要将包围盒展示在眼前了,这里使用辅助对象Box3Helper。地址:Box3Helper – three.js docs (threejs.org)

代码:

// 显示包围盒
let boxHelper = new THREE.Box3Helper(personBox, 0xff0000);
scene.add(boxHelper);

效果:

在这里插入图片描述

由此,我们就可以看到模型各块集合体的包围盒位置和大小了。


世界矩阵

但是,当你将3D模型的位置和大小改变之后,会发现生成的包围盒位置还是停留在原地,这是就需要通过世界矩阵进行处理了。在Object3D中有一个matrixWorld属性,API地址:Object3D#matrixWorld – three.js docs (threejs.org)

在这里插入图片描述

设置世界矩阵:(这里有一点,此步骤需要在模型位置和大小发生改变之后设置)

// 更新世界矩阵
child.updateWorldMatrix(true, true);
// 更新包围盒
personBox.applyMatrix4(child.matrixWorld);
// 显示包围盒
let boxHelper = new THREE.Box3Helper(personBox, 0xff0000);
scene.add(boxHelper);

当前效果:

在这里插入图片描述


几何体居中

geometry中,存在center方法,可以让几何体直接居中。但是因为我的模型是一个组,所以直接让所有geometry居中是不行的,会让模型错乱。

错乱效果:

在这里插入图片描述

这里就只需要一个包围盒,那本身模型是一个group组,所以可以自己创建一个new Box3()实例对象,接下来通过union合并方法,将内部的child包围盒计算到大盒子中。API地址:Box3#union – three.js docs (threejs.org)

实现代码

// 创建一个大盒子
let bigBox = new THREE.Box3();

// 递归遍历层级模型
module.traverse((child:any)=>{
	if (child.isMesh){
		const geometry = child.geometry;
		// 计算包围盒
		geometry.computeBoundingBox();
		// 获取包围盒
		let personBox = geometry.boundingBox;
		// 将包围盒放到大盒子中计算
		bigBox.union(personBox);
		
	}
})
console.log(bigBox);
// 显示包围盒
let boxHelper = new THREE.Box3Helper(bigBox, 0xff0000);
scene.add(boxHelper);

效果:
在这里插入图片描述

接下来可以使用getCenter方法,获取中心点地址。然后通过设置3D模型位置,调整世界矩阵,就可以让物体居中了。

// 获取大盒子中心点
let centerV3 = bigBox.getCenter(new THREE.Vector3());
console.log(centerV3);
module.position.set(-centerV3.x, -centerV3.y, -centerV3.z);
// 更新世界矩阵
module.updateWorldMatrix(true, true);
bigBox.applyMatrix4(module.matrixWorld);

在这里插入图片描述

以上就是当前关于包围盒的基础学习,当然还有碰撞等一系列东西还没学。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1632443.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Redis__数据类型

文章目录 &#x1f60a; 作者&#xff1a;Lion J &#x1f496; 主页&#xff1a; https://blog.csdn.net/weixin_69252724 &#x1f389; 主题&#xff1a;Redis__数据类型 ⏱️ 创作时间&#xff1a;2024年04月28日 ———————————————— 这里写目录标题 文…

Git零基础

Git工作流程图 操作指令 分支 、 指令总结 远程仓库

[C++] 类和对象 _ 剖析构造、析构与拷贝

一、构造函数 构造函数是特殊的成员函数&#xff0c;它在创建对象时自动调用。其主要作用是初始化对象的成员变量&#xff08;不是开辟空间&#xff09;。构造函数的名字必须与类名相同&#xff0c;且没有返回类型&#xff08;即使是void也不行&#xff09;。 在C中&#xff0…

222.完全二叉树的节点个数

题目链接 题目描述 给你一棵 完全二叉树 的根节点 root &#xff0c;求出该树的节点个数。 完全二叉树 的定义如下&#xff1a;在完全二叉树中&#xff0c;除了最底层节点可能没填满外&#xff0c;其余每层节点数都达到最大值&#xff0c;并且最下面一层的节点都集中在该层最…

vue2—— mixin 超级详细!!!

mixin Mixin是面向对象程序设计语言中的类&#xff0c;提供了方法的实现。其他类可以访问mixin类的方法而不必成为其子类 Mixin类通常作为功能模块使用&#xff0c;在需要该功能时“混入”&#xff0c;有利于代码复用又避免了多继承的复杂 vue中的mixin 先来看一下官方定义 mi…

【麒麟(Linux)系统远程连接到windows系统并进行文件传输】

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 前言使用步骤总结 前言 一般来说&#xff0c;windows自带远程桌面&#xff0c;使用的RDP协议&#xff0c;Linux上支持RDP协议的软件很多&#xff0c;常用的是Remmi…

基于决策树的DDoS攻击检测与防护系统研究---实验/论文

⚠申明&#xff1a; 未经许可&#xff0c;禁止以任何形式转载&#xff0c;若要引用&#xff0c;请标注链接地址。 全文共计3077字&#xff0c;阅读大概需要3分钟 &#x1f308;更多学习内容&#xff0c; 欢迎&#x1f44f;关注&#x1f440;【文末】我的个人微信公众号&#xf…

【前端热门框架【vue框架】】——条件渲染和列表渲染的学习的秒杀方式

&#x1f468;‍&#x1f4bb;个人主页&#xff1a;程序员-曼亿点 &#x1f468;‍&#x1f4bb; hallo 欢迎 点赞&#x1f44d; 收藏⭐ 留言&#x1f4dd; 加关注✅! &#x1f468;‍&#x1f4bb; 本文由 秩沅 原创 &#x1f468;‍&#x1f4bb; 收录于专栏&#xff1a;v…

HTTPS证书申请:相关流程及注意事项

申请HTTPS证书的过程主要包括以下几个步骤&#xff0c;以及一些需要注意的事项&#xff1a; 申请流程&#xff1a; 1. 选择证书类型和期限&#xff1a; - 根据需求选择合适的SSL证书类型&#xff0c;常见的有DV&#xff08;域名验证&#xff09;、OV&#xff08;组织验证&#…

Unity 问题之 开发应用在设备上运行闪屏花屏问题的分析处理

Unity 问题之 开发应用在设备上运行闪屏花屏问题的分析处理 目录 Unity 问题之 开发应用在设备上运行闪屏花屏问题的分析处理 一、简单介绍 二、问题现象 三、问题分析 四、使用空后处理&#xff0c;解决闪屏花屏的显示问题 五、空后处理完整代码 一、简单介绍 Unity 在…

鸿蒙开发HarmonyOS4.0入门与实践

鸿蒙开发HarmonyOS4.0 配合视频一起食用&#xff0c;效果更佳 课程地址&#xff1a;https://www.bilibili.com/video/BV1Sa4y1Z7B1/ 源码地址&#xff1a;https://gitee.com/szxio/harmonyOS4 准备工作 官网地址 鸿蒙开发者官网&#xff1a;https://developer.huawei.com/con…

使用FPGA发送一个经过曼彻斯特编码的伪随机序列

介绍 这几天突然就不知道要使用FPGA实现什么样的功能了,然后就跑去学习数电了,学的也是晕晕的。正好之前写了一个使用FPGA发送伪随机序列的代码,然后因为需要使用曼彻斯特编码,所以又加了一个模块吧,使得最后输出的波形经过曼彻斯特编码。 曼彻斯特编码 首先,曼彻斯特编…

【操作系统复习资料】(持续更新中)

目录 第一章&#xff1a;操作系统引论 第二章&#xff1a;进程的描述与控制 未完待续。。。。。接 第三章&#xff1a;处理机调度与死锁 第四章&#xff1a;存储器管理 第五章&#xff1a;虚拟存储器 第六章&#xff1a;第八节 磁盘存储器的性能和调度 第一章&#xff1a…

pgvector扩展在IvorySQL Oracle兼容模式下的应用实践

向量数据库是生成式人工智能(GenAI)的关键组成部分。作为PostgreSQL的重要扩展&#xff0c;pgvector支持高达16000维的向量计算能力&#xff0c;使得PostgreSQL能够直接转化为高效的向量数据库。 IvorySQL基于PostgreSQL开发&#xff0c;因此它同样支持添加pgvector扩展。在Ora…

社交媒体数据恢复:新浪微博

当我们在使用新浪微博时&#xff0c;可能会遇到一些意外情况&#xff0c;如误删微博、账号出现问题等。这时&#xff0c;我们需要进行数据恢复。本文将详细介绍如何在新浪微博中进行数据恢复。 首先&#xff0c;我们需要了解新浪微博的数据恢复功能。根据微博的帮助中心&#…

实验8 顺序图、状态图

一、实验目的 通过绘制顺序图、状态图&#xff0c;掌握顺序图、状态图之间的基本原理和差异。 能对简单问题进行顺序图、状态图的分析与绘制。 二、实验项目内容&#xff08;实验题目&#xff09; 在图书信息管理系统中&#xff0c;系统管理员可以对图书信息进行管理和维护…

Python轻量级Web框架Flask(12)—— Flask类视图实现前后端分离

0、前言&#xff1a; 在学习类视图之前要了解前后端分离的概念&#xff0c;相对于之前的模板&#xff0c;前后端分离的模板会去除views文件&#xff0c;添加两个新python文件apis和urls&#xff0c;其中apis是用于传输数据和解析数据 的&#xff0c;urls是用于写模板路径的。 …

merge and rebase

文章目录 什么是merge什么是rebasemerge和rebase的区别操作执行git merge操作git rebase操作冲突解决解决冲突的步骤 Git Merge 和 Git Rebase 都是用于集成来自不同分支的修改的 Git 命令。 什么是merge Git Merge 是将一个分支的改动合并到另一个分支的方式。当你执行一个 m…

Unity 物体触碰事件监听

声明委托 public delegate void MyDelegate(Collider trigger); C# 委托&#xff08;Delegate&#xff09; | 菜鸟教程 (runoob.com)https://www.runoob.com/csharp/csharp-delegate.html 定义委托 public MyDelegate onTriggerEnter; public MyDelegate onTriggerStay; pu…

Leetcode—1041. 困于环中的机器人【中等】

2024每日刷题&#xff08;121&#xff09; Leetcode—1041. 困于环中的机器人 实现代码 class Solution { public:bool isRobotBounded(string instructions) {int x 0;int y 0;int d 0;vector<vector<int>> direction{{0, 1}, {1, 0}, {0, -1}, {-1, 0}};for…