Create a 3D space for random moving dots

I have a code that animates dots moving in random directions in a 2D space (x and y axis). I tried to create a 3rd dimension (z axis) using spherical coordinates In order to draw and display the dots in a 3D space, I used the Psychtoolbox function moglDrawDots3D, as it takes 3d coordinates XYZ, but I am still getting a 2D animation, the dots on the z don't appear. I have no clue on the cause. I am very new to Matlab and animations, I'd be very grateful to get your feedback and insight. I tried to explain my code step by step below for the sake of clarity. Thank you in advance for your help!
PS: The use of the Psychtoolbox is not a necessity, if you have any other solution, I'd be happy to try it out.
AssertOpenGL;
InitializeMatlabOpenGL;
display = OpenWindow()
dots.nDots = 531; % number of dots
dots.color = [255,255,255]; % color of the dots
dots.size = 10; % size of dots (pixels)
dots.center = [0,0,0]; % center of the field of dots (x,y,z)
dots.apertureSize = [50.8,28.5,50.8]; % size of rectangular aperture [w,h,depth] in degrees
First, random position within the aperture for each of the dots. 'dots.x' and 'dots.y' will hold the x and y positions for each dot.
[dots.x,dots.y,dots.z] = CreateUniformDotsIn3DFrustum(dots.nDots, 25, 1/screen_ratio, 0.1, 100);
Then I converted these dot positions from a visual angle into pixel coordinates using a created function 'angle2pix'
tmp = Screen('Resolution',0); % (1) Screen's 'Resolution' function determine the screen resolution.
display.resolution = [tmp.width,tmp.height];
display.width = 50.8; % (2) Width of the screen in cm.
display.dist = 50; % (3) Distance of the screen from the observer in cm.
This generates pixel positions, but they're centered at [0,0], which is the top left corner
pixpos.x = angle2pix(display,dots.x); % Convert the x position of the dots from visual angle to pixel.
pixpos.y = angle2pix(display,dots.y); % Convert the y position of the dots from visual angle to pixel.
pixpos.z = ones(1, dots.nDots) * -1;
I defined some timing and motion parameters for the animation
dots.speed = 3; % degrees/second
dots.duration = 10; % seconds
dots.theta_deg = randi(360,1,dots.nDots); % degrees
dots.phi_deg = 30; % degrees
dots.theta_rad = dots.theta_deg * pi /180; % direction converted to radians
dots.phi_rad = dots.phi_deg * pi /180; % direction converted to radians
I calculated the distance travelled by the dot, by determining the x,y and z positions using spherical coordinates and then their derivate.
dx = dots.speed* sin(-dots.phi_rad-dots.theta_rad)/display.frameRate;
dy = -dots.speed* cos(dots.phi_rad + dots.theta_rad)/display.frameRate;
dz = -dots.speed*cos(dots.theta_rad)/display.frameRate;
The total number of frames for the animation is determined by the duration (seconds) multiplied by the frame rate (frames/second). The function secs2frames performs the calculation
nFrames = secs2frames(display,dots.duration);
I try to fit the dots within the aperture by calculating the left, right top, bottom and depth(forward and backward) of the aperture (in degrees)
l = dots.center(1)-dots.apertureSize(1)/2;
r = dots.center(1)+dots.apertureSize(1)/2;
b = dots.center(2)-dots.apertureSize(2)/2;
t = dots.center(2)+dots.apertureSize(2)/2;
d_forward = dots.center(3)- dots.apertureSize(3)/2;
d_backward = dots.center(3)+ dots.apertureSize(3)/2;
New random starting positions
[dots.x,dots.y,dots.z] = CreateUniformDotsIn3DFrustum(dots.nDots, 25, 1/screen_ratio, 0.1, 100);
Make the dots move
try
for i=1:nFrames
%convert from degrees to screen pixels
pixpos.x = angle2pix(display,dots.x)+ display.resolution(1)/2;
pixpos.y = angle2pix(display,dots.y)+ display.resolution(2)/2;
pixpos.z = ones(1, dots.nDots) * -1;
moglDrawDots3D(display.windowPtr, [pixpos.x;pixpos.y;pixpos.z],dots.size, dots.color, dots.center,1);
update the dot position
dots.x = dots.x + dx;
dots.y = dots.y + dy;
dots.z = dots.z + dz;
Move the dots that are outside the aperture back one aperture width
dots.x(dots.x<l) = dots.x(dots.x<l) + dots.apertureSize(1);
dots.x(dots.x>r) = dots.x(dots.x>r) - dots.apertureSize(1);
dots.y(dots.y<b) = dots.y(dots.y<b) + dots.apertureSize(2);
dots.y(dots.y>t) = dots.y(dots.y>t) - dots.apertureSize(2);
dots.z(dots.z<d_forward) = dots.z(dots.z<d_forward) + dots.apertureSize(3);
dots.z(dots.z>d_backward) = dots.z(dots.z>d_backward) - dots.apertureSize(3);
Screen('Flip',display.windowPtr);
end
catch ME
Screen('CloseAll');
rethrow(ME)
end
Screen('CloseAll');

16 Commenti

You are using the PsychToolbox, which is a 3rd party tool. Please mention such important details.
What does "the z doesn't appear" mean?
Hi Jan, I mentioned the psychtoolbox in the tags of my question. I can of course add it in my question, thanks for mentioning it.
My goal is to have dots moving randomly in a 3D space (with three axis x, y and z - z representing the 3rd dimension). With the present code, the dots move in a 2D space (only x and y), despite the fact that I computed the z coordinates and the z axis. I don't necessary have to use the psychtoolbox, I am open to any suggestion or/and solution to showing the perception of depth (z axis) I am looking for.
@Kahina Olafsson: It is still not clear, what the problem is. What does "dots move in a 2D space" mean? Is their z value always 0? What does "computed the z axis" mean?
In other words, I don't have a 3D space, but a 2D one, which means that there is no depth in the space where the dots are moving. They move only between the X and Y axis and not "behind" (z axis = 3rd dimension).
I computed the z coordinates and defined a depth length (z axis) as shown in the code using spherical coordinates.
Sorry @Kahina Olafsson, for me, it's still unclear.
Kahina
Kahina il 26 Giu 2019
Modificato: Kahina il 26 Giu 2019
@KALYAN ACHARJYA It might help to know what is precisely unclear, that way I would know what to clarify. It would also be more productive and constructive, when commenting, to ask a direct question about the code. I have tried to explain the problem which is simply a 3 dimension animation. If 3D animation are new for some users, as it is for me, I understand that it is unclear. I am mainly asking experts or people who have already dealt with this issue. Thanks for your understanding.
As you are using psychtoolbox it is not obvious to us that you have a perspective view that would permit you to observe z differences. If you have a situation where a point with a smaller z is on top of a point with a higher z then that would be a psychtoolbox issue.
Thanks for your answer @Walter Roberson. As I am really new to Matlab and Psychtoolbox, I am not sure I understand why the psychtoolbox makes it difficult to observe z differences. I could also skip the psychtoolbox, and generate a number of frames (a movie) that I can play in a different script. However, I am unsure if the problem is with how I display the dots using Psychtoolbox, or with how I compute the motion.
@Kahina: I have asked some specific questions already, e.g. what "dots move in a 2D space" mean. Here an example of what might be meant:
t = 1:10
x = sin(t ./ 10);
y = cos(t ./ 10);
z = zeros(size(x));
This describes a situation, in which x and y coordinates are moving, while z is fixed. If I explain, that x,y,z are the 3D coordinates of a dot, the above code can be understood as "dots move in a 2D space".
But perhaps z is not fixed and you do not talk about some code, but you have a visualization already. If the view position is in the Z-direction and you have an orthographic projection, you do have a motion in 3D, but you do not see it due to the projection.
So are you talking about the corrdinates, or about an animation?
Explain, what you observe and not what happens internally. "dots move in a 2D space" is an interpretation of something, you see on the screen, in the code, in the workspace browser. But this can be a misinterpretation, so we need to know, what you observe with which tool.
psychtoolbox uses its own graphics routines that might default to being a view from above. For a range of distances and relative sizes it can become difficult to tell that there is z difference, and potentially impossible for othographic projections.
MATLAB defaults 3d plots to be viewed from an angle that makes it easier to tell that points are different z.
Kahina
Kahina il 26 Giu 2019
Modificato: Kahina il 26 Giu 2019
@Jan Excellent, thanks for your clarifications, it's clearer for me. When I run my code, I observe only x and y moving. What I would like to observe is x y and z moving, which means a depth in the screen (e.g.,like dots moving in a cube).
In fact the x, y and z coordinates should all be moving. Therefore the z should not have fixed value as in your example. I realize that the z value is actually fixed in my code. Therefore, I have tried to replace the following command line:
pixpos.z = ones(1, dots.nDots) * -1;
with this command line:
pixpos.z = angle2pix(display,dots.z);
Then inside the for loop, I replaced :
pixpos.z = ones(1, dots.nDots) * -1;
with :
angle2pix(display,dots.z)+dots.apertureSize(3) ;
I observed either a black screen without any visible dots, or when I ran it a second time, I observed only one visible dot moving alone.
If you want to visualize the animation, I put my code as well as auxiliary functions in this Github repo https://github.com/Kathia301m/Matlab-Psychtoolbox.
Thank you very much for your help.
@Walter Roberson Good to know about Psychtoolbox's own graphics routines. I should then skip this toolbox. However, I have to generate a set of frames (a movie) of white dots moving on a black background screen for an experiment in Neuroscience. Therefore, I cannot use plots. althought it would make my task easier as I have found examples of 3D dots plots online. Is there a way to avoid this orthogonal projection and the psychtoolbox, and still generate a 3D space?
You can use plots and write to videos file if you do not need real-time video generation.
If you want to change the background color of a figure you can use:
whitebg([0 0 0])
That should make the background color black, and you can then use standard plot3 calls, or scatter3 if you want easy controll of the dot colour...
Your problem seems to be made worse with the psyco-toolbox interface, it should be rather simple:
for i1 = 1:n,
plot3(x,y,z,'w.','markersize',23)
view(23,34)
axis([-1 sX+1,-1 sY+1, -1 sZ+1])
grid on
set(gca,'projection','perspective')
% additional decorations
M(i1) = getframe(gca);
% update x y and z
end
...with obvious replacements for you to style it out.
I have tried to plot the dots, remove the axis and put a black background, and it does not make a difference - I see do not observe or get the feeling of 3D (dots moving in z axis) probably because of the orthographic projection.
Here is the code :
function Demo3dDotsMovie
%% Generate some data
N_OBJS = 20;
P = rand(N_OBJS,3) .* ones(1,1,3);
%% Create the figure
figure('Color', 'k');
hP(1) = plot3(P(:,1,1), P(:,2,1), P(:,3,1), '.', 'Color', [0 0 0]+0.2, 'MarkerSize', 20); hold on;
hP(2) = plot3(P(:,1,2), P(:,2,2), P(:,3,2), '.', 'Color', [0 0 0]+0.4, 'MarkerSize', 20);
hP(3) = plot3(P(:,1,3), P(:,2,3), P(:,3,3), '.', 'Color', [0 0 0]+1.0, 'MarkerSize', 20);
AX_LIMS = [-1 1]*3;
drawnow; set(gca, 'XLim', AX_LIMS, 'YLim', AX_LIMS, 'ZLim', AX_LIMS, 'Color', 'k',...
'XColor', 'k', 'YColor', 'k', 'ZColor', 'k');
%% Animate:
FPS = 12;
for ind1 = 1:500
% Update coordinates:
dP = randn(N_OBJS,3)*0.1;
P(:,:,1) = P(:,:,2);
P(:,:,2) = P(:,:,3);
P(:,:,3) = P(:,:,3) + dP;
% Update plot objects:
for ind2 = 1:3
set( hP(ind2), 'XData', P(:,1,ind2), 'YData', P(:,2,ind2), 'ZData', P(:,3,ind2) );
end
pause(FPS^-1);
end
I am guessing that a way to get the feeling of depth would be a change in the size of dots when they move from the axis z (3rd dimension) to the axis XY (2nd dimension). But the problem of orthographic projection might remain, right? I might only observe dots becoming bigger in a 2D dimension (XY) rather than an increase of size through the trajectory from the 3rd dimension to XY.
Oh, you want to get a 3-D feeling when looking at your figure. That is another task altogether.
You might get a bit of a feel for 3-D motion if you do change the size depending on distance from your eye. I would still do that with plain matlab-coding, the trick would be to calculate size depending on distance from your eye, the angular diameter of your dots would decrease as , where l is distance from your eye. The question is how to properly scale the distance from the nearest to the farthes point relative to the distance between the screen and your eye. My guess is that you should try for dimensions close to reality, perhaps 0.4 m from eye to screen, and another .15 m from nearest to farthest corner of your cube. It "seems reasonable" that our visual perception would handle such a setting better than some completely different ratio.
The reason I write eye and not eyes is obviously that since you will only plot the points in one figure at the physical screen surface, and at that distance objects are close enough that we determine 3-D position from paralax. Because of that your eyes might actually be too clever to be fooled by your size-variation technique, they might see the points and determine by stereoscopic triangulation that they are at the screen-surface and simply interpret the size-variation as just that, The 3-D illusion might have a bigger chans if you only look with one eye. The ideal way to go about this would be to use one frame for the left eye and another frame for the right eye and then use VR-techniques to display the sequence - once uppon a time I worked with a SGI Onyx where you could separate frames for the left/right eyes with polarization and it worked really well.

Accedi per commentare.

Risposte (0)

Richiesto:

il 25 Giu 2019

Commentato:

il 27 Giu 2019

Community Treasure Hunt

Find the treasures in MATLAB Central and discover how the community can help you!

Start Hunting!

Translated by