【rust/bevy】使用points构造ConvexMesh
目录
- 说在前面
- 问题提出
- Rapier
- 具体实现
- 参考
说在前面
- 操作系统:win11
- rust版本:rustc 1.77.0-nightly
- bevy版本:0.12
- github:这里
问题提出
-
在
three.js中,可以通过使用ConvexGeometry从给定的三维点集合生成凸包(Convex Hull)import { ConvexGeometry } from 'three/addons/geometries/ConvexGeometry.js';例如:
const geometry = new ConvexGeometry( points ); const material = new THREE.MeshBasicMaterial( { color: 0x00ff00 } ); const mesh = new THREE.Mesh( geometry, material ); scene.add( mesh );
-
但是在
bevy中如何实现呢?
Rapier
- 在当前
bevy的版本中,并没有类似的实现,目前支持的shape也比three.js少:- Box
- Capsule
- Circle
- Cube
- Cylinder
- Icosphere
- Plane
- Quad
- RegularPolygon
- Torus
- UVSphere
- 所以,如果要构造
ConvexHull,只能借助第三方库(或者自己实现,可以参考three.js实现) - 这里我们借助一个物理库
rapier来实现 - 关于rapier
这里
具体实现
-
首先我们通过点集构造
ConvexHull,rapier可以直接完成这一步:let collider = Collider::convex_hull(&points);但是该方法构造的是一个
Collider,实际上是无法直接当成Mesh使用的 -
然后我们将其转换成
ConvexPolyhedronlet convex = c.as_convex_polyhedron().unwrap(); -
该结构中包含一个凸包的所有属性,例如点、边、面等,事实上,它提供了一个方法,能够直接转换成TriangleMesh所需要的数据:
impl ConvexPolyhedron {/// Discretize the boundary of this convex polyhedron as a triangle-mesh.pub fn to_trimesh(&self) -> (Vec<Point3<Real>>, Vec<[u32; 3]>) {let mut indices = Vec::new();for face in self.faces() {let i1 = face.first_vertex_or_edge;let i2 = i1 + face.num_vertices_or_edges;let first_id = self.vertices_adj_to_face()[i1 as usize] as u32;for idx in self.vertices_adj_to_face()[i1 as usize + 1..i2 as usize].windows(2) {indices.push([first_id, idx[0] as u32, idx[1] as u32]);}}(self.points().to_vec(), indices)} }但是不包含
normal数据,导致光照对其没有作用

-
所以我们需要自己实现一个相似的方法,首先我们来看看测试数据,实际上它有20个点,共12个面,每个面是一个正五边形,所以使用TriangleMesh来表达的话,一共是36个三角形
-
再让我们来看看
bevy中构造一个TriangleMesh需要哪些数据:fn create_simple_parallelogram() -> Mesh {// Create a new mesh using a triangle list topology, where each set of 3 vertices composes a triangle.Mesh::new(PrimitiveTopology::TriangleList)// 顶点数据.with_inserted_attribute(Mesh::ATTRIBUTE_POSITION,vec![[0.0, 0.0, 0.0], [1.0, 2.0, 0.0], [2.0, 2.0, 0.0], [1.0, 0.0, 0.0]])// uv数据 在本文中我们并不需要.with_inserted_attribute(Mesh::ATTRIBUTE_UV_0,vec![[0.0, 1.0], [0.5, 0.0], [1.0, 0.0], [0.5, 1.0]])// 法线.with_inserted_attribute(Mesh::ATTRIBUTE_NORMAL,vec![[0.0, 0.0, 1.0], [0.0, 0.0, 1.0], [0.0, 0.0, 1.0], [0.0, 0.0, 1.0]])// 三角形的顶点索引.with_indices(Some(Indices::U32(vec![0, 3, 1,1, 3, 2]))) } -
对比我们需要的数据,以及
to_trimesh方法,发现我们少了normal数据,不过这个数据在face中就有,那么所有条件就具备了 -
完整代码
let plist: Vec<f32> = vec![0., 3.568220853805542, 9.341723442077637, 5.773502826690674, 5.773502826690674, 5.773502826690674, -5.773502826690674, 5.773502826690674, 5.773502826690674, 3.568220853805542, 9.341723442077637, 0., -3.568220853805542, 9.341723442077637, 0., 9.341723442077637, 0., 3.568220853805542, 9.341723442077637, 0., -3.568220853805542, 5.773502826690674, 5.773502826690674, -5.773502826690674, 5.773502826690674, -5.773502826690674, -5.773502826690674, 0., -3.568220853805542, -9.341723442077637, 0., 3.568220853805542, -9.341723442077637, -5.773502826690674, -5.773502826690674, -5.773502826690674, -9.341723442077637, 0., -3.568220853805542, -5.773502826690674, 5.773502826690674, -5.773502826690674, -3.568220853805542, -9.341723442077637, 0., -5.773502826690674, -5.773502826690674, 5.773502826690674, -9.341723442077637, 0., 3.568220853805542, 0., -3.568220853805542, 9.341723442077637, 3.568220853805542, -9.341723442077637, 0., 5.773502826690674, -5.773502826690674, 5.773502826690674]; let points: Vec<Vec3> = plist.array_chunks().into_iter().map(|&v: &[f32; 3]| Vec3::from_array(v)).collect(); // 通过点集构造convex hull let collider = Collider::convex_hull(&points); if let Some(c) = collider {let convex = c.as_convex_polyhedron().unwrap();// 取convex hull的所有面let faces = convex.raw.faces();// 取点集let points = convex.raw.points();// 取映射关系let face_to_vertices = convex.raw.vertices_adj_to_face();let mut positions = Vec::new();// 法向量 用于处理光照let mut normals = Vec::new();let mut indices = Vec::new();// 遍历所有的面for face in faces {let i1 = face.first_vertex_or_edge;let i2 = i1 + face.num_vertices_or_edges;for idx in i1..i2 {let point = points[face_to_vertices[idx as usize] as usize];// 重新构造点集 points是原始点集positions.push([point.x, point.y, point.z]);// 面上的所有点的朝向与面相同normals.push([face.normal.x, face.normal.y, face.normal.z]);}for idx in i1 + 1..i2 - 1 {// 构造顶点索引indices.push([i1, idx as u32, idx + 1 as u32]);}}// 构造Meshlet mesh = Mesh::new(PrimitiveTopology::TriangleList).with_inserted_attribute(Mesh::ATTRIBUTE_POSITION, positions).with_inserted_attribute(Mesh::ATTRIBUTE_NORMAL, normals).with_indices(Some(Indices::U32(indices.concat())));commands.spawn(PbrBundle {mesh: meshes.add(mesh),material: materials.add(Color::rgb_u8(124, 144, 255).into()),transform: Transform::from_xyz(0.0, 1., 0.0).with_scale(Vec3::new(0.1, 0.1, 0.1)),..default()}); } -
结果(gif)

参考
- ConvexGeometry
相关文章:
【rust/bevy】使用points构造ConvexMesh
目录 说在前面问题提出Rapier具体实现参考 说在前面 操作系统:win11rust版本:rustc 1.77.0-nightlybevy版本:0.12github:这里 问题提出 在three.js中,可以通过使用ConvexGeometry从给定的三维点集合生成凸包(Convex Hu…...
【C语言】string.h——主要函数总结
string.h主要定义了字符串处理函数和内存操作函数。 字符串处理函数 strlen() 功能:strlen()函数返回字符串的字节长度,不包括末尾的空字符\0。 函数原型:size_t strlen(const char* s); 返回值:返回的是size_t类型的无符号整…...
如何在前端优化中减少页面加载时间?
在前端优化中,减少页面加载时间是至关重要的,因为快速加载的页面可以提高用户体验,减少跳出率,从而提升网站的整体性能。本文将介绍一些实用的前端优化技巧,以帮助您减少页面加载时间。 一、优化图片 图片是页面加载…...
Typecho后台无法登录显示503 service unavailable问题及处理
一、Typecho 我的博客地址:https://www.aomanhao.top 使用老薛主机动态Typecho博客框架handsome主题的搭配,文章内容可以异地网页更新,可以听后台背景音乐,很好的满足我的痛点需求,博客部署在云端服务器访问响应较快…...
Python入门(一)
anaconda安装 官网:https://www.anaconda.com下载 jupyter lab 简介: 包含了Jupyter Notebook所有功能。 JupyterLab作为一种基于web的集成开发环境,你可以使用它编写notebook,操作终端,编辑markdown文本…...
云表企业级无代码案例-自主开发ERP管理系统
痛点 我是一名企业经营者,同时也是信息化建设的坚定倡导者。凭借管理专业背景,我深知经营数据对于企业的至关重要性。如何高效搜集、精准分析经营数据,并将其转化为决策依据,直接关乎企业的生死存亡。太多因盲目决策而倒闭的企业…...
Qt —— 编译Qt5版本QFTP库,并实现连接服务、获取列表、上传、下载、删除文件等操作(附源码、附基于Qt5编译好的QFTP库)
示例效果1 示例效果2 介绍 QFTP是Qt4的库,Qt5改用了QNetworkAccessManager来代替。但是Qt5提供的QNetworkAccessManager仅支持FTP的上传和下载,所以只能将QFTP库编译为Qt5的库来进行调用。 QFTP在Github的下载地址:https://github.com/qt/qtftp 客户端源码生成的release结果…...
碰到es6的...拓展运算符
第一次碰到,哥们啥也不会 let searchForm ref({}) let formData ref({}) const initArgs async() > { args.value props.init_data formData .value { ...searchForm.value,//把值都带过来 workWhere : args.value.workWhere, statusArgs : args.value.sta…...
JDK8新特性详解
☆* o(≧▽≦)o *☆嗨~我是小奥🍹 📄📄📄个人博客:小奥的博客 📄📄📄CSDN:个人CSDN 📙📙📙Github:传送门 📅&a…...
ELK+Filebeat 部署实验
Filebeat是轻量级的开源日志文件数据搜集器。通常在需要采集数据的客户端安装 Filebeat,并指定目录与日志格式,Filebeat 就能快速收集数据,并发送给 logstash 进行解析,或是直接发给 Elasticsearch 存储,性能上相比运行…...
利用wireshark lua扩展能力增加自定义解析器[注释解读版]
前言 Wireshark提供了lua扩展能力,可以定制一些Listner和Dissector,用于一些自定义的使用场景,例如: lua插件适应场景Listener报文统计、内容抽取等Dissector协议树解析,在wireshark中立等可看 已在以前的文档中积累了对于List…...
GPT-5不叫GPT-5?下一代模型会有哪些新功能?
OpenAI首席执行官奥特曼在上周三达沃斯论坛接受媒体采访时表示,他现在的首要任务就是推出下一代大模型,这款模型不一定会命名GPT-5。虽然GPT-5的商标早已经注册。 如果GPT-4目前解决了人类任务的10%,GPT-5应该是15%或者20%。 OpenAI从去年开…...
2024.1.23(347.前k个高频元素)
2024.1.23(347.前k个高频元素) 思路 这道题目主要涉及到如下三块内容: 1.要统计元素出现频率 2.对频率排序 3.找出前K个高频元素 首先统计元素出现的频率,这一类的问题可以使用map来进行统计。 然后是对频率进行排序,这里我们可以使用一种…...
MySQL对数据库的操作
前腰:本节只是的数据库本身进行增删查改、备份、恢复等操作,而不是对数据库内的数据表做操作,还请您区分好这两点。 1.创建数据库 # 创建数据库的语法形式 CREATE DATABASE [IF NOT EXISTS] database_name [create_specification]# 大写的是…...
解决Unity WebGLInput插件全屏输入的问题
unity webgl的中文输入插件WebglInput在全屏的时候会出现无法输入中文/输入的英文会字母出现在光标后面/什么都输入不了的等无法正常使用的情况。 插件官网作者给出了unity的2017,2018,2019版本的全屏输入解决方法。 最新插件下载地址:http…...
Android14实战:调整A2DP音量曲线(五十三)
简介: CSDN博客专家,专注Android/Linux系统,分享多mic语音方案、音视频、编解码等技术,与大家一起成长! 优质专栏:Audio工程师进阶系列【原创干货持续更新中……】🚀 优质专栏:多媒体系统工程师系列【原创干货持续更新中……】🚀 人生格言: 人生从来没有捷径,只…...
vector讲解
在学习玩string后我们开始学习vector,本篇博客将对vector进行简单的介绍,还会对vector一些常用的函数进行讲解 vector的介绍 实际上vector就是一个数组的数据结构,但是vector是由C编写而成的,他和数组也有本质上的区别ÿ…...
nvm 配置淘宝镜像失效,以及安装node后 npm-v 无效
win11 nvm版本 1.1.4 和1.1.7和1.1.12(目前最新版本24年 一月二十三日) 以上nvm版本都会出现一下问题, 从https://github.com/coreybutler/nvm-windows/releases 下载nvm安装包如下图 傻瓜式安装后,不用去配置环境变量&#…...
【Android Gradle 插件】Gradle 基础配置 ④ ( Gradle Wrapper 配置作用 | Gradle 下载的依赖库存放位置 )
一、Gradle Wrapper 配置作用 gradle wrapperdistributionBaseGRADLE_USER_HOME distributionPathwrapper/dists distributionUrlhttps\://services.gradle.org/distributions/gradle-6.7.1-bin.zip zipStoreBaseGRADLE_USER_HOME zipStorePathwrapper/distsGradle Wrapper 配…...
Deepin_Ubuntu_查看树形目录结构(tree)
Linux系统(Deepin、Ubuntu)中,可以使用tree命令来查看树形目录结构,下面是一些示例: 查看当前目录的树形结构: tree查看指定目录的树形结构,例如/etc/X11/fonts目录: tree /etc/X…...
docker详细操作--未完待续
docker介绍 docker官网: Docker:加速容器应用程序开发 harbor官网:Harbor - Harbor 中文 使用docker加速器: Docker镜像极速下载服务 - 毫秒镜像 是什么 Docker 是一种开源的容器化平台,用于将应用程序及其依赖项(如库、运行时环…...
边缘计算医疗风险自查APP开发方案
核心目标:在便携设备(智能手表/家用检测仪)部署轻量化疾病预测模型,实现低延迟、隐私安全的实时健康风险评估。 一、技术架构设计 #mermaid-svg-iuNaeeLK2YoFKfao {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg…...
解决Ubuntu22.04 VMware失败的问题 ubuntu入门之二十八
现象1 打开VMware失败 Ubuntu升级之后打开VMware上报需要安装vmmon和vmnet,点击确认后如下提示 最终上报fail 解决方法 内核升级导致,需要在新内核下重新下载编译安装 查看版本 $ vmware -v VMware Workstation 17.5.1 build-23298084$ lsb_release…...
基于服务器使用 apt 安装、配置 Nginx
🧾 一、查看可安装的 Nginx 版本 首先,你可以运行以下命令查看可用版本: apt-cache madison nginx-core输出示例: nginx-core | 1.18.0-6ubuntu14.6 | http://archive.ubuntu.com/ubuntu focal-updates/main amd64 Packages ng…...
【Go】3、Go语言进阶与依赖管理
前言 本系列文章参考自稀土掘金上的 【字节内部课】公开课,做自我学习总结整理。 Go语言并发编程 Go语言原生支持并发编程,它的核心机制是 Goroutine 协程、Channel 通道,并基于CSP(Communicating Sequential Processes࿰…...
python如何将word的doc另存为docx
将 DOCX 文件另存为 DOCX 格式(Python 实现) 在 Python 中,你可以使用 python-docx 库来操作 Word 文档。不过需要注意的是,.doc 是旧的 Word 格式,而 .docx 是新的基于 XML 的格式。python-docx 只能处理 .docx 格式…...
Caliper 配置文件解析:config.yaml
Caliper 是一个区块链性能基准测试工具,用于评估不同区块链平台的性能。下面我将详细解释你提供的 fisco-bcos.json 文件结构,并说明它与 config.yaml 文件的关系。 fisco-bcos.json 文件解析 这个文件是针对 FISCO-BCOS 区块链网络的 Caliper 配置文件,主要包含以下几个部…...
如何在网页里填写 PDF 表格?
有时候,你可能希望用户能在你的网站上填写 PDF 表单。然而,这件事并不简单,因为 PDF 并不是一种原生的网页格式。虽然浏览器可以显示 PDF 文件,但原生并不支持编辑或填写它们。更糟的是,如果你想收集表单数据ÿ…...
MySQL账号权限管理指南:安全创建账户与精细授权技巧
在MySQL数据库管理中,合理创建用户账号并分配精确权限是保障数据安全的核心环节。直接使用root账号进行所有操作不仅危险且难以审计操作行为。今天我们来全面解析MySQL账号创建与权限分配的专业方法。 一、为何需要创建独立账号? 最小权限原则…...
人工智能(大型语言模型 LLMs)对不同学科的影响以及由此产生的新学习方式
今天是关于AI如何在教学中增强学生的学习体验,我把重要信息标红了。人文学科的价值被低估了 ⬇️ 转型与必要性 人工智能正在深刻地改变教育,这并非炒作,而是已经发生的巨大变革。教育机构和教育者不能忽视它,试图简单地禁止学生使…...
