- /
-
You get a cube! And you get a cube! And...
on 1 Nov 2024
- 43
- 173
- 0
- 3
- 1947
This is really just a performance update. I was not happy with the execution times and learned about Persistent variables from other entries so I improved it.
Now that it is fast I could make more of them.... Hans Scharler, you wanted one; Take as many as you want!
function drawframe(f)
persistent S V f1 f2
%% Movement sequence, MS
% (1,:) Which axis x, y, z, or (pause p) to rotate around
% (2,:) Which row to rotate 1, 2, 3, or 4 for all. Any character if pause.
% (3,:) Which direction to rotate, n if negative direction, p for positive
% Change to alter moves made. The function tries to fit all moves within 4s
% If timing issues arise all moves are executed and then a pause untill the
% time runs out
MS=['pzxzpyxzpzxyy';'0444021303124';'0npn0ppp0nnnp'];
%% First frame initiation
if f == 1
%% Set figure window properties
f2=figure(2); % Multi cube window
f1=figure(1); % Base rubix figure window
lim=[-1,1]*2.4;
hold on
xlim(lim);
ylim(lim);
zlim(lim);
axis off
pbaspect([1,1,1])
%% Get Textures encoded in audio
y=audioread("audio.wav");
y=reshape(y,[],1);
% Texture size, s
s=28;
n=s*s*3;% Number of elements in image
% Create the textures of each face
% By looping backwards we skip the need for explicit preallocation for
% speed and thus save characters.
for i=55:-1:1
I{i}=reshape(y(n*(i-1)+1:n*i),[s,s,3]);
end
%% Initiate surfaces
% Surfaces
S=initSurf(I);
% Verticies
% V = [v1 v2 v3 v4] X [Faces] X [x y z]
V=cell2mat(cellfun(@(x)reshape([x.XData,x.YData,x.ZData],4,1,3),S,...
UniformOutput=0));
% V = [x y z] X [Faces] X [v1 v2 v3 v4]
V=permute(V,[3,2,1]);
end
%% Prevent ears from bleeding
if f==96
% P C1 C2 C3 F2 G2
freq=[0 65.41 130.81 261.63 174.61 196];
note=[2 3 4 1 2 3 4 3 2 3 4 1 2 3 4 6];
fs=44100;
y=[];
for i=note
y=[y,.5*sin(2*pi*freq(i)*(0:1/fs:1))];
end
audiowrite('audio.wav',y,fs)
end
%% Timing and frame variables
figure(f1)
% Frames per move, FPM
FPM=floor(96/size(MS,2));
AngSpd=90/FPM;
view(45+180*f/96,35.2644);
%Pause for remaining time if timing issues arise
if f>FPM*size(MS,2)
return
end
% Determine which move in the sequence we are performing
c=ceil(AngSpd*f/90);
%% Set the rotation matrix
% Direction of rotation
if MS(3,c)=='n'
dir=-1;
elseif MS(3,c)=='p'
dir=1;
end
%Choice of Rotation Matrix
switch MS(1,c)
% Rotation matrix, R
% Vertice data in the axis of rotation, D
case 'x'
R=[1,0,0;
0,cosd(dir*AngSpd),-sind(dir*AngSpd);
0,sind(dir*AngSpd),cosd(dir*AngSpd)];
D=V(1,:,:);
case 'y'
R=[cosd(dir*AngSpd),0,sind(dir*AngSpd);
0,1,0;
-sind(dir*AngSpd),0,cosd(dir*AngSpd)];
D=V(2,:,:);
case 'z'
R=[cosd(dir*AngSpd),-sind(dir*AngSpd),0;
sind(dir*AngSpd),cosd(dir*AngSpd),0;
0,0,1];
D=V(3,:,:);
case 'p' %pause
return
end
%% Find the indices for the faces to rotate
D=squeeze(D)';
% Index of faces to include in rotation, F
if MS(2,c)=='1'
F=find(sum(D>=.5-10^-5,1)==4);
elseif MS(2,c)=='2'
F=find(sum(D<=.5+10^-5&D>=-.5-10^-5,1)==4);
elseif MS(2,c)=='3'
F=find(sum(D<=-.5+10^-5,1)==4);
elseif MS(2,c)=='4'
F=1:size(S,2);
end
%% Perform the rotation for each of the four vertices in a face
V(:,F,:)=pagemtimes(R,V(:,F,:));
%% Update the surface coordinate data
% We need to update the data of relevant faces
for i=F
S{i}.XData=reshape(V(1,i,:),2,2);
S{i}.YData=reshape(V(2,i,:),2,2);
S{i}.ZData=reshape(V(3,i,:),2,2);
end
%% DrawRubix
drawnow
%% Multi Cube
% So... I was going to make an enire other cube to rotate to prove how much
% faster the program is executing. But it was a pain so I will be cheating
% here...
if f>1
Images=cell(20,1);
Images(:) = {imresize(frame2im(getframe),[345,310],Method='bicubic')};
figure(f2)
montage(Images)
f2.Position=[0 0 600 600];
drawnow
end
end
function S = initSurf(I)
% shorthand some matrixes to save some characters
a=[0,0;0,0];
b=[2,3;2,3];
c=[0,0;1,1];
% Unfortunately we need to create every surface by itself if we want to
% texture them individually and not have any morphing geometry during plot
% We loop across:
% The 3 coordinate axes, C
% The 6 planes of the cube, p (inside planes count to not make it hollow)
% The 3 columns on each side of the cube, i
% The 3 rows on each side of the cube, j
t=1;%Counter for selection of textures
v=1;%Counter for keeping track of loop iteration
S=cell(1,162);%Preallocation
for C=0:2
for p=0:5
for i=0:2
for j=0:2
d=0;
if p==0||p==5 % First or last plane -> Textures!
T=I{t};
t=t+1;
else
% Plane inside the cube, we texture these black.
% To be able to "select" plane faces easily, we
% separate them slightly from eachother with a delta, d
if mod(p,2)
d=-10^-4;
else
d=+10^-4;
end
T=I{end};
end
pl=round(p/2);
%Determine coordinates based on axis and plane
switch C
case 0 %x
x=a+pl+d;
y=[3,3;2,2]-i;
z=b-j;
case 1 %y
x=c+i;
y=a+pl+d;
z=b-j;
case 2 %z
x=c+i;
y=[1,0;1,0]+j;
z=a+pl+d;
end
% Create, texture, and store the individual surface objects
% Unfortunately we need seperate surfaces as we do not want
% them to stay connected to stationary faces when rotating.
S{v}=surf(x-1.5,y-1.5,z-1.5,T,FaceColor='texturemap');
v=v+1;
end
end
end
end
end