【MATLAB】一个宝藏博主公开的代码,给它加个速——水晶爱心模块

21 篇文章 3 订阅

【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、哔哩哔哩讲解与测试

  • 4
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值