用MATLAB画一个地球

MATLAB是强大的数据处软件,同时也是绝佳的绘图工具,或许我们可以尝试用MATLAB画一个地球!

绘制海洋

我们都知道“三分陆地,七分海洋”的地球主色调是蓝色,并且南北极常年被冰雪覆盖导致地球两极呈白色,因此我们先画一个“白-蓝-白”渐变的球。sphere生成球的坐标,然后使用surf绘制球面。选择白色[0.9,0.9,1]和蓝色[0,0.5,0.9],使用interp1插值得到“白-蓝-白”渐变的colormap。

clc; clear; close all;
[a,b,c]=sphere(99);
surf(a,b,c,EdgeColor="none");
bg_color=[0.9,0.9,1;0,0.5,0.9;0.9,0.9,1];
bwmap = [interp1(bg_color(:,1),1:0.01:3);interp1(bg_color(:,2),1:0.01:3);interp1(bg_color(:,3),1:0.01:3)]';
colormap(bwmap);

图1 蓝白海洋的地球

绘制陆地

地球除了海洋就是陆地,我们看到的陆地其实是被海洋“覆盖”剩余的部分,因此我们绘制的地球也可以利用这种“覆盖”的方法生成分散的大陆。利用vecnorm归一化得到球体上的坐标,乘以系数1.03使得陆地比海面高。将得到的球体坐标利用delaunay生成网格化球体,就得到了陆地。此时,我们故技重施构造一个黄绿色的colormap,并用patch给陆地“染色”。由于海洋的“覆盖”,剩下的陆地就呈分散的大陆。

hold on;
lx=randn(3,99);
lx=1.03*lx./vecnorm(lx);
lp=delaunay(lx');
land_map = [linspace(1,0,size(lx, 2));linspace(1,0.6,size(lx,2));linspace(0,0.25,size(lx, 2))]';
lh = patch('faces',lp,'vertices',lx', FaceVertexCData=land_map,FaceAlpha = 0.40);
shading interp;

图2 没有海洋覆盖的陆地(左侧)与被海洋覆盖的陆地(右侧)

绘制云层

此时的地球看起来还略显单调,缺少陆地之上的白色云层。云层的绘制的方法与陆地一样,只不过我们需要一个稍微大点的球,所以系数设置为1.04。设置colormap色调为白色,FaceAlpha减小为0.2,增加云层的透明度。

cx=randn(3,999);
cx=1.04*cx./vecnorm(cx);
cp=delaunay(cx');
cloud_map = [linspace(1,0.8,size(cx, 2));linspace(1,0.8,size(cx,2));linspace(1,0.8,size(cx, 2))]';
ch = patch('faces',cp,'vertices',cx', FaceVertexCData=cloud_map,FaceAlpha = 0.20);
shading interp;

图3 带云层的地球

最后点缀

最后,我们换一个黑色的太空背景,再在周围用scatter画点星星作为点缀。地球就画好啦!

set(gcf,'color','k');
r=@()rand(1,300);
scatter(r()*10-5,r()*10-5,r().^2*200,'.w');
camva(2);
图4 地球!

完整代码

clc;clear;close all;
[a,b,c]=sphere(100);
surf(a,b,c,EdgeColor="none");
bg_color=[0.9,0.9,1;0,0.5,0.9;0.9,0.9,1];
bwmap = [interp1(bg_color(:,1),1:0.01:3);interp1(bg_color(:,2),1:0.01:3);interp1(bg_color(:,3),1:0.01:3)]';
colormap(bwmap);

hold on;
lx=randn(3,99);
lx=1.03*lx./vecnorm(lx);
lp=delaunay(lx');
land_map = [linspace(1,0,size(lx, 2));linspace(1,0.6,size(lx,2));linspace(0,0.25,size(lx, 2))]';
lh = patch('faces',lp,'vertices',lx', FaceVertexCData=land_map,FaceAlpha = 0.40);
shading interp;
axis equal off;

cx=randn(3,999);
cx=1.04*cx./vecnorm(cx);
cp=delaunay(cx');
cloud_map = [linspace(1,0.8,size(cx, 2));linspace(1,0.8,size(cx,2));linspace(1,0.8,size(cx, 2))]';
ch = patch('faces',cp,'vertices',cx', FaceVertexCData=cloud_map,FaceAlpha = 0.20);
shading interp;

set(gcf,'color','k');
r=@()rand(1,300);
scatter(r()*10-5,r()*10-5,r().^2*200,'.w');
camva(2);