- /
-
Trick or Treat
on 31 Oct 2024
- 25
- 95
- 1
- 1
- 1948
Cite your audio source here (if applicable):
drawframe(1);drawframe(23);
Write your drawframe function below
function drawframe(f)
persistent P L
a=@arrayfun;
r=@repmat;
n=12; % Hidden face steps
s=(96-n)/2; % Remaining half-rotation length
f1=r([r(s/2+1,1,n/4),s/2+1:s,1:s/2,r(s/2+1,1,n/4)],1,2); f1=f1(f); % Face state index
% Draw the face for the mask
% Mouth
x=[-.5:.1:.5,flip(-.5:.1:.5)];
y=[.25 -.5 -.4 -.8 -.65 -.95,flip([.25 -.5 -.4 -.8 -.65]),.25 -.1 0 -.4 -.25 -.5,flip([.25 -.1 0 -.4 -.25])];
% Right eye
x1=[-.35 -.05 -.05 -.35];
y1=[.15 0 0 .7];
% Left eye
x2=[.35 .05 .05 .35];
y2=[.15 0 0 .7];
th=linspace(0,4*pi,97);
if f==1
figure(Color='k')
axes(Po=[0 0 1 1],Vis=0)
axis equal off
hold on
[~,~,~,P]=p(x,F(y,f1,s+1),x1,F(y1,f1,s+1),x2,F(y2,f1,s+1),r);
a(@(x)light(St='l',Po=[0 0 0],Col='g'),1:4)
L=a(@(x)light('St','l','Po',2*[sin(th(f)) -cos(th(f)) 0]),1:3);
lighting g
campos([0 -75 5]);
camtarget([0 0 .1]);
camva(1.8)
else
% Update face mask
[P.XData,P.YData,P.ZData]=p(x,F(y,f1,s+1),x1,F(y1,f1,s+1),x2,F(y2,f1,s+1),r);
% Rotate light
set(L,'Po',2*[sin(th(f)) -cos(th(f)) 0]);
end
end
function [X,Y,Z,P]=p(x,y,x1,y1,x2,y2,r)
% Pumpkin
l=@linspace;
n=600;
% Body
[X,Y,Z]=sphere(n);
% Shape pumpkin ribs (ridges)
R=(1-(1-mod(0:20/n:20,2)).^2/12);
X=R.*X;Y=R.*Y;Z=R.*Z;
% Apply face mask
[X,Y,Z]=M(X,Y,Z,x,y,x1,y1,x2,y2);
Z=(.8+(0-l(1,-1,n+1)'.^4)*.3).*Z;
% Stem
s=[1.5 1 repelem(.7, 6)].*[r([.1 .06],1,round(n/20)) .1]';
[t,p]=meshgrid(0:pi/15:pi/2,l(0,pi,round(n/10)+1));
x=r(-(.4-cos(p).*s).*cos(t)+.4,2,1);
z=r((.5-cos(p).*s).*sin(t)+.55,2,1);
y=[-sin(p).*s;sin(p).*s];
if nargout>3
P=surf(X,Y,Z,FaceC=[1 .4 .1],EdgeC='n',SpecularS=.5,AmbientS=0,DiffuseS=.2);
S=surf(x,y,z,FaceC='#008000',EdgeC='n');
end
end
function [X,Y,Z]=M(X,Y,Z,x,y,x1,y1,x2,y2)
% Masking function
% Surface is in the form of
% -1 -1 . . . -1 -1
% . . . . . . .
% . . . . . . .
% 1 1 . . . 1 1
% Easy enough to mask w/ inpolygon (mask projected onto pumpkin)
i=@inpolygon;
% Rotate to align ribs with face
[X,Y,Z]=R(X,Y,Z,[-pi/2 0 0]);
% Mask
mask=ones(size(Z));
mask((i(X,Y,x,y)|i(X,Y,x1,y1)|i(X,Y,x2,y2))&Z>=0)=NaN;
Z=Z.*mask;
% Rotate back
[X,Y,Z]=R(X,Y,Z,[pi/2 0 0]);
end
function [X,Y,Z]=R(X,Y,Z,t)
% Rotation matrices from scratch because why not
Rx=[1 0 0;0 cos(t(1)) -sin(t(1));0 sin(t(1)) cos(t(1))];
Ry=[cos(t(2)) 0 sin(t(2));0 1 0;-sin(t(2)) 0 cos(t(2))];
Rz=[cos(t(3)) -sin(t(3)) 0;sin(t(3)) cos(t(3)) 0;0 0 1];
for i=1:size(X,1)
for j=1:size(X,2)
r=Rx*Ry*Rz*[X(i,j);Y(i,j);Z(i,j)];
X(i,j)=r(1);
Y(i,j)=r(2);
Z(i,j)=r(3);
end
end
end
function y = F(y,f,s)
% Face motion
y=reshape(y',[],2)';
y(2,:)=flip(y(2,:));
y=arrayfun(@(x)linspace(y(1,x),y(2,x),s)',1:size(y,2),Un=0);
y=[y{:}];
y=[y(f,:);y(end-f+1,:)];
y=[y(1,:),flip(y(2,:))];
end