无法创建第3维到2D点的动画

时间:2019-06-25 16:21:00

标签: matlab animation 3d visualization scatter3d

我有一个代码,可以使在2D空间(x和y轴)中沿随机方向移动的点动画化。我尝试使用球面坐标创建第3维(z轴)。为了在3D空间中绘制和显示点,我使用了Psychtoolbox函数moglDrawDots3D,因为它需要3d坐标XYZ,但我仍在获得2D动画, z上的点不出现。我对原因一无所知。我对Matlab和动画非常陌生,非常感谢您的反馈和见解。为了清楚起见,我尝试在下面逐步解释我的代码。预先感谢您的帮助!

PS:不必使用Psychtoolbox,如果您有其他解决方案,我很乐意尝试。

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

首先,每个点在光圈内的随机位置。 “ dots.x”和“ dots.y”将保持每个点的x和y位置。

[dots.x,dots.y,dots.z] = CreateUniformDotsIn3DFrustum(dots.nDots, 25, 1/screen_ratio, 0.1, 100);  

然后我使用创建的函数'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.     

这会生成像素位置,但它们的中心位于[0,0],即左上角

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;               

我为动画定义了一些定时和运动参数

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                                                   

我通过使用球坐标确定x,y和z位置并推导它们来计算点的行进距离。

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; 

我尝试通过计算光圈的左,右上,下和光圈深度(向前和向后)(以度为单位)来使光圈适合点

动画的总帧数由持续时间(秒)乘以帧速率(帧/秒)确定。 secs2frames函数执行计算

nFrames = secs2frames(display,dots.duration);

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;

新的随机起始位置

[dots.x,dots.y,dots.z] = CreateUniformDotsIn3DFrustum(dots.nDots, 25, 1/screen_ratio, 0.1, 100);   

让点移动

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);

更新点的位置

        dots.x = dots.x + dx;
        dots.y = dots.y + dy;    
        dots.z = dots.z + dz;   

将光圈外部的点向后移动一个光圈宽度

     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');                                                                    

1 个答案:

答案 0 :(得分:1)

您要求提供有关如何以不同方式执行此操作的建议,因此,这里是一个简单3D动画的演示:

function q56758294
%% Generate some data
N_OBJS = 20;
P = rand(N_OBJS,3) .* ones(1,1,3);

%% Create the figure
figure(); 
hP(1) = plot3(P(:,1,1), P(:,2,1), P(:,3,1), 's', 'Color', [0 0 0]+0.8); hold on;
hP(2) = plot3(P(:,1,2), P(:,2,2), P(:,3,2), 's', 'Color', [0 0 0]+0.6);
hP(3) = plot3(P(:,1,3), P(:,2,3), P(:,3,3), 's', 'Color', [0 0 0]);
AX_LIMS = [-1 1]*3;
drawnow; set(gca, 'XLim', AX_LIMS, 'YLim', AX_LIMS, 'ZLim', AX_LIMS); grid on;

%% 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

这将导致:

enter image description here


如果要在黑色背景上显示白色圆圈,请使用以下内容替换图形创建代码:

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');

这将导致:

enter image description here


要将图导出为电影文件,您需要在循环内使用getframe,然后按照this example中的说明使用VideoWriter

此外,出于美观目的,我添加了“拖尾”,但是如果您不需要它们,可以轻松删除它们。