Не удалось создать трехмерную анимацию двухмерных точек.

У меня есть код, который анимирует точки, движущиеся в случайных направлениях в 2D-пространстве (оси x и y). Я попытался создать 3-е измерение (ось Z) с использованием сферических координат. Чтобы нарисовать и отобразить точки в 3D-пространстве, я использовал функцию moglDrawDots3D Psychtoolbox, так как она принимает 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');                                                                    

person Kathia    schedule 25.06.2019    source источник
comment
Я не могу сказать, связана ли проблема с тем, как вы рисуете, или с тем, как вы вычисляете движение (возможно, dz всегда равно нулю, или соотношение сторон таково, что, хотя движение в направлении z есть, оно настолько мало по сравнению с x и y кажется, что он не движется). Я очень сомневаюсь, что на ваш вопрос можно ответить в его нынешнем виде. Можно ли опубликовать работающий пример? Вам нужно будет либо включить все вспомогательные функции, либо избегать их использования (вместо этого используя некоторые приближения). См. также: минимально воспроизводимый пример.   -  person Dev-iL    schedule 26.06.2019
comment
Спасибо за ваш комментарий @Dev-iL. Я помещаю свой код, а также вспомогательные функции в свой репозиторий github.com/Kathia301m/Matlab- Psychtoolbox.git. Заранее спасибо за вашу помощь!   -  person Kathia    schedule 26.06.2019


Ответы (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

Что приводит к:

введите здесь описание изображения


Если вы хотите белые круги на черном фоне, замените код создания фигуры следующим:

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

Что затем приводит к:

введите здесь описание изображения


Чтобы экспортировать график в виде файла фильма, вам потребуется использовать getframe внутри цикла, а затем используйте VideoWriter, как описано в в этом примере .

Кроме того, я добавил следы в эстетических целях, но их легко удалить, если они вам не нужны.

person Dev-iL    schedule 26.06.2019
comment
Спасибо, мне нужно показать фильм как эксперимент по нейробиологии, а не как сюжет. Он должен иметь черный фон с белыми точками, движущимися случайным образом по экрану. Я действительно нашел несколько кодов, которые отображают трехмерные точки, но ничего о том, как генерировать кадры, чтобы создать фильм из случайных точек, движущихся в трехмерном пространстве. - person Kathia; 26.06.2019
comment
@Kathia А, ты никогда не упоминал об этом в своем вопросе. Вам нужно разделить вашу проблему на несколько шагов. Это был этап создания 3D-анимации. Еще одним шагом было бы раскрасить его в соответствии с вашими предпочтениями (черный фон, убрать оси и т. д.). Наконец, экспорт это третья проблема. По отдельности ни одна из этих проблем не является сложной, но вместе они могут показаться непосильными. Мне только интересно - как вы планируете показывать 3D фильм? Чего вам сейчас не хватает в моем ответе? - person Dev-iL; 26.06.2019
comment
Отлично, большое спасибо за ваш ответ и решение. Что ж, мне удалось создать фильм оптического потока, и я сохранил кадры в файл. Затем я создал еще один сценарий для воспроизведения фильма. С оптическим потоком было легко создать трехмерную глубину. Спасибо за сюжетное решение. Есть ли причина, по которой некоторые точки выглядят серыми, а не белыми? - person Kathia; 26.06.2019
comment
Серые точки — это именно те следы, о которых я упоминал... Когда точка перемещается в новое положение, ее предыдущее положение становится серым, а предпоследнее положение становится темно-серым. Это просто способ показать путь, по которому прошла точка, показывая некоторую ограниченную историю. Как уже упоминалось, это легко удалить. - person Dev-iL; 26.06.2019
comment
Последний вопрос: можно ли контролировать длину глубины (z). Например, я хочу видеть больше глубины в 3D, где я мог бы четко различать точки, расположенные на оси Z. С нашей анимацией я мог подумать, что точки движутся в 2D-пространстве при визуальном наблюдении — я думаю, это может быть связано с ортогональной проекцией? - person Kathia; 26.06.2019