【MATLAB】一个宝藏博主公开的代码,给它加个速——水晶爱心模块
by 今天不飞了
注意!源代码来自 MATLAB专家slandarer博客 注意!源代码来自 MATLAB专家slandarer博客 注意!源代码来自 MATLAB专家slandarer博客 →→→七夕节快到了,教你用MATLAB绘制blingbling的大钻石←←←
实验结果
先看效果
提速效果可用自己电脑测试,下面出代码
一、原版
原理和原始代码可以点击上面链接去大佬博客里看。 这里调整缩进并增加过程注释,如下
主要函数
clear; close all; clc
%% {构造爱心}
% [生成爱心采样点]
sep = pi/8;
t = [0:0.2:sep,sep:0.02:pi-sep,pi-sep:0.2:pi+sep,pi+sep:0.02:2*pi-sep,2*pi-sep:0.2:2*pi];
x = 16*sin(t).^3;
y = 13*cos(t)-5*cos(2*t)-2*cos(3*t)-cos(4*t);
z = zeros(size(t));
% [绘制爱心轮廓]
plot3(x,y,z,'Color',[186,110,64]./255,'LineWidth',1),hold on
%% {生成水晶}
tic
cnum = 6; % 每个点生长cnum个水晶
for i = 1:length(t)
for j = 1:cnum
% [随机形态]
len = rand(1)*2+2;
tempV = rand(1,3)-0.5;
tempV = tempV./norm(tempV).*len;
tempSpnt = [x(i),y(i),z(i)];
tempEpnt = tempV+tempSpnt;
% [绘制]
drawCrystal(tempSpnt,tempEpnt,pi/6,0.8,0.14)
end
disp(i) % 计数,可删掉
end
toc
% [调整视角]
ax=gca;
ax.XLim=[-22,22];
ax.YLim=[-20,20];
ax.ZLim=[-10,10];
grid on
ax.GridLineStyle='--';
ax.LineWidth=1.2;
ax.XColor=[1,1,1].*0.4;
ax.YColor=[1,1,1].*0.4;
ax.ZColor=[1,1,1].*0.4;
ax.DataAspectRatio=[1,1,1];
ax.DataAspectRatioMode='manual';
% -------------------function---------------------
% {绘制水晶}
function drawCrystal(Spnt,Epnt,theta,cl,w)
mainV = Epnt-Spnt;
cutPnt = cl.*(mainV)+Spnt;
cutV = [mainV(3),mainV(3),-mainV(1)-mainV(2)];
cutV = cutV./norm(cutV).*w.*norm(mainV);
cornerPnt = cutPnt+cutV;
cornerPnt = rotateAxis(Spnt,Epnt,cornerPnt,theta);
cornerPntSet(1,:) = cornerPnt';
for ii = 1:3
cornerPnt = rotateAxis(Spnt,Epnt,cornerPnt,pi/2);
cornerPntSet(ii+1,:) = cornerPnt';
end
for ii = 1:4
jj = mod(ii,4)+1;
fill33(Spnt,cornerPntSet(ii,:),cornerPntSet(jj,:))
fill33(Epnt,cornerPntSet(ii,:),cornerPntSet(jj,:))
end
end
% {填充颜色}
function fill33(p1,p2,p3)
fill3([p1(1),p2(1),p3(1)],[p1(2),p2(2),p3(2)],[p1(3),p2(3),p3(3)],[0 71 177]./255.*1.03,...
'FaceAlpha',0.2,'EdgeColor',[0 71 177]./255.*0.9,'EdgeAlpha',0.25,'LineWidth',0.5,...
'EdgeLighting','gouraud','SpecularStrength',0.3)
end
子函数,在后续修改中该函数不会有改动,所以单独列出来
% {沿中轴旋转}
function newPnt = rotateAxis(Spnt,Epnt,cornerPnt,theta)
V = Epnt-Spnt;
V = V./norm(V);
u = V(1);
v = V(2);
w = V(3);
a = Spnt(1);
b = Spnt(2);
c = Spnt(3);
cornerPnt = [cornerPnt(:);1];
rotateMat = [u^2+(v^2+w^2)*cos(theta) , u*v*(1-cos(theta))-w*sin(theta), u*w*(1-cos(theta))+v*sin(theta), (a*(v^2+w^2)-u*(b*v+c*w))*(1-cos(theta))+(b*w-c*v)*sin(theta);
u*v*(1-cos(theta))+w*sin(theta), v^2+(u^2+w^2)*cos(theta) , v*w*(1-cos(theta))-u*sin(theta), (b*(u^2+w^2)-v*(a*u+c*w))*(1-cos(theta))+(c*u-a*w)*sin(theta);
u*w*(1-cos(theta))-v*sin(theta), v*w*(1-cos(theta))+u*sin(theta), w^2+(u^2+v^2)*cos(theta) , (c*(u^2+v^2)-w*(a*u+b*v))*(1-cos(theta))+(a*v-b*u)*sin(theta);
0 , 0 , 0 , 1];
newPnt = rotateMat*cornerPnt;
newPnt(4) = [];
end
二、优化一
用patch替换fill3函数,提速。仅修改drawCrystal函数里面的绘制部分。
该方式下,一次绘制整颗水晶(依赖这个特性有了 本文第四节)
clear; close all; clc
%% {构造爱心}
% [生成爱心采样点]
sep = pi/8;
t = [0:0.2:sep,sep:0.02:pi-sep,pi-sep:0.2:pi+sep,pi+sep:0.02:2*pi-sep,2*pi-sep:0.2:2*pi];
x = 16*sin(t).^3;
y = 13*cos(t)-5*cos(2*t)-2*cos(3*t)-cos(4*t);
z = zeros(size(t));
% [绘制爱心轮廓]
plot3(x,y,z,'Color',[186,110,64]./255,'LineWidth',1),hold on
%% {生成水晶}
tic
cnum = 6; % 每个点生长cnum个水晶
for i = 1:length(t)
for j = 1:cnum
% [随机形态]
len = rand(1)*2+2;
tempV = rand(1,3)-0.5;
tempV = tempV./norm(tempV).*len;
tempSpnt = [x(i),y(i),z(i)];
tempEpnt = tempV+tempSpnt;
% [绘制]
drawCrystal(tempSpnt,tempEpnt,pi/6,0.8,0.14)
end
disp(i) % 计数,可删掉
end
toc
% [调整]
ax = gca;
ax.XLim = [-22,22];
ax.YLim = [-20,20];
ax.ZLim = [-10,10];
grid on
ax.GridLineStyle = '--';
ax.LineWidth = 1.2;
ax.XColor = [1,1,1].*0.4;
ax.YColor = [1,1,1].*0.4;
ax.ZColor = [1,1,1].*0.4;
ax.DataAspectRatio = [1,1,1];
ax.DataAspectRatioMode = 'manual';
% -------------------function---------------------
% {绘制水晶}
function drawCrystal(Spnt,Epnt,theta,cl,w)
mainV = Epnt-Spnt;
cutPnt = cl.*(mainV)+Spnt;
cutV = [mainV(3),mainV(3),-mainV(1)-mainV(2)];
cutV = cutV./norm(cutV).*w.*norm(mainV);
cornerPnt = cutPnt+cutV;
cornerPnt = rotateAxis(Spnt,Epnt,cornerPnt,theta);
cornerPntSet(1,:) = cornerPnt';
for ii = 1:3
cornerPnt = rotateAxis(Spnt,Epnt,cornerPnt,pi/2);
cornerPntSet(ii+1,:) = cornerPnt';
end
% 修改部分
F = [1,3,4;1,4,5;1,5,6;1,6,3;...
2,3,4;2,4,5;2,5,6;2,6,3];
V = [Spnt;Epnt;cornerPntSet];
patch('Faces',F,'Vertices',V,'FaceColor',[1 0 0],...
'FaceAlpha',0.2,'EdgeColor',[1 0 0]*0.9,...
'EdgeAlpha',0.25,'LineWidth',0.5,'EdgeLighting',...
'gouraud','SpecularStrength',0.3)
end
三、优化二
将绘制部分提到主函数执行。
一次性绘制整个图形(整体化,就不方便独立修改)
clear; close all; clc
%% {构造爱心}
% [生成爱心采样点]
sep = pi/8;
t = [0:0.2:sep,sep:0.02:pi-sep,pi-sep:0.2:pi+sep,pi+sep:0.02:2*pi-sep,2*pi-sep:0.2:2*pi];
x = 16*sin(t).^3;
y = 13*cos(t)-5*cos(2*t)-2*cos(3*t)-cos(4*t);
z = zeros(size(t));
y = -y-15;
% [绘制爱心轮廓]
plot3(x,y,z,'Color',[186,110,64]./255,'LineWidth',1),hold on
%% {生成水晶}
tic
Flist = [];
Vlist = [];
idx = 0;
cnum = 6; % 每个点生长cnum个水晶
for i = 1:length(t)
for j = 1:cnum
% [随机形态]
len = rand(1)*2+2;
tempV = rand(1,3)-0.5;
tempV = tempV./norm(tempV).*len;
tempSpnt = [x(i),y(i),z(i)];
tempEpnt = tempV+tempSpnt;
% [绘制]
[f,v] = drawCrystal(tempSpnt,tempEpnt,pi/6,0.8,0.14);
Flist = [Flist;f+idx];
idx = idx+size(v,1);
Vlist = [Vlist;v];
end
disp(i) % 计数,可删掉
end
toc
% [绘制]
% figure
patch('Faces',Flist,'Vertices',Vlist,'FaceColor',[1 0 0],...
'FaceAlpha',0.35,'EdgeColor',[1 0 0]*0.9,...
'EdgeAlpha',0.20,'LineWidth',0.5,'EdgeLighting',...
'gouraud','SpecularStrength',0.3)
% [调整]
ax = gca;
ax.XLim = [-22,22];
ax.YLim = [-20,20];
ax.ZLim = [-10,10];
grid on
hold off
ax.GridLineStyle = '--';
ax.LineWidth = 1.2;
ax.XColor = [1,1,1].*0.4;
ax.YColor = [1,1,1].*0.4;
ax.ZColor = [1,1,1].*0.4;
ax.DataAspectRatio = [1,1,1];
ax.DataAspectRatioMode = 'manual';
light
axis off
% -------------------function---------------------
% {绘制水晶}
function [F,V] = drawCrystal(Spnt,Epnt,theta,cl,w)
mainV = Epnt-Spnt;
cutPnt = cl.*(mainV)+Spnt;
cutV = [mainV(3),mainV(3),-mainV(1)-mainV(2)];
cutV = cutV./norm(cutV).*w.*norm(mainV);
cornerPnt = cutPnt+cutV;
cornerPnt = rotateAxis(Spnt,Epnt,cornerPnt,theta);
cornerPntSet(1,:) = cornerPnt';
for ii = 1:3
cornerPnt = rotateAxis(Spnt,Epnt,cornerPnt,pi/2);
cornerPntSet(ii+1,:) = cornerPnt';
end
% 修改部分
F = [1,3,4;1,4,5;1,5,6;1,6,3;...
2,3,4;2,4,5;2,5,6;2,6,3];
V = [Spnt;Epnt;cornerPntSet];
end
四、衍生物
上接第二节,既然可以单独绘制一颗,那么就可以给每一颗不一样的颜色
clear; close all; clc
%% {构造爱心}
% [生成爱心采样点]
sep = pi/8;
t = [0:0.2:sep,sep:0.02:pi-sep,pi-sep:0.2:pi+sep,pi+sep:0.02:2*pi-sep,2*pi-sep:0.2:2*pi];
x = 16*sin(t).^3;
y = 13*cos(t)-5*cos(2*t)-2*cos(3*t)-cos(4*t);
z = zeros(size(t));
% [绘制爱心轮廓]
plot3(x,y,z,'Color',[186,110,64]./255,'LineWidth',1),hold on
%% {生成水晶}
tic
cnum = 6; % 每个点生长cnum个水晶
for i = 1:length(t)
for j = 1:cnum
% [随机形态]
len = rand(1)*2+2;
tempV = rand(1,3)-0.5;
tempV = tempV./norm(tempV).*len;
tempSpnt = [x(i),y(i),z(i)];
tempEpnt = tempV+tempSpnt;
% [绘制]
color = rand(1,3)*0.5+0.5;
drawCrystal(tempSpnt,tempEpnt,pi/6,0.8,0.14,color)
end
disp(i) % 计数,可删掉
end
toc
% [调整]
ax = gca;
ax.XLim = [-22,22];
ax.YLim = [-20,20];
ax.ZLim = [-10,10];
grid on
ax.GridLineStyle = '--';
ax.LineWidth = 1.2;
ax.XColor = [1,1,1].*0.4;
ax.YColor = [1,1,1].*0.4;
ax.ZColor = [1,1,1].*0.4;
ax.DataAspectRatio = [1,1,1];
ax.DataAspectRatioMode = 'manual';
axis off
% -------------------function---------------------
% {绘制水晶}
function drawCrystal(Spnt,Epnt,theta,cl,w,color)
mainV = Epnt-Spnt;
cutPnt = cl.*(mainV)+Spnt;
cutV = [mainV(3),mainV(3),-mainV(1)-mainV(2)];
cutV = cutV./norm(cutV).*w.*norm(mainV);
cornerPnt = cutPnt+cutV;
cornerPnt = rotateAxis(Spnt,Epnt,cornerPnt,theta);
cornerPntSet(1,:) = cornerPnt';
for ii = 1:3
cornerPnt = rotateAxis(Spnt,Epnt,cornerPnt,pi/2);
cornerPntSet(ii+1,:) = cornerPnt';
end
% 修改部分
F = [1,3,4;1,4,5;1,5,6;1,6,3;...
2,3,4;2,4,5;2,5,6;2,6,3];
V = [Spnt;Epnt;cornerPntSet];
patch('Faces',F,'Vertices',V,'FaceColor',color,...
'FaceAlpha',0.52,'EdgeColor',color*0.9,...
'EdgeAlpha',0.6,'LineWidth',0.5,'EdgeLighting',...
'gouraud','SpecularStrength',0.3)
end
其他
1、基本原理就是在规定的位置,随机生成多个水晶簇。所以根据选定的位置不同,就能绘制出各种有趣的东西。下面抛出一种思路
在网上下载免费的STL文件(3D打印用的),比如下载一个奥特曼的模型。 然后提取里面的顶点信息,然后调用上面的方法,就能得到一个水晶奥特曼
2、哔哩哔哩讲解与测试
|