- /
-
Stereographic Projection using Shadows
on 24 Oct 2024
- 31
- 163
- 0
- 1
- 1518
Cite your audio source here (if applicable): Generated in MATLAB!
Stereographic projections are a way to project featuers on a sphere onto a flat plane, and are used when creating some kinds of maps of the earth on paper (or screen)
They also lend themseves to make interesting spherical shapes that project shadows you may not expect!
Here's a nice reference video: https://www.youtube.com/watch?v=VX-0Laeczgk
drawframe(1);
Write your drawframe function below
function drawframe(f)
persistent Tri L Lm Ps
if f==1
%% Hex Grid
row=9;
col=8;
hr=.5; % hex radius
% origin centered coordinates of one hex of size hr
T=linspace(0,2,7);
xhex=sinpi(T)*hr;
yhex=cospi(T)*hr;
% Distance from center of edge center
D=cosd(30)*hr;
% Width of hex grid
WIDTH=col*D*2;
% Height of hex grid
HEIGHT=(row-1)*hr*1.5;
ps=polyshape.empty();
for i = 1:(col+1)
j = i-1;
for k = 1:row
if i<=col || ~mod(k,2)
m = k-1;
% Compute x,y positions of one hax in hex location j,k
% X coords are offset on alternating rows in Y
xbuff = ((xhex+mod(k,2)*D)+D*2*j)'-WIDTH/2;
% Each row in Y is nestled between corners of other rows
% so Y offset is not 2xhr.
ybuff = (yhex+1.5*hr*m)'-HEIGHT/2;
ps(end+1) = polybuffer([xbuff ybuff], 'lines', hr/4); %#ok
end
end
end
psTri = union(ps).triangulation();
pts = psTri.Points;
faces = psTri.ConnectivityList();
%% Reverse Stereographic projection
X=pts(:,1)/2;
Y=pts(:,2)/2;
H=X.^2+Y.^2;
SpherePts = [ 2*X./(1+H), 2*Y./(1+H), (H-1)./(H+1) ];
% Offset in Z by 1 to move sphere above the Z=0 plane
Tri = triangulation(faces, SpherePts+[0 0 1]);
%% Graphics Objects
newplot
% Patch to draw shape that casts shadows
patch('Vertices',Tri.Points,'Faces',Tri.ConnectivityList(),...
'FaceColor',lines(1),'EdgeColor','none');
% Represenation of the light
Lpos = [0 0 2];
L=light('position',Lpos,'style','local','color','y');
Lm=line('Marker','p','MarkerFaceColor','y','markersize',14);
view(3)
daspect([1 1 1])
lighting g
material([ .8 .9 .3 2 .5 ])
axis([-2 2 -2 2 -2 4],'off')
set(gcf,'color','w');
camproj('p');
% Patch to draw shadow
Ps = patch('Vertices',Tri.Points,'Faces', Tri.ConnectivityList,...
'FaceColor', [0 0 0], 'FaceAlpha', 'interp', 'FaceLighting','none',...
'EdgeColor', 'none','clipping','off');
alphamap(linspace(.6,.1,200)');
alim([0 8]);
end
%% Position our lightsource
lt=interp1([1 96],[-1 1],f);
x = sinpi(lt)*cospi(lt/2);
z = cospi(lt)*cospi(lt/2);
Lpos=[x*2 -x*2 z+2];
%% Compute Shadow
% Shadow points are a projection from the light to every vertex cast on Z==0 plane.
% We only need to compute new verteices. Faces Array doesn't need to change.
pts = Tri.Points;
Spts = zeros(size(pts));
Spts(:,1:2) = Lpos(3).*(pts(:,1:2)-Lpos(1:2))./(Lpos(3)-pts(:,3))+Lpos(1:2);
Sdist = vecnorm(Spts-Lpos,2,2); % attenuation of shadow based on distance
%% Setup objects
set(Ps,'Vertices',Spts,'FaceVertexAlphaData',Sdist);
set(Lm,'XData',Lpos(1), 'YData',Lpos(2), 'ZData',Lpos(3));
set(L,'Position',Lpos);
%% Sound generation
% Tone is based on height of light
%AS.osc.volume = .7;
%AS.osc.freq = 200+sinpi(lt)*100;
%AS.osc.tremolo_freq = 7;
%AS.osc.tremolo_depth = .8;
%AS.oscstereo = cospi(lt);
end