MATLAB三维绘图和相机图形术语玩到6起来会怎样?

一个摸鱼的上班日,一台电脑,加上MATLAB和一些奇思妙想,能得到什么?

答案是,我要给项目写个原创彩蛋,如下:

动起来的太阳系,还有运动的镜头。

代码来也!


function EasterEgg
% Draw several shapes rotating around the 
% parent star and the camera trajectory is an ellipse
planetsNum=4;
Sun_magnification=15;
Planets_magnification=10;
mainWin=figure(1);
set(mainWin, 'Toolbar', 'none','numbertitle','off');
set(mainWin,'menubar','none','Name', 'Easter Egg ')
axesmain=axes('Position', [0, 0, 1, 1]);
mainWin.WindowState = 'fullscreen';

%draw sun begin
[a,b,c]=sphere(99);
surf(axesmain,a*Sun_magnification,b*Sun_magnification,c*Sun_magnification);
newmap=[1 0 0];
colormap(newmap)
xx0=randn(3,999);       
xx0=(Sun_magnification+0.1)*xx0./vecnorm(xx0);
p=delaunay(xx0');

patch(axesmain,'faces',p,'vertices',xx0','FaceVertexCData',cool(size(p,1)),'FaceAlpha',.25);
set(mainWin,'color','k')
set(mainWin,'InvertHardCopy','off')
shading flat
%draw sun done


theta=[0 0 0 0 0 0 0 0];  %theta Planet_Sun_angle
phi=[7.01 3.39 0 1.85 1.31 2.49 0.77 1.77]; %phi Planet_Earth_angle
Ma=[0.4667,0.7282,1.0167,1.666,5.459,9.537,19.218,30.07]*100;
ecc_ratio=[0.2056,0.0068,0.0167,0.0934,0.0489,0.0565,0.0464,0.0097];
diametersOfPlanets = [4.88, 12.1, 12.742, 6.779, 139.82, 116.46, 50.72, 49.24]*Planets_magnification; % Relative size, unit: diameter of the earth
colorsOfPlanets = [0.5, 0.5, 0.5; 1, 0.8, 0; 0, 0, 1; 1, 0, 0; 1, 0.5, 0; 0.8, 0.8, 0.8; 0, 0.5, 1; 0, 0, 0.5]; % RGB of each planets
% period0=[0.24 0.62 1 1.88 11.86 29.46 84.01 164.79];
% period=[0.5 0.25 0.125 0.1 0.02 0.008 0.002 0.001];
period=[384 192 96 48 24 12 6 3];
if planetsNum<length(period)
    diametersOfPlanets(planetsNum+1:end) =[];
    colorsOfPlanets(planetsNum+1:end,:) =[];
    period(planetsNum+1:end)=[];
end


x0=[];y0=[];z0=[];
for i=1:planetsNum
    [x0(i,:),y0(i,:),z0(i,:)]=Orbit_coor_calcu(theta(i),phi(i),Ma(i),ecc_ratio(i));
    if i==1
        x=[x0(i,:)];
        y=[y0(i,:)];
        z=[z0(i,:)];
    elseif i>1
        x=[x,nan,x0(i,:)];
        y=[y,nan,y0(i,:)];
        z=[z,nan,z0(i,:)];
    end

end
% draw Planetary orbit
hold on;
plot3(axesmain,x, y, z, 'w', 'LineWidth', 0.1); 
% draw Planetary orbit done

% draw stars
tempBound=[x,y];
a0= max(abs(tempBound))*1.2;
farBound = a0*3;
r=@()rand(1,100);
arrayrand1 =(2*farBound) *r()-farBound;
arrayrand2 = (2*farBound) *r()-farBound;
arrayrand3 = (2*farBound/2) *r()-farBound/2;
strascoor=[arrayrand1;arrayrand2;arrayrand3];
index = strascoor(1, :) >= -a0 & strascoor(1, :) <= a0 & ...
        strascoor(2, :) >= -a0 & strascoor(2, :) <= a0 & ...
        strascoor(3, :) >= -a0/2 & strascoor(3, :) <= a0/2;
strascoor(:,index)=nan;

hold on
scatter3(axesmain,strascoor(1,:),strascoor(2,:),strascoor(3,:),'.w','SizeData', 50);
axis equal 
axis vis3d
axis off
% draw stars done

for j=1:planetsNum
    original_array = x0(j,:);
    interval=period(j)/period(end);
    expanded_new_array=Array_Thinning(original_array,interval);
    x1(j,:)=expanded_new_array;

    original_array = y0(j,:);
    expanded_new_array=Array_Thinning(original_array,interval);
    y1(j,:)=expanded_new_array;

    original_array = z0(j,:);
    expanded_new_array=Array_Thinning(original_array,interval);
    z1(j,:)=expanded_new_array;
    
end

[camtrack_x,camtrack_y,camtrack_z]=Orbit_coor_calcu(0,20,Ma(planetsNum),ecc_ratio(planetsNum));
camtrack_x=camtrack_x-max(camtrack_x)*0.8;

xlimset=size(x0,2);
m=xlimset;
step=1;
%draw Planets
hold on;
v=scatter3(axesmain,x1(:,m), y1(:,m), z1(:,m),diametersOfPlanets',colorsOfPlanets, 'filled'); 
%draw Planets done


%%%%%%%%%%%%% save gif
% filename = 'animation.gif';
% fps = 30; 
% gif_obj = [];
%%%%%%%%%%%%% save gif

while ishandle(1)
    m=m-step;
    if m==1
        m=xlimset;
    end
    % move plantes
    set(v,'xdata',x1(:,m),'ydata',y1(:,m),'zdata',z1(:,m))
    % move plantes

    camtarget(axesmain, [0, 0, 0]); 
    campos(axesmain,[camtrack_x(m)*8,camtrack_y(m)*8,camtrack_z(m)*5+250]); 
    pause(0.01)
    
    drawnow
%%%%%%%%%%%%%  save gif
%     frame = getframe(gcf);
%     img = frame2im(frame);
%     
%     if isempty(gif_obj)
%         [imind, cm] = rgb2ind(img, 256);
%         imwrite(imind, cm, filename, 'gif', 'Loopcount', inf, 'DelayTime', 1/fps);
%         gif_obj = false;
%     else
%         [imind, cm] = rgb2ind(img, 256);
%         imwrite(imind, cm, filename, 'gif', 'WriteMode', 'append', 'DelayTime', 1/fps);
%     end
%     
%     pause(0.01);
%%%%%%%%%%%%%  save gif
end


end

上面这些是主程序的内容,姑且叫“”太阳系模拟吧,因为并不是按照真实的八大行星的运行速度模拟的。
大致就是①生成了一个太阳,②生成行星的轨道,③随机生成一些星星并且控制其在太阳系内不显示,④画出行星。这里用到了一点小心思,我并没有一个一个绘制所有行星,而是一次性绘制了所有行星,这样可以提高性能(尽管其实也没有必要提高),而且代码看着会精简一些。


另外动图嘛,当然要保存一哈,只需要将   %%%%%%%%%%%%% save gif   之内的代码取消注释就行。要想退出动画,那就按一下esc键就行了,因为窗口不关循环不停。

下面是两个自己写的函数,主程序会调用,建议将这俩函数分别存到不同的*.m文件中。

Orbit_coor_calcu函数是用法向量的方式生成三维椭圆用的;

Array_Thinning函数有点难以解释,大概是这个效果,例如:函数输入:original_array=[1 2 3 4 5 6 7 8 9],interval=3,那么函数的输出就是:[1 4 7 1 4 7 1 4 7];

function [x_circle, y_circle, z_circle] = Orbit_coor_calcu(alpha, phi, major_axis, ecc_ratio)
num=768*4;
Ma = major_axis;
Sa = Ma * sqrt(1 - ecc_ratio^2);
x0 = sind(phi) * cosd(alpha);
y0 = sind(phi) * sind(alpha);
z0 = cosd(phi);
n = [x0, y0, z0]; % 法向量n

theta = linspace(0, 2*pi, num); % theta角从0到2*pi
a = cross(n, [1, 0, 0]); % n与i叉乘,求取a向量
if all(a == 0) % 如果a为零向量,将n与j叉乘
    a = cross(n, [0, 1, 0]);
end
b = cross(n, a); % 求取b向量
a = a / norm(a); % 单位化a向量
b = b / norm(b); % 单位化b向量

% 计算圆上各点的坐标,取实部确保结果是实数
x_circle = real(Ma * a(1) * cos(theta) + Sa * b(1) * sin(theta));
y_circle = real(Ma * a(2) * cos(theta) + Sa * b(2) * sin(theta));
z_circle = real(Ma * a(3) * cos(theta) + Sa * b(3) * sin(theta));

end



function expanded_new_array=Array_Thinning(original_array,interval)

    new_length = ceil(length(original_array) / interval);
    new_array = zeros(1, new_length);
    
    for i = 1:new_length
        index = (i - 1) * interval + 1;
        new_array(i) = original_array(index);
    end
    expanded_new_array = repmat(new_array, 1, interval);
end

哦对了,如果你看到这里了,那么我就说一嘴,主程序刚开始的位置

planetsNum=4;
Sun_magnification=15;
Planets_magnification=10;

这三个变量是可以更改的,planetsNum最大是8,要是你想让更多的行星出现,比如10,那么这些数组的维度都要改成10:

theta=[...];  %theta Planet_Sun_angle

phi=[...]; %phi Planet_Earth_angle

Ma=[...]*100;

ecc_ratio=[...];

diametersOfPlanets = [...]*Planets_magnification; % Relative size, unit: diameter of the earth

colorsOfPlanets = [...]; % RGB of each planets

period=[384 192 96 48 24 12 6 3];

要说一下数组period,里面的元素一定要是768*4的约数哟,至于为啥必须是768*4,是因为我闭着眼睛敲得三个数,写到最后发现:“哎!还可以哎”,但是代价就是,这个数不能改了(好像吧)

最后感谢 "Matlab矩阵研学社",代码里的太阳就是模仿这个公众号里的内容画的。

  • 9
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值