【collisionMesh根据一组三维顶点创建碰撞几何体】处理杯子的表面数据并将其转换为碰撞网格

本文主要是介绍【collisionMesh根据一组三维顶点创建碰撞几何体】处理杯子的表面数据并将其转换为碰撞网格,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

第一段代码

从杯子的点云(即点的集合)创建一个碰撞网格几何体。下面是步骤和代码示例:

1. 从 X, Y, Z 坐标中提取杯子的顶点数据

2. 使用 collisionMesh 函数将顶点转换为碰撞网格

示例代码:

cupHeight = 0.2;
cupRadius = 0.05;
cupPosition = [-0.5, 0.5, cupHeight/2];% 创建用于视觉化杯子的点
[X,Y,Z] = cylinder(cupRadius*linspace(0,1,50).^0.125);
% 调整 Z 坐标的比例,使其符合杯子的高度
Z = cupHeight*Z - cupHeight/2;%杯子的中点被放置在Z=0的位置。这样,杯子在Z方向上的范围变成了从-0.1到0.1
% 将杯子的位置平移到指定位置
X = X + cupPosition(1);
Y = Y + cupPosition(2);
Z = Z + cupPosition(3);% 创建点的数组,用于碰撞网格
vertices = [X(:), Y(:), Z(:)];% 使用 collisionMesh 函数将点转换为碰撞网格
cupMesh = collisionMesh(vertices);% 可视化碰撞网格
show(cupMesh);
title('Cup Collision Mesh');

代码解释:

  1. 提取顶点数据:我们将 X, Y, Z 数据点展开为一个 N×3 的顶点数组 vertices,其中 N 是点的数量。

  2. 创建碰撞网格:使用 collisionMesh(vertices) 函数将这些顶点转换为凸网格碰撞几何体。

  3. 可视化:使用 show(cupMesh) 来显示生成的碰撞网格。

vertices = [X(:), Y(:), Z(:)];X, Y, Z 三个矩阵中的数据重新组织成一个表示三维空间中顶点(或点)坐标的数组(矩阵)。

1. 矩阵展平 (Flattening):
  • X(:), Y(:), Z(:) 通过 (:) 运算符将各自的矩阵展平成一个列向量。这意味着,矩阵中的所有元素会按照列优先顺序被排列成一列。
  • 如果 XYZ 的尺寸是 m x n,那么 X(:)Y(:)Z(:) 的尺寸将变成 mn x 1 的列向量。
2. 组合成顶点数组:
  • [X(:), Y(:), Z(:)] 将展平后的 XYZ 列向量按列拼接在一起,形成一个 mn x 3 的矩阵。
  • 这个矩阵中的每一行代表一个顶点的三维坐标 (x, y, z)。其中,第 i 行的元素分别是 X(i)Y(i)Z(i) 对应的坐标值。
3. 用途:
  • 这些顶点可以用于创建三维物体的网格结构,或者进行碰撞检测等计算。本例提供的代码中,vertices 就表示杯子表面的所有点的坐标,通过这些顶点可以构建杯子的三维形状。
代码示例:
clear; clc; close all;
% 假设 X, Y, Z 是 50 x 2 的矩阵,表示生成圆柱体表面的点
X = [0.1, 0.2; 0.3, 0.4];
Y = [0.5, 0.6; 0.7, 0.8];
Z = [0.9, 1.0; 1.1, 1.2];% 展平并组合成顶点坐标矩阵
vertices = [X(:), Y(:), Z(:)];
disp(vertices);
% 结果 vertices 将会是:
% vertices =
%    0.1    0.5    0.9
%    0.3    0.7    1.1
%    0.2    0.6    1.0
%    0.4    0.8    1.2

在这个例子中,每一行代表一个点的 (x, y, z) 坐标,这些点可以用于表示一个三维物体的几何形状,例如杯子的表面。

第二段代码

  1. 使用 surf2patch 函数将曲面数据转换为网格数据(顶点和面)。
  2. 使用 collisionMesh 函数创建碰撞网格。
  3. 可视化碰撞体以验证结果。

代码示例:

% 清除环境
clear; clc; close all;% 定义杯子的参数
cupHeight = 0.2;                 % 杯子高度
cupRadius = 0.05;                % 杯子半径
cupPosition = [-0.5, 0.5, cupHeight/2];  % 杯子的位置% 创建用于视觉化杯子的点
theta = linspace(0, 2*pi, 21);   % 角度分布
r = cupRadius * (linspace(0, 1, 50).^0.125);  % 半径分布,创造出杯子形状
[Theta, R] = meshgrid(theta, r);
X = R .* cos(Theta);
Y = R .* sin(Theta);
Z = linspace(-cupHeight/2, cupHeight/2, 50)';
Z = repmat(Z, 1, size(X,2));% 平移杯子到指定位置
X = X + cupPosition(1);
Y = Y + cupPosition(2);
Z = Z + cupPosition(3);% 将曲面数据转换为网格数据(顶点和面)
[F,V] = surf2patch(X,Y,Z,'triangles');% 创建碰撞网格
cupMesh = collisionMesh(V);% 可视化碰撞网格
figure;
show(cupMesh);
title('杯子碰撞体');
xlabel('X');
ylabel('Y');
zlabel('Z');
axis equal;
grid on;

代码解释:

  1. 定义杯子参数:

    • cupHeight:定义杯子的高度。
    • cupRadius:定义杯子的半径。
    • cupPosition:定义杯子在空间中的位置。
  2. 创建杯子的曲面数据:

    • 使用参数化的方法生成杯子的表面,其中半径随高度变化,可以通过调整指数(此处为 0.125)控制杯子的形状。
    • 使用 meshgrid 生成二维网格,然后计算对应的 X、Y、Z 坐标。
  3. 转换为网格数据:

    • 使用 surf2patch 函数将曲面数据转换为网格数据,得到顶点 (V) 和面 (F)。
    • 指定 'triangles' 参数以确保生成的面是三角形,这对于碰撞检测更稳定。
  4. 创建碰撞网格:

    • 使用 collisionMesh 函数并传入顶点数据 V,创建杯子的碰撞体。
    • 注意:collisionMesh 需要一个凸包,因此如果杯子的形状是非凸的,可能需要进一步处理。
  5. 可视化碰撞网格:

    • 使用 show 函数可视化创建的碰撞体,以验证结果是否符合预期。
    • 设置标题和坐标轴标签,并使用 axis equal 保持比例一致。
Z = repmat(Z, 1, size(X,2)); 通过复制和扩展矩阵 Z,使其与矩阵 X 在列数上匹配。
  1. repmat 函数:

    • repmat 是 MATLAB 中用于复制和重复数组的函数,其语法为 B = repmat(A, m, n),其中 A 是原始矩阵,mn 分别表示在行和列方向上复制的次数。repmat 返回一个新的矩阵 B,其大小为 [m*size(A,1), n*size(A,2)]
  2. 解释 Z = repmat(Z, 1, size(X,2));

  • Z 是一个列向量或矩阵,最初可能是一个 m x 1 的矩阵。
  • size(X,2) 返回矩阵 X 的列数。如果 X 是一个 m x n 的矩阵,那么 size(X,2) 就是 n
  • repmat(Z, 1, size(X,2)) 的作用是将 Z 沿列方向复制 n 次(即 size(X,2) 次),从而生成一个新的矩阵,该矩阵的大小为 m x n
  1. 示例:

假设 Z 是一个 50x1 的列向量,表示某些数据的高度值。X 是一个 50x21 的矩阵,表示某个曲面(例如圆柱体表面)的 X 坐标。

Z = linspace(-0.1, 0.1, 50)';  % Z 是一个 50x1 的列向量
X = rand(50, 21);  % X 是一个 50x21 的矩阵

执行 Z = repmat(Z, 1, size(X,2)); 后,Z 将变成一个 50x21 的矩阵,其中原来的 Z 列向量被重复复制了 21 次(size(X,2) 的值),使得 Z 的列数与 X 匹配。

  1. 为什么要这样做:

在许多情况下,为了在计算或绘图时对矩阵进行操作,需要两个矩阵的大小相匹配(即它们的行数和列数相同)。通过 repmatZ 的列数扩展到与 X 一致,可以在后续的操作中,将 Z 矩阵与 X 矩阵一起使用,比如在 surfmeshplot3 等函数中用于三维绘图。

注意事项:

  • 凸性要求: collisionMesh 函数要求输入的网格是凸的。如果杯子的形状存在凹陷,可能需要使用凸包算法(例如 convhull)处理顶点数据,确保生成的碰撞体是凸的。

    % 如果需要生成凸包
    K = convhull(V);
    cupMesh = collisionMesh(V(K,:));
    
  • 性能考虑: 如果顶点数量较多,可能会影响碰撞检测的性能。可以通过减少采样点或简化模型来提升性能。

  • 进一步应用: 创建的碰撞体可以用于机器人运动规划、物理仿真等领域,结合 MATLAB 的其他工具箱实现复杂的应用。

区别说明:

这两段代码的目的是生成一个杯子的三维模型并为其创建碰撞网格,不过它们在实现方式上有一些关键区别。

第一段代码的特点:

  1. 使用 cylinder 函数:

    • 第一段代码使用了 MATLAB 的 cylinder 函数来生成杯子的表面点。cylinder 函数生成了一个大小为 50x21 的矩阵,这对应于 50 个高度切片,每个切片上有 21 个点。这个方法相对简单,并且直接利用 MATLAB 的内置函数来生成圆柱体表面。
  2. vertices 的生成:

    • 通过 [X(:), Y(:), Z(:)] 生成 vertices,这将 XYZ 矩阵展平成列向量并组合成一个 1050x3 的矩阵,其中每一行是一个顶点的 (x, y, z) 坐标。这个 vertices 矩阵可以用于进一步的碰撞检测。
  3. 碰撞网格创建:

    • 使用 collisionMesh(vertices) 创建碰撞网格。vertices 是一个展平后的顶点矩阵。

第二段代码的特点:

  1. 手动创建圆柱体表面:

    • 第二段代码通过 linspacemeshgrid 手动生成了杯子的表面点。它通过参数化的角度 theta 和半径 r 来生成 XY 坐标,同时通过 linspace 生成 Z 坐标。
    • Z 坐标使用 repmat 扩展,使其与 XY 的列数匹配。结果是 XY 矩阵的大小为 50x21Z 也扩展为 50x21
  2. 使用 surf2patch 生成网格:

    • 该段代码使用 surf2patch 函数将生成的曲面数据 (X, Y, Z) 转换为面片 (F) 和顶点 (V) 数据。V 是一个 n x 3 的矩阵,其中 n 是所有顶点的数量。
  3. 碰撞网格创建:

    • 使用 collisionMesh(V) 来生成碰撞网格。这里的 V 是从 surf2patch 中得到的顶点数据,包含杯子表面的所有顶点。

关键区别:

  1. 生成表面点的方式:

    • 第一段代码使用 cylinder 生成圆柱体,这是一种更简单和直接的方式。
    • 第二段代码手动创建表面点,通过 meshgridlinspace 生成的表面点更加灵活,但代码相对复杂。
  2. 网格数据的生成:

    • 第一段代码没有明确生成面片数据,而是直接将展平后的顶点用于碰撞网格的创建。
    • 第二段代码生成了面片数据 (F) 和顶点数据 (V),提供了更细致的几何信息,适合更复杂的形状和处理。
  3. 结果差异:

    • 尽管两段代码的目标相同,生成的顶点数据 (verticesV) 可能会由于计算和生成方法的不同而略有差异。第二段代码通过手动控制生成的细节,可能会在浮点精度上略有不同。

顶点比较的意义:

比较 V1V2(以及 vertices)的目的是检查这两种生成方法是否在实际生成的几何形状上有差异。由于浮点数精度的原因,即使是理论上应该相等的点,在计算机中也可能会有细微的差异,这就是为什么需要使用容差进行比较的原因。

clear; clc; close all;cupHeight = 0.2;
cupRadius = 0.05;
cupPosition = [-0.5, 0.5, cupHeight/2];% 创建用于视觉化杯子的点
[X,Y,Z] = cylinder(cupRadius*linspace(0,1,50).^0.125);
% 调整 Z 坐标的比例,使其符合杯子的高度
Z = cupHeight*Z - cupHeight/2;%杯子的中点被放置在Z=0的位置。这样,杯子在Z方向上的范围变成了从-0.1到0.1
% 将杯子的位置平移到指定位置
X = X + cupPosition(1);
Y = Y + cupPosition(2);
Z = Z + cupPosition(3);% 创建点的数组,用于碰撞网格
vertices = [X(:), Y(:), Z(:)];%矩阵中的所有元素会按照列优先顺序被排列成一列
[~,V1] = surf2patch(X,Y,Z,'triangles');
% isEqual1 = (vertices == V1);
% if isEqual1
%         disp('V1 和 vertices 的点是相同的。');
% else
%         disp('V1 和 vertices 的点不同。');
% end
% 确认维度是否相同
if isequal(size(V1), size(vertices))% 逐元素比较,考虑浮点数误差tolerance = 1e-10;  % 设置容差值difference = abs(V1 - vertices);  % 计算差异isEqual1 = all(difference(:) < tolerance);  % 判断所有差异是否都在容差范围内if isEqual1disp('V1 和 vertices 的点是相同的。');elsedisp('V1 和 vertices 的点不同。');end
elsedisp('V1 和 vertices 的维度不同,因此它们不相同。');
end% 创建用于视觉化杯子的点
theta = linspace(0, 2*pi, 21);   % 角度分布
r = cupRadius * (linspace(0, 1, 50).^0.125);  % 半径分布,创造出杯子形状
[Theta, R] = meshgrid(theta, r);
X2 = R .* cos(Theta);
Y2 = R .* sin(Theta);
Z2 = linspace(-cupHeight/2, cupHeight/2, 50)';
Z2 = repmat(Z2, 1, size(X2,2));% 平移杯子到指定位置
X2 = X2 + cupPosition(1);
Y2 = Y2 + cupPosition(2);
Z2 = Z2 + cupPosition(3);% 将曲面数据转换为网格数据(顶点和面)
[F2,V2] = surf2patch(X2,Y2,Z2,'triangles');
% isEqual2 = (V2 == V1);% 在浮点数比较时使用容差范围,而不是直接比较两个数值是否完全相等
% if isEqual2
%         disp('V1 和 V2 的点是相同的。');
% else
%         disp('V1 和 V2 的点不同。');
% end% 确认维度是否相同
if isequal(size(V1), size(V2))% 逐元素比较,考虑浮点数误差tolerance = 1e-10;  % 设置容差值difference = abs(V1 - V2);  % 计算差异isEqual = all(difference(:) < tolerance);  % 判断所有差异是否都在容差范围内if isEqualdisp('V1 和 V2 的点是相同的。');elsedisp('V1 和 V2 的点不同。');end
elsedisp('V1 和 V2 的维度不同,因此它们不相同。');
endif isequal(size(V2), size(vertices))% 逐元素比较,考虑浮点数误差tolerance = 1e-10;  % 设置容差值difference = abs(V2 - vertices);  % 计算差异isEqual1 = all(difference(:) < tolerance);  % 判断所有差异是否都在容差范围内if isEqual1disp('V2 和 vertices 的点是相同的。');elsedisp('V2 和 vertices 的点不同。');end
elsedisp('V2 和 vertices 的维度不同,因此它们不相同。');
enda = 0.1 + 0.2;
b = 0.3;isEqual_test = (a == b)  % 直接比较,可能不准确
difference = abs(a - b) < 1e-10  % 使用容差比较

通过上述解释,可以理解这两段代码虽然在最终视觉效果上可能非常相似,但在实现细节和生成数据的精确度上存在不同。

collisionMesh 是 MATLAB 中用来创建凸网格碰撞几何体的工具。

它可以根据一组三维顶点创建碰撞几何体,这在机器人学、仿真以及碰撞检测等应用中非常有用。

创建方式

语法
MSH = collisionMesh(Vertices)
MSH = collisionMesh(___,Pose=pose)
描述
  1. MSH = collisionMesh(Vertices):从一组三维顶点列表 Vertices 创建一个凸网格碰撞几何体。顶点相对于指定的坐标系(通常是碰撞几何体的坐标系)给定。默认情况下,碰撞几何体的坐标系与世界坐标系重合。

  2. MSH = collisionMesh(___,Pose=pose):设置网格的姿态 Pose,相对于世界坐标系。Pose 属性可以在创建碰撞几何体时指定。

在 MATLAB 文档中,___ 是一个占位符,表示前面语法中的输入参数。也就是说,MSH = collisionMesh(___,Pose=pose) 这一语法中的 ___ 表示你可以在此处插入前面介绍过的必需参数或可选参数,然后再添加 Pose=pose 参数来设置网格的姿态。

具体来说,这里的 ___ 可以是你创建 collisionMesh 对象时所需的其他参数。例如,最基本的形式是:

MSH = collisionMesh(Vertices)

在这个基础上,如果你还想指定姿态 (Pose),就可以这样写:

MSH = collisionMesh(Vertices, Pose=pose)

在这个语法中:

  • Vertices 是你指定的顶点数据,用于定义网格的几何形状。
  • Pose=pose 用于设置网格在世界坐标系中的姿态。

所以,___ 代表的是前面提到的 Vertices 这个参数,表示你必须首先指定网格的顶点,然后才可以选择性地指定 Pose

属性

  • Vertices:网格的顶点,指定为一个 N×3 的数组,其中 N 是顶点的数量。每一行表示三维空间中的一个点的坐标。注意,有些点可能在构建的凸网格内部。

    数据类型:double

  • Pose:碰撞几何体相对于世界坐标系的姿态,指定为一个 4×4 的齐次矩阵或 se3 对象。可以在创建几何体之后更改姿态。

    数据类型:single | double

对象函数

  • show:显示碰撞几何体。
  • fitCollisionCapsule:在碰撞几何体周围拟合一个碰撞胶囊体。

示例

  1. 创建并可视化网格碰撞几何体

    • 创建一个包含十个随机选择的单位球面上点的数组。为了确保结果可重复,将随机种子设置为默认值。
    rng default
    n = 10;
    pts = zeros(n,3);
    for k = 1:nph = 2*pi*rand(1);th = pi*rand(1);pts(k,:) = [cos(th)*sin(ph) sin(th)*sin(ph) cos(ph)];
    end
    
    • 从数组创建凸网格碰撞几何体并可视化。
    m = collisionMesh(pts);
    show(m)
    
  2. 使用更多的点生成网格

    • 创建一个包含1000个随机选择的单位球面上点的数组,并可视化生成的网格碰撞几何体。
    n = 1000;
    pts2 = zeros(n,3);
    for k = 1:nph = 2*pi*rand(1);th = pi*rand(1);pts2(k,:) = [cos(th)*sin(ph) sin(th)*sin(ph) cos(ph)];
    end
    m2 = collisionMesh(pts2);
    show(m2)
    
  3. 创建包含立方体顶点的数组

    • 创建一个立方体的八个角点的数组,并将这些点添加到先前的点数组中。生成并可视化新的网格碰撞几何体。
    cubeCorners = [-2 -2 -2 ; -2 2 -2 ; 2 -2 -2 ; 2 2 -2 ;...-2 -2 2 ; -2 2 2 ; 2 -2 2 ; 2 2 2];
    pts3 = [pts2;cubeCorners];
    m3 = collisionMesh(pts3);
    show(m3)
    

这篇关于【collisionMesh根据一组三维顶点创建碰撞几何体】处理杯子的表面数据并将其转换为碰撞网格的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1095018

相关文章

大模型研发全揭秘:客服工单数据标注的完整攻略

在人工智能(AI)领域,数据标注是模型训练过程中至关重要的一步。无论你是新手还是有经验的从业者,掌握数据标注的技术细节和常见问题的解决方案都能为你的AI项目增添不少价值。在电信运营商的客服系统中,工单数据是客户问题和解决方案的重要记录。通过对这些工单数据进行有效标注,不仅能够帮助提升客服自动化系统的智能化水平,还能优化客户服务流程,提高客户满意度。本文将详细介绍如何在电信运营商客服工单的背景下进行

基于MySQL Binlog的Elasticsearch数据同步实践

一、为什么要做 随着马蜂窝的逐渐发展,我们的业务数据越来越多,单纯使用 MySQL 已经不能满足我们的数据查询需求,例如对于商品、订单等数据的多维度检索。 使用 Elasticsearch 存储业务数据可以很好的解决我们业务中的搜索需求。而数据进行异构存储后,随之而来的就是数据同步的问题。 二、现有方法及问题 对于数据同步,我们目前的解决方案是建立数据中间表。把需要检索的业务数据,统一放到一张M

关于数据埋点,你需要了解这些基本知识

产品汪每天都在和数据打交道,你知道数据来自哪里吗? 移动app端内的用户行为数据大多来自埋点,了解一些埋点知识,能和数据分析师、技术侃大山,参与到前期的数据采集,更重要是让最终的埋点数据能为我所用,否则可怜巴巴等上几个月是常有的事。   埋点类型 根据埋点方式,可以区分为: 手动埋点半自动埋点全自动埋点 秉承“任何事物都有两面性”的道理:自动程度高的,能解决通用统计,便于统一化管理,但个性化定

无人叉车3d激光slam多房间建图定位异常处理方案-墙体画线地图切分方案

墙体画线地图切分方案 针对问题:墙体两侧特征混淆误匹配,导致建图和定位偏差,表现为过门跳变、外月台走歪等 ·解决思路:预期的根治方案IGICP需要较长时间完成上线,先使用切分地图的工程化方案,即墙体两侧切分为不同地图,在某一侧只使用该侧地图进行定位 方案思路 切分原理:切分地图基于关键帧位置,而非点云。 理论基础:光照是直线的,一帧点云必定只能照射到墙的一侧,无法同时照到两侧实践考虑:关

使用SecondaryNameNode恢复NameNode的数据

1)需求: NameNode进程挂了并且存储的数据也丢失了,如何恢复NameNode 此种方式恢复的数据可能存在小部分数据的丢失。 2)故障模拟 (1)kill -9 NameNode进程 [lytfly@hadoop102 current]$ kill -9 19886 (2)删除NameNode存储的数据(/opt/module/hadoop-3.1.4/data/tmp/dfs/na

异构存储(冷热数据分离)

异构存储主要解决不同的数据,存储在不同类型的硬盘中,达到最佳性能的问题。 异构存储Shell操作 (1)查看当前有哪些存储策略可以用 [lytfly@hadoop102 hadoop-3.1.4]$ hdfs storagepolicies -listPolicies (2)为指定路径(数据存储目录)设置指定的存储策略 hdfs storagepolicies -setStoragePo

Hadoop集群数据均衡之磁盘间数据均衡

生产环境,由于硬盘空间不足,往往需要增加一块硬盘。刚加载的硬盘没有数据时,可以执行磁盘数据均衡命令。(Hadoop3.x新特性) plan后面带的节点的名字必须是已经存在的,并且是需要均衡的节点。 如果节点不存在,会报如下错误: 如果节点只有一个硬盘的话,不会创建均衡计划: (1)生成均衡计划 hdfs diskbalancer -plan hadoop102 (2)执行均衡计划 hd

hdu1240、hdu1253(三维搜索题)

1、从后往前输入,(x,y,z); 2、从下往上输入,(y , z, x); 3、从左往右输入,(z,x,y); hdu1240代码如下: #include<iostream>#include<algorithm>#include<string>#include<stack>#include<queue>#include<map>#include<stdio.h>#inc

hdu4826(三维DP)

这是一个百度之星的资格赛第四题 题目链接:http://acm.hdu.edu.cn/contests/contest_showproblem.php?pid=1004&cid=500 题意:从左上角的点到右上角的点,每个点只能走一遍,走的方向有三个:向上,向下,向右,求最大值。 咋一看像搜索题,先暴搜,TLE,然后剪枝,还是TLE.然后我就改方法,用DP来做,这题和普通dp相比,多个个向上

【Prometheus】PromQL向量匹配实现不同标签的向量数据进行运算

✨✨ 欢迎大家来到景天科技苑✨✨ 🎈🎈 养成好习惯,先赞后看哦~🎈🎈 🏆 作者简介:景天科技苑 🏆《头衔》:大厂架构师,华为云开发者社区专家博主,阿里云开发者社区专家博主,CSDN全栈领域优质创作者,掘金优秀博主,51CTO博客专家等。 🏆《博客》:Python全栈,前后端开发,小程序开发,人工智能,js逆向,App逆向,网络系统安全,数据分析,Django,fastapi