Christmas Tree for Matlaber : Rotating With Falling Snowflakes
Latest activity Reply by Vasilis Bellos
on 6 Jan 2025


Christmas is coming, here are two dynamic Christmas tree drawing codes:
Crystal XMas Tree
function XmasTree2024_1
fig = figure('Units','normalized', 'Position',[.1,.1,.5,.8],...
'Color',[0,9,33]/255, 'UserData',40 + [60,65,75,72,0,59,64,57,74,0,63,59,57,0,1,6,45,75,61,74,28,57,76,57,1,1]);
axes('Parent',fig, 'Position',[0,-1/6,1,1+1/3], 'UserData',97 + [18,11,0,13,3,0,17,4,17],...
'XLim',[-1.5,1.5], 'YLim',[-1.5,1.5], 'ZLim',[-.2,3.8], 'DataAspectRatio', [1,1,1], 'NextPlot','add',...
'Projection','perspective', 'Color',[0,9,33]/255, 'XColor','none', 'YColor','none', 'ZColor','none')
%% Draw Christmas tree
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];
dP = @(V) patch('Faces',F, 'Vertices',V, 'FaceColor',[0 71 177]./255,...
'FaceAlpha',rand(1).*0.2+0.1, 'EdgeColor',[0 71 177]./255.*0.8,...
'EdgeAlpha',0.6, 'LineWidth',0.5, 'EdgeLighting','gouraud', 'SpecularStrength',0.3);
r = .1; h = .8;
V0 = [0,0,0; 0,0,1; 0,r,h; r,0,h; 0,-r,h; -r,0,h];
% Rotation matrix
Rx = @(V, theta) V*[1 0 0; 0 cos(theta) sin(theta); 0 -sin(theta) cos(theta)];
Rz = @(V, theta) V*[cos(theta) sin(theta) 0;-sin(theta) cos(theta) 0; 0 0 1];
N = 180; Vn = zeros(N, 3); eval(char(fig.UserData))
for i = 1:N
tV = Rz(Rx(V0.*(1.2 - .8.*i./N + rand(1).*.1./i^(1/5)), pi/3.*(1 - .6.*i./N)), i.*pi/8.1 + .001.*i.^2) + [0,0,.016.*i];
dP(tV); Vn(i,:) = tV(2,:);
end
scatter3(Vn(:,1).*1.02,Vn(:,2).*1.02,Vn(:,3).*1.01, 30, 'w', 'Marker','*', 'MarkerEdgeAlpha',.5)
%% Draw Star of Bethlehem
w = .3; R = .62; r = .4; T = (1/8:1/8:(2 - 1/8)).'.*pi;
V8 = [ 0, 0, w; 0, 0,-w;
1, 0, 0; 0, 1, 0; -1, 0, 0; 0,-1,0;
R, R, 0; -R, R, 0; -R,-R, 0; R,-R,0;
cos(T).*r, sin(T).*r, T.*0];
F8 = [1,3,25; 1,3,11; 2,3,25; 2,3,11; 1,7,11; 1,7,13; 2,7,11; 2,7,13;
1,4,13; 1,4,15; 2,4,13; 2,4,15; 1,8,15; 1,8,17; 2,8,15; 2,8,17;
1,5,17; 1,5,19; 2,5,17; 2,5,19; 1,9,19; 1,9,21; 2,9,19; 2,9,21;
1,6,21; 1,6,23; 2,6,21; 2,6,23; 1,10,23; 1,10,25; 2,10,23; 2,10,25];
V8 = Rx(V8.*.3, pi/2) + [0,0,3.5];
patch('Faces',F8, 'Vertices',V8, 'FaceColor',[255,223,153]./255,...
'EdgeColor',[255,223,153]./255, 'FaceAlpha', .2)
%% Draw snow
sXYZ = rand(200,3).*[4,4,5] - [2,2,0];
sHdl1 = plot3(sXYZ(1:90,1),sXYZ(1:90,2),sXYZ(1:90,3), '*', 'Color',[.8,.8,.8]);
sHdl2 = plot3(sXYZ(91:200,1),sXYZ(91:200,2),sXYZ(91:200,3), '.', 'Color',[.6,.6,.6]);
annotation(fig,'textbox',[0,.05,1,.09], 'Color',[1 1 1], 'String','Merry Christmas Matlaber',...
'HorizontalAlignment','center', 'FontWeight','bold', 'FontSize',48,...
'FontName','Times New Roman', 'FontAngle','italic', 'FitBoxToText','off','EdgeColor','none');
% Rotate the Christmas tree and let the snow fall
for i=1:1e8
sXYZ(:,3) = sXYZ(:,3) - [.05.*ones(90,1); .06.*ones(110,1)];
sXYZ(sXYZ(:,3)<0, 3) = sXYZ(sXYZ(:,3) < 0, 3) + 5;
sHdl1.ZData = sXYZ(1:90,3); sHdl2.ZData = sXYZ(91:200,3);
view([i,30]); drawnow; pause(.05)
end
end

Curved XMas Tree
function XmasTree2024_2
fig = figure('Units','normalized', 'Position',[.1,.1,.5,.8],...
'Color',[0,9,33]/255, 'UserData',40 + [60,65,75,72,0,59,64,57,74,0,63,59,57,0,1,6,45,75,61,74,28,57,76,57,1,1]);
axes('Parent',fig, 'Position',[0,-1/6,1,1+1/3], 'UserData',97 + [18,11,0,13,3,0,17,4,17],...
'XLim',[-6,6], 'YLim',[-6,6], 'ZLim',[-16, 1], 'DataAspectRatio', [1,1,1], 'NextPlot','add',...
'Projection','perspective', 'Color',[0,9,33]/255, 'XColor','none', 'YColor','none', 'ZColor','none')
%% Draw Christmas tree
[X,T] = meshgrid(.4:.1:1, 0:pi/50:2*pi);
XM = 1 + sin(8.*T).*.05;
X = X.*XM; R = X.^(3).*(.5 + sin(8.*T).*.02);
dF = @(R, T, X) surf(R.*cos(T), R.*sin(T), -X, 'EdgeColor',[20,107,58]./255,...
'FaceColor', [20,107,58]./255, 'FaceAlpha',.2, 'LineWidth',1);
CList = [254,103,110; 255,191,115; 57,120,164]./255;
for i = 1:5
tR = R.*(2 + i); tT = T+i; tX = X.*(2 + i) + i;
SFHdl = dF(tR, tT, tX);
[~, ind] = sort(SFHdl.ZData(:)); ind = ind(1:8);
C = CList(randi([1,size(CList,1)], [8,1]), :);
scatter3(tR(ind).*cos(tT(ind)), tR(ind).*sin(tT(ind)), -tX(ind), 120, 'filled',...
'CData', C, 'MarkerEdgeColor','none', 'MarkerFaceAlpha',.3)
scatter3(tR(ind).*cos(tT(ind)), tR(ind).*sin(tT(ind)), -tX(ind), 60, 'filled', 'CData', C)
end
%% Draw Star of Bethlehem
Rx = @(V, theta) V*[1 0 0; 0 cos(theta) sin(theta); 0 -sin(theta) cos(theta)];
% Rz = @(V, theta) V*[cos(theta) sin(theta) 0;-sin(theta) cos(theta) 0; 0 0 1];
w = .3; R = .62; r = .4; T = (1/8:1/8:(2 - 1/8)).'.*pi;
V8 = [ 0, 0, w; 0, 0,-w;
1, 0, 0; 0, 1, 0; -1, 0, 0; 0,-1,0;
R, R, 0; -R, R, 0; -R,-R, 0; R,-R,0;
cos(T).*r, sin(T).*r, T.*0];
F8 = [1,3,25; 1,3,11; 2,3,25; 2,3,11; 1,7,11; 1,7,13; 2,7,11; 2,7,13;
1,4,13; 1,4,15; 2,4,13; 2,4,15; 1,8,15; 1,8,17; 2,8,15; 2,8,17;
1,5,17; 1,5,19; 2,5,17; 2,5,19; 1,9,19; 1,9,21; 2,9,19; 2,9,21;
1,6,21; 1,6,23; 2,6,21; 2,6,23; 1,10,23; 1,10,25; 2,10,23; 2,10,25];
V8 = Rx(V8.*.8, pi/2) + [0,0,-1.3];
patch('Faces',F8, 'Vertices',V8, 'FaceColor',[255,223,153]./255,...
'EdgeColor',[255,223,153]./255, 'FaceAlpha', .2)
annotation(fig,'textbox',[0,.05,1,.09], 'Color',[1 1 1], 'String','Merry Christmas Matlaber',...
'HorizontalAlignment','center', 'FontWeight','bold', 'FontSize',48,...
'FontName','Times New Roman', 'FontAngle','italic', 'FitBoxToText','off','EdgeColor','none');
%% Draw snow
sXYZ = rand(200,3).*[12,12,17] - [6,6,16];
sHdl1 = plot3(sXYZ(1:90,1),sXYZ(1:90,2),sXYZ(1:90,3), '*', 'Color',[.8,.8,.8]);
sHdl2 = plot3(sXYZ(91:200,1),sXYZ(91:200,2),sXYZ(91:200,3), '.', 'Color',[.6,.6,.6]);
for i=1:1e8
sXYZ(:,3) = sXYZ(:,3) - [.1.*ones(90,1); .12.*ones(110,1)];
sXYZ(sXYZ(:,3)<-16, 3) = sXYZ(sXYZ(:,3) < -16, 3) + 17.5;
sHdl1.ZData = sXYZ(1:90,3); sHdl2.ZData = sXYZ(91:200,3);
view([i,30]); drawnow; pause(.05)
end
end

I wish all MATLABers a Merry Christmas in advance!
6 Comments
%% MATLAB tree
% Ref: https://uk.mathworks.com/matlabcentral/discussions/tips/878025-christmas-tree-for-matlaber-rotating-with-falling-snowflakes
fig = figure('Units','normalized', 'Position',[.25,0,.5,1],...
'Color',[0,9,33]/255);
axes('Parent',fig, 'Position',[0,-1/6,1,1+1/3],...
'XLim',[-6,6], 'YLim',[-6,6], 'ZLim',[-18, 1], 'DataAspectRatio', [1,1,1], 'NextPlot','add',...
'Projection','perspective', 'Color',[0,9,33]/255, 'XColor','none', 'YColor','none', 'ZColor','none')
% Draw Christmas tree
[X,T] = meshgrid(.4:.15:1, 0:pi/150:2*pi);
XM = 1 + sin(8.*T).*.05;
X = X.*XM; R = X.^(3).*(.5 + sin(8.*T).*.02);
dF = @(R, T, X) surf(R.*cos(T), R.*sin(T), -X, 'EdgeColor','interp',...
'FaceColor', [20,107,58]./255, 'FaceAlpha',.8, 'LineWidth',1,'MeshStyle','Column',...
'facelighting','gouraud','ambientstrength',.3,'diffusestrength',.5,'specularstrength',.5);
cmap = colormap(turbo);
% LED strips
cmap = colormap(repmat([cmap;flip(cmap)],3,1));
% Star light
arrayfun(@(x)light('Style','local','Position',[0 0 -1.3],'color',[255,223,153]./255),1:4)
CList = [255,100,100; 150,255,100; 0,255,255]./255;
rng(1)
for i = 1:6 % Number of tree 'layers'
tR = R.*(2 + i); tT = T+i; tX = X.*(2 + i) + i;
SFHdl = dF(tR, tT, tX);
% LED strip gradient
for j=1:size(SFHdl.CData,2)
SFHdl.CData(:,j)=linspace(1,numel(cmap),size(SFHdl.CData,1));
end
[~, ind] = sort(SFHdl.ZData(:)); ind = ind(1:8);
C = CList(randi([1,size(CList,1)], [8,1]), :);
% Tree lights symmetry
if i==1
C(length(C)/2+1:end,:) = C(1:length(C)/2,:);
end
if mod(i,2)
for j=1:length(ind)/2
P = drawPinecone;
set(P,'Matrix',makehgtform(Translate=[tR(ind(j)).*cos(tT(ind(j))), tR(ind(j)).*sin(tT(ind(j))), -tX(ind(j))],Scale=0.35))
end
scatter3(tR(ind(length(ind)/2+1:end)).*cos(tT(ind(length(ind)/2+1:end)))*1.01, tR(ind(length(ind)/2+1:end)).*sin(tT(ind(length(ind)/2+1:end)))*1.01, -tX(ind(length(ind)/2+1:end)), 500, 'filled',...
'CData', C(length(ind)/2+1:end,:), 'MarkerEdgeColor','none', 'MarkerFaceAlpha',.3)
scatter3(tR(ind(length(ind)/2+1:end)).*cos(tT(ind(length(ind)/2+1:end)))*1.01, tR(ind(length(ind)/2+1:end)).*sin(tT(ind(length(ind)/2+1:end)))*1.01, -tX(ind(length(ind)/2+1:end)), 80, 'filled', 'CData', C(length(ind)/2+1:end,:))
else
% Add a few membrane ornaments
if i==2 || i==4
M = drawMembraneOrnament;
set(M,'Matrix',makehgtform(Translate=[tR(ind(1)).*cos(tT(ind(1)))*.98, tR(ind(1)).*sin(tT(ind(1)))*.98, -tX(ind(1))+0.05*0],ZRotate=rand*pi+pi/4*i,Scale=.9))
M = drawMembraneOrnament;
set(M,'Matrix',makehgtform(Translate=[tR(ind(3)).*cos(tT(ind(3)))*.98, tR(ind(3)).*sin(tT(ind(3)))*.98, -tX(ind(3))+0.05*0],ZRotate=rand*pi+pi/4*i,Scale=.9))
scatter3(tR(ind([2,4:end])).*cos(tT(ind([2,4:end])))*1.01, tR(ind([2,4:end])).*sin(tT(ind([2,4:end])))*1.01, -tX(ind([2,4:end])), 500, 'filled',...
'CData', C([2,4:end],:), 'MarkerEdgeColor','none', 'MarkerFaceAlpha',.3)
scatter3(tR(ind([2,4:end])).*cos(tT(ind([2,4:end])))*1.01, tR(ind([2,4:end])).*sin(tT(ind([2,4:end])))*1.01, -tX(ind([2,4:end])), 80, 'filled', 'CData', C([2,4:end],:))
else
scatter3(tR(ind).*cos(tT(ind))*1.01, tR(ind).*sin(tT(ind))*1.01, -tX(ind), 500, 'filled',...
'CData', C, 'MarkerEdgeColor','none', 'MarkerFaceAlpha',.3)
scatter3(tR(ind).*cos(tT(ind))*1.01, tR(ind).*sin(tT(ind))*1.01, -tX(ind), 80, 'filled', 'CData', C)
end
end
% Tree lights
if i==1
arrayfun(@(h)light('Style','Local','Position',[tR(ind(h)).*cos(tT(ind(h)))*.7, tR(ind(h)).*sin(tT(ind(h)))*.7, -tX(ind(h))+2],'Color',C(h,:)),length(ind)/2+1:length(ind))
end
end
% Draw Star of Bethlehem
Rx = @(V, theta) V*[1 0 0; 0 cos(theta) sin(theta); 0 -sin(theta) cos(theta)];
w = .3; R = .62; r = .4; T = (1/8:1/8:(2 - 1/8)).'.*pi;
V8 = [ 0, 0, w; 0, 0,-w;
1, 0, 0; 0, 1, 0; -1, 0, 0; 0,-1,0;
R, R, 0; -R, R, 0; -R,-R, 0; R,-R,0;
cos(T).*r, sin(T).*r, T.*0];
F8 = [1,3,25; 1,3,11; 2,3,25; 2,3,11; 1,7,11; 1,7,13; 2,7,11; 2,7,13;
1,4,13; 1,4,15; 2,4,13; 2,4,15; 1,8,15; 1,8,17; 2,8,15; 2,8,17;
1,5,17; 1,5,19; 2,5,17; 2,5,19; 1,9,19; 1,9,21; 2,9,19; 2,9,21;
1,6,21; 1,6,23; 2,6,21; 2,6,23; 1,10,23; 1,10,25; 2,10,23; 2,10,25];
V8 = Rx(V8.*.8, pi/2) + [0,0,-1.3];
patch('Faces',F8, 'Vertices',V8, 'FaceColor',[255,223,153]./255,...
'EdgeColor',[255,223,153]./255, 'FaceAlpha', 1,'facelighting','gouraud','ambientstrength',.7,'diffusestrength',.8,'specularstrength',0)
% Draw snow
sXYZ = rand(200,3).*[12,12,19] - [6,6,18];
sHdl1 = plot3(sXYZ(1:90,1),sXYZ(1:90,2),sXYZ(1:90,3), '*','linewidth',1,'markersize',12, 'Color',[1 1 1]*.9);
sHdl2 = plot3(sXYZ(91:200,1),sXYZ(91:200,2),sXYZ(91:200,3), '.','markersize',10, 'Color',[1 1 1]*.9);
for i=1:360 % Seamless loop
sXYZ(:,3) = sXYZ(:,3) - [2*19/360.*ones(90,1); 3*19/360.*ones(110,1)];
sXYZ(sXYZ(:,3)<-18, 3) = sXYZ(sXYZ(:,3) < -18, 3) + 19;
sHdl1.ZData = sXYZ(1:90,3); sHdl2.ZData = sXYZ(91:200,3);
view([i,30]); drawnow;
end
function H=drawPinecone
% Ref: https://blogs.mathworks.com/graphics-and-apps/2024/12/16/pinecode-creating-pinecones-with-fibonacci-spirals/
% Pinecone Attributes
nscales = 140;% Number of scales
height = 2.5; % Height of inner part of pinecone
nn = 18; % Number of needles
vps = 17; % verts per scale : An odd number so 1 vert is in center
vpr = 20; % verts per radius
% Scale locations
FIB = (1+sqrt(5))*(1:nscales); % Fibonacci golden ratio as factor of pi
H = linspace(0,1,nscales).^2.8*height; % Height of the root of each scale
R = 1-linspace(-1,1,nscales).^2; % Radius of pinecone over height
U = 1-abs(linspace(-1,1,nscales).^3); % Thickness of scale U shape by height
% Geometry of the scales at the locations
ST = reshape((linspace(-.5,.5,vps)*.3+FIB')', 1,[]);
SR = reshape(((1-abs(linspace(-1,1,vps).^3)).*R')',1,[]);
SH = reshape((ones(1,vps).*H'+abs(linspace(-1,1,vps).^3.*U')*.2)',1,[]);
MR = linspace(0,1,vpr)'.*SR;
% Compute final geometry of the pinecone
X = cospi(ST).*MR;
Y = sinpi(ST).*MR;
Z = SH.*ones(vpr,1)+MR.*linspace(0,1,vps*nscales).^2.1*1.2;
% C = linspace(0,1,vpr).^2'.*ones(1,vps*nscales);
% Plot pinecone
P(1) = plot3(X(end,:),Y(end,:),-Z(end,:),'-','linewidth',.5,'Color',[120 61 3]/255*.5);
P(2) = surface(X,Y,-Z,'FaceColor',"#783D03",'EdgeColor','none','FaceLighting','gouraud','AmbientStrength',0.5,'SpecularColorReflectance',0.1,'SpecularStrength',0.1,'SpecularExponent',5,'DiffuseStrength',0.15);
% Branch & Needles
P(3) = line('XData',(0:.5:2)/3*cos(rand*2*pi),'YData',zeros(1,5),'ZData',[ 0 .05 .2 .25 .2 ]*2,...
'Color','k', 'LineWidth',1); % Branch
NT = linspace(0,5,nn)';
NR = linspace(.1,.8,nn)';
NV = [ 0 0 0; -ones(nn,1).*randi([-1,1],nn,1)*.5 cospi(NT).*NR sinpi(NT).*NR+.9 ];
NF = [ ones(nn,1) (1:nn)'+1 ];
P(4) = patch('Vertices',NV,'Faces',NF,'EdgeColor','#0F9666','FaceColor','none',...
'LineWidth',1); % Needles
H = hgtransform;
set(P,'Parent',H);
end
function H=drawMembraneOrnament
% Ref: https://uk.mathworks.com/help/matlab/visualize/creating-the-matlab-logo.html
% https://uk.mathworks.com/matlabcentral/discussions/fun/877700-matlab-ornament
% https://uk.mathworks.com/matlabcentral/discussions/fun/878156-tree-topper-l-shaped-membrane
L = membrane(1,100);
L = L-max(L,[],'all');
[x,y] = deal(linspace(-.5,.5,length(L)));
[r,c] = find(L==max(L,[],'all'));
x = x+x(r);
y = y+y(c);
[X,Y] = meshgrid(x,y);
S(1) = surface(X,Y,L,'EdgeColor','none');
view(3)
Z = S.ZData;
% Close the membrane & combine sides
S(2) = surf([X(Y==Y(1))*[1 1];NaN(1,2);X(X==X(1))*[1 1];NaN(1,2);X(Y==Y(end))*[1 1];NaN(1,2);X(X==X(end))*[1 1];NaN(1,2);X([1,end],[1,end])],...
[Y(Y==Y(1))*[1 1];NaN(1,2);Y(X==X(1))*[1 1];NaN(1,2);Y(Y==Y(end))*[1 1];NaN(1,2);Y(X==X(end))*[1 1];NaN(1,2);Y([1,end],[1,end])],...
[[Z(Y==Y(1)),ones(size(Z(Y==Y(1))))*(min(Z,[],'all'))];NaN(1,2);[Z(X==X(1)),ones(size(Z(X==X(1))))*(min(Z,[],'all'))];NaN(1,2);...
[Z(Y==Y(end)),ones(size(Z(Y==Y(end))))*(min(Z,[],'all'))];NaN(1,2);[Z(X==X(end)),ones(size(Z(X==X(end))))*(min(Z,[],'all'))];...
NaN(1,2);ones(2,2)*(min(Z,[],'all'))],'edgecolor','none');
set(S,'FaceColor','#FF4433','FaceLighting','gouraud','AmbientStrength',.3,'DiffuseStrength',.6,'BackFaceLighting','lit','SpecularStrength',1,'SpecularColorReflectance',1,'SpecularExponent',7)
H = hgtransform;
set(S,'Parent',H);
end
Merry Christmas and Happy Holidays. Thanks for sharing the code.
Impressive as usual Zhaoxu Liu! Thanks for sharing!