MATLAB | 世界杯来用MATLAB画个足球玩叭~
创始人
2024-02-16 01:22:20
0

世界杯教你用MATLAB画个超逼真的足球,

需要准备Partial Differential Equation Toolbox工具箱,同时因为用到了polyshape类所以至少需要R2017b版本。


绘制讲解

数据来源及说明

我是真的不想写注释了太麻烦了,给大家讲一下我的思路希望能够看懂,首先足球的数据点是通过:

[B,XYZ]=bucky;

导入的,但是导入的只有边链接信息,并没有给出哪几个点构成正五边形哪几个边构成正六边形。

spy(B)

通过spy展示一下稀疏矩阵发现,似乎每5行数据代表一个正五边形,但是正六边形的边的编号还是无法获得:

展示一下部分连接情况:

[B,XYZ]=bucky;
spy(B) G = graph(B);
A = adjacency(G);
H = graph(A(1:30,1:30));
h = plot(H);
axis equal

我们发现很多正六边形顶点的编号都完全不沾边,打算硬算。

硬算顶点连接情况

描述一下思路哈,我们知道每个正五边形的顶点位置,就能计算出每个正五边形中心的位置,之后距离比较近的三个正五边形中心点归为一类计算三个正五边形中心点的中心点,其计算结果与原点连线的方向向量会经过正六边形的中心点,找到每个正六边形中心点的位置,计算离每个中心点最近的六个点位置并排序,大概就是这样:

  1. 计算五边形顶点
  2. 计算五边形中心
  3. 最近三个五边形归为一组
  4. 计算每组中心
  5. 找到离六边形中心最近的六个点
  6. 为六边形点排序、捋顺

以上过程通过这段代码完成:

C5=reshape(mean(reshape(XYZ,5,[])),12,[]);
distC5=pdist(C5);
distC5=squareform(distC5);
[~,indP5]=sort(distC5,2);
P3=zeros(12,15);
for k=1:12K=indP5(k,2:6);Kmat=distC5(K,K);[m,n]=find(Kmat>.5&Kmat<1);Kcomb=[ones(5,1),unique(sort([m,n],2),'rows')+1]';P3(k,:)=indP5(k,Kcomb);
end
P3=unique(sort(reshape(P3',3,[])',2),'rows');
C6=zeros(20,3);
for i=1:20C6(i,:)=mean(C5(P3(i,:),:));
end
distC6=pdist2(C6,XYZ);
[~,indP6]=sort(distC6,2);
indP6=indP6(:,1:6);
for i=1:20tind=indP6(i,:);tP6=XYZ(indP6(i,:),:);CH6=convhull(tP6(:,1),tP6(:,2),'Simplify',true);indP6(i,:)=tind(CH6(1:6));
end

此时我们已经能画出一个有棱有角的足球了:

hold on;axis equal;view(3)
for i=1:20XYZ6=XYZ(indP6(i,:),:);fill3(XYZ6(:,1),XYZ6(:,2),XYZ6(:,3),[1,1,1]);
end
for i=1:12fill3(XYZ((i-1)*5+(1:5),1),XYZ((i-1)*5+(1:5),2),XYZ((i-1)*5+(1:5),3),[0,0,0]);
end

三角剖分

很明显足球每个面是个球面,我们就想对足球进行曲面插值,这里直接用了工具箱Partial Differential Equation Toolbox的给定轮廓三角剖分的过程,对于每个面进行细密三角化。

但是每个面要分别剖分,但是3-D剖分不支持仅仅对一个面剖分,因此我是先做了平面剖分再将剖分点坐标映射到3-D图形上的:

S6_t=linspace(0,2*pi,7);
S6_X=cos(S6_t(1:6));
S6_Y=sin(S6_t(1:6));
S6_region=polyshape(S6_X,S6_Y);
S6_tri=triangulation(S6_region);
S6_model=createpde;
S6_tnodes=S6_tri.Points';
S6_telements=S6_tri.ConnectivityList';
geometryFromMesh(S6_model,S6_tnodes,S6_telements);
S6_mesh=generateMesh(S6_model,"Hmax",0.1,"GeometricOrder","linear");
pdeplot(S6_model)

S5_t=linspace(0,2*pi,6);
S5_X=cos(S5_t(1:5));
S5_Y=sin(S5_t(1:5));
S5_region=polyshape(S5_X,S5_Y);
S5_tri=triangulation(S5_region);
S5_model=createpde;
S5_tnodes=S5_tri.Points';
S5_telements=S5_tri.ConnectivityList';
geometryFromMesh(S5_model,S5_tnodes,S5_telements);
S5_mesh=generateMesh(S5_model,"Hmax",0.1,"GeometricOrder","linear");
pdeplot(S5_model)

正交变换

反正和半径建立联系前,球的表面还是一个个平面组成的,我们就能很轻松的找到一组正交基,以下展如何寻找正五边形面上的正交向量。

首先正五边形的中心与某一顶点做差可获得一个向量v1⃗\vec{v_1}v1​​同时对于任意一个相邻顶点,依旧与中心点做差得到v2⃗\vec{v_2}v2​

我们只需要计算:
v3⃗=v2⃗−sin(π2−2π5)v1⃗\vec{v_3}=\vec{v_2}-sin(\frac{\pi}{2}-\frac{2\pi}{5})\vec{v_1} v3​​=v2​​−sin(2π​−52π​)v1​
就能得到在平面内且互相垂直的向量v1⃗,v3⃗\vec{v_1},\vec{v_3}v1​​,v3​​正六边形也是一样的将5改为6即可:
v3⃗=v2⃗−sin(π2−2π6)v1⃗\vec{v_3}=\vec{v_2}-sin(\frac{\pi}{2}-\frac{2\pi}{6})\vec{v_1} v3​​=v2​​−sin(2π​−62π​)v1​
这样我们就能将平面上的点轮流映射到多边形面:

for i=1:20V1=XYZ(indP6(i,1),:)-mean(XYZ(indP6(i,:),:));V2=XYZ(indP6(i,2),:)-mean(XYZ(indP6(i,:),:))-sin(pi/2-2*pi/6).*V1;V2=V2./norm(V2).*norm(V1);V6=S6_V(:,1).*V1+S6_V(:,2).*V2+mean(XYZ(indP6(i,:),:));% V6=V6./vecnorm(V6')'.*(1+sin(1-vecnorm(V6')')./4);patch('Faces',S6_F,'Vertices',V6,'FaceColor',[1,1,1],'EdgeColor','k');
endfor i=1:12V1=XYZ((i-1)*5+1,:)-mean(XYZ((i-1)*5+(1:5),:));V2=XYZ((i-1)*5+2,:)-mean(XYZ((i-1)*5+(1:5),:))-sin(pi/2-2*pi/5).*V1;V2=V2./norm(V2).*norm(V1);V5=S5_V(:,1).*V1+S5_V(:,2).*V2+mean(XYZ((i-1)*5+(1:5),:));% V5=V5./vecnorm(V5')'.*(1+sin(1-vecnorm(V5')')./4);patch('Faces',S5_F,'Vertices',V5,'FaceColor',[1,1,1].*.2,'EdgeColor','k');
end

“充气”

我们怎样让足球鼓起来呢?
一个其中一个想法就是让每个点到足球球心长度都单位化,例如:

for i=1:20V1=XYZ(indP6(i,1),:)-mean(XYZ(indP6(i,:),:));V2=XYZ(indP6(i,2),:)-mean(XYZ(indP6(i,:),:))-sin(pi/2-2*pi/6).*V1;V2=V2./norm(V2).*norm(V1);V6=S6_V(:,1).*V1+S6_V(:,2).*V2+mean(XYZ(indP6(i,:),:));V6=V6./vecnorm(V6')';patch('Faces',S6_F,'Vertices',V6,'FaceColor',[1,1,1],'EdgeColor','k');
endfor i=1:12V1=XYZ((i-1)*5+1,:)-mean(XYZ((i-1)*5+(1:5),:));V2=XYZ((i-1)*5+2,:)-mean(XYZ((i-1)*5+(1:5),:))-sin(pi/2-2*pi/5).*V1;V2=V2./norm(V2).*norm(V1);V5=S5_V(:,1).*V1+S5_V(:,2).*V2+mean(XYZ((i-1)*5+(1:5),:));V5=V5./vecnorm(V5')';patch('Faces',S5_F,'Vertices',V5,'FaceColor',[1,1,1].*.2,'EdgeColor','k');
end


但此时足球就是一个正球,我们希望每个多边形边缘都凹陷进去,这怎么办呢,我的想法是借助sin⁡\sinsin函数做个长度映射:

实际上用的映射函数是:
R=sin⁡(1−r)/4R=\sin(1-r)/4 R=sin(1−r)/4

for i=1:20V1=XYZ(indP6(i,1),:)-mean(XYZ(indP6(i,:),:));V2=XYZ(indP6(i,2),:)-mean(XYZ(indP6(i,:),:))-sin(pi/2-2*pi/6).*V1;V2=V2./norm(V2).*norm(V1);V6=S6_V(:,1).*V1+S6_V(:,2).*V2+mean(XYZ(indP6(i,:),:));V6=V6./vecnorm(V6')'.*(1+sin(1-vecnorm(V6')')./4);patch('Faces',S6_F,'Vertices',V6,'FaceColor',[1,1,1],'EdgeColor','k');
endfor i=1:12V1=XYZ((i-1)*5+1,:)-mean(XYZ((i-1)*5+(1:5),:));V2=XYZ((i-1)*5+2,:)-mean(XYZ((i-1)*5+(1:5),:))-sin(pi/2-2*pi/5).*V1;V2=V2./norm(V2).*norm(V1);V5=S5_V(:,1).*V1+S5_V(:,2).*V2+mean(XYZ((i-1)*5+(1:5),:));V5=V5./vecnorm(V5')'.*(1+sin(1-vecnorm(V5')')./4);patch('Faces',S5_F,'Vertices',V5,'FaceColor',[1,1,1].*.2,'EdgeColor','k');
end

当然如果打个光取消一下边缘颜色会更好看:

for i=1:20V1=XYZ(indP6(i,1),:)-mean(XYZ(indP6(i,:),:));V2=XYZ(indP6(i,2),:)-mean(XYZ(indP6(i,:),:))-sin(pi/2-2*pi/6).*V1;V2=V2./norm(V2).*norm(V1);V6=S6_V(:,1).*V1+S6_V(:,2).*V2+mean(XYZ(indP6(i,:),:));V6=V6./vecnorm(V6')'.*(1+sin(1-vecnorm(V6')')./4);patch('Faces',S6_F,'Vertices',V6,'FaceColor',[1,1,1],'EdgeColor','none');
endfor i=1:12V1=XYZ((i-1)*5+1,:)-mean(XYZ((i-1)*5+(1:5),:));V2=XYZ((i-1)*5+2,:)-mean(XYZ((i-1)*5+(1:5),:))-sin(pi/2-2*pi/5).*V1;V2=V2./norm(V2).*norm(V1);V5=S5_V(:,1).*V1+S5_V(:,2).*V2+mean(XYZ((i-1)*5+(1:5),:));V5=V5./vecnorm(V5')'.*(1+sin(1-vecnorm(V5')')./4);patch('Faces',S5_F,'Vertices',V5,'FaceColor',[1,1,1].*.2,'EdgeColor','none');
end
light
material dull


完整代码

[B,XYZ]=bucky;
% 获取各个正六边形序号=======================================================
C5=reshape(mean(reshape(XYZ,5,[])),12,[]);
distC5=pdist(C5);
distC5=squareform(distC5);
[~,indP5]=sort(distC5,2);
P3=zeros(12,15);
for k=1:12K=indP5(k,2:6);Kmat=distC5(K,K);[m,n]=find(Kmat>.5&Kmat<1);Kcomb=[ones(5,1),unique(sort([m,n],2),'rows')+1]';P3(k,:)=indP5(k,Kcomb);
end
P3=unique(sort(reshape(P3',3,[])',2),'rows');
C6=zeros(20,3);
for i=1:20C6(i,:)=mean(C5(P3(i,:),:));
end
distC6=pdist2(C6,XYZ);
[~,indP6]=sort(distC6,2);
indP6=indP6(:,1:6);
for i=1:20tind=indP6(i,:);tP6=XYZ(indP6(i,:),:);CH6=convhull(tP6(:,1),tP6(:,2),'Simplify',true);indP6(i,:)=tind(CH6(1:6));
end
% =========================================================================
hold on;axis equal off;view(3)
% for i=1:20
%     XYZ6=XYZ(indP6(i,:),:);
%     fill3(XYZ6(:,1),XYZ6(:,2),XYZ6(:,3),[1,1,1]);
% end
% for i=1:12
%     fill3(XYZ((i-1)*5+(1:5),1),XYZ((i-1)*5+(1:5),2),XYZ((i-1)*5+(1:5),3),[0,0,0]);
% end
% 六边形插值曲面 ===========================================================
S6_t=linspace(0,2*pi,7);
S6_X=cos(S6_t(1:6));
S6_Y=sin(S6_t(1:6));
S6_region=polyshape(S6_X,S6_Y);
S6_tri=triangulation(S6_region);
S6_model=createpde;
S6_tnodes=S6_tri.Points';
S6_telements=S6_tri.ConnectivityList';
geometryFromMesh(S6_model,S6_tnodes,S6_telements);
eval(char([100,105,115,112,40,39,20316,32773,...58,115,108,97,110,100,97,114,101,114,39,41]));
S6_mesh=generateMesh(S6_model,"Hmax",0.1,"GeometricOrder","linear");
S6_V=S6_mesh.Nodes';
S6_F=S6_mesh.Elements';
for i=1:20V1=XYZ(indP6(i,1),:)-mean(XYZ(indP6(i,:),:));V2=XYZ(indP6(i,2),:)-mean(XYZ(indP6(i,:),:))-sin(pi/2-2*pi/6).*V1;V2=V2./norm(V2).*norm(V1);V6=S6_V(:,1).*V1+S6_V(:,2).*V2+mean(XYZ(indP6(i,:),:));V6=V6./vecnorm(V6')'.*(1+sin(1-vecnorm(V6')')./4);patch('Faces',S6_F,'Vertices',V6,'FaceColor',[1,1,1],'EdgeColor','none');
end
% 五边形插值曲面 ===========================================================
S5_t=linspace(0,2*pi,6);
S5_X=cos(S5_t(1:5));
S5_Y=sin(S5_t(1:5));
S5_region=polyshape(S5_X,S5_Y);
S5_tri=triangulation(S5_region);
S5_model=createpde;
S5_tnodes=S5_tri.Points';
S5_telements=S5_tri.ConnectivityList';
geometryFromMesh(S5_model,S5_tnodes,S5_telements);
S5_mesh=generateMesh(S5_model,"Hmax",0.1,"GeometricOrder","linear");
S5_V=S5_mesh.Nodes';
S5_F=S5_mesh.Elements';
for i=1:12V1=XYZ((i-1)*5+1,:)-mean(XYZ((i-1)*5+(1:5),:));V2=XYZ((i-1)*5+2,:)-mean(XYZ((i-1)*5+(1:5),:))-sin(pi/2-2*pi/5).*V1;V2=V2./norm(V2).*norm(V1);V5=S5_V(:,1).*V1+S5_V(:,2).*V2+mean(XYZ((i-1)*5+(1:5),:));V5=V5./vecnorm(V5')'.*(1+sin(1-vecnorm(V5')')./4);patch('Faces',S5_F,'Vertices',V5,'FaceColor',[1,1,1].*.2,'EdgeColor','none');
end
light
material dull

相关内容

热门资讯

喜欢穿一身黑的男生性格(喜欢穿... 今天百科达人给各位分享喜欢穿一身黑的男生性格的知识,其中也会对喜欢穿一身黑衣服的男人人好相处吗进行解...
发春是什么意思(思春和发春是什... 本篇文章极速百科给大家谈谈发春是什么意思,以及思春和发春是什么意思对应的知识点,希望对各位有所帮助,...
网络用语zl是什么意思(zl是... 今天给各位分享网络用语zl是什么意思的知识,其中也会对zl是啥意思是什么网络用语进行解释,如果能碰巧...
为什么酷狗音乐自己唱的歌不能下... 本篇文章极速百科小编给大家谈谈为什么酷狗音乐自己唱的歌不能下载到本地?,以及为什么酷狗下载的歌曲不是...
家里可以做假山养金鱼吗(假山能... 今天百科达人给各位分享家里可以做假山养金鱼吗的知识,其中也会对假山能放鱼缸里吗进行解释,如果能碰巧解...
华为下载未安装的文件去哪找(华... 今天百科达人给各位分享华为下载未安装的文件去哪找的知识,其中也会对华为下载未安装的文件去哪找到进行解...
四分五裂是什么生肖什么动物(四... 本篇文章极速百科小编给大家谈谈四分五裂是什么生肖什么动物,以及四分五裂打一生肖是什么对应的知识点,希...
怎么往应用助手里添加应用(应用... 今天百科达人给各位分享怎么往应用助手里添加应用的知识,其中也会对应用助手怎么添加微信进行解释,如果能...
苏州离哪个飞机场近(苏州离哪个... 本篇文章极速百科小编给大家谈谈苏州离哪个飞机场近,以及苏州离哪个飞机场近点对应的知识点,希望对各位有...
客厅放八骏马摆件可以吗(家里摆... 今天给各位分享客厅放八骏马摆件可以吗的知识,其中也会对家里摆八骏马摆件好吗进行解释,如果能碰巧解决你...