Как сделать плавный поворот 3D-графика в MATLAB? - PullRequest
8 голосов
/ 02 декабря 2010

Если я попытаюсь повернуть камеру вокруг моей текущей фигуры с помощью plot3, используя

while true; camorbit(0.9,-0.1); drawnow; end

тогда вращение на некоторое время периодически зависает ( пример ) даже на 8-ядерном MacPro.

Можно ли сделать это гладко?

EDIT1:

Хотя для моего первоначального вопроса пока нет решения, мне удалось сделать лучший фильм с функцией getframe. Тем не менее, он не позволяет записывать вращение от руки, и в MATLAB2010b для Mac довольно глючит.

%# fix wrong figure position in MATLAB2010b for Mac - depends on your layout
correctedPosition = get(gcf,'Position') + [21 -125 0 0];

fps = 60; sec = 10;

vidObj = VideoWriter('newfile.avi');
vidObj.Quality = 100;
vidObj.FrameRate = fps;

open(vidObj);
for i=1:fps*sec
  camorbit(0.9,-0.1);
  writeVideo(vidObj,getframe(gcf, correctedPosition));
end
close(vidObj);

EDIT2:

Я создал аналогичную тему в MATLAB Central .

EDIT3:

Можете попробовать сами скачав одну из моих фигур .

Ответы [ 3 ]

4 голосов
/ 02 декабря 2010

Я бы сказал, что именно большое количество точек, которые вы рисуете, вызывает замедление. Один из вариантов - уменьшить выборку. Также вы можете использовать низкоуровневые функции для рисования (отметьте этот связанный пост для сравнения производительности plot3 / scatter3 / line).

Рассмотрим приведенную ниже анимацию, оптимизированную для скорости:

[X Y Z] = sphere(64);
X = X(:); Y = Y(:); Z = Z(:);

%# set-up figure
hFig = figure('Backingstore','off', 'renderer','zbuffer');

%# use lower-level function LINE
line(0.50*[X,X], 0.50*[Y,Y], 0.50*[Z,Z], 'LineStyle','none', 'Marker','.', 'MarkerSize',1, 'Color','r')
line(0.75*[X,X], 0.75*[Y,Y], 0.75*[Z,Z], 'LineStyle','none', 'Marker','.', 'MarkerSize',1, 'Color','g')
line(1.00*[X,X], 1.00*[Y,Y], 1.00*[Z,Z], 'LineStyle','none', 'Marker','.', 'MarkerSize',1, 'Color','b')
view(3)

%# freeze the aspect ratio to override stretch-to-fill behaviour
axis vis3d

%# fix the axes limits manually
%#set(gca, 'xlim',[-1 1], 'ylim',[-1 1], 'zlim',[-1 1])
axis manual

%# maybe even remove the tick labels
%set(gca, 'xticklabel',[], 'yticklabel',[], 'zticklabel',[])

%# animate (until figure is closed)
while ishandle(hFig); camorbit(0.9,-0.1); drawnow; end

alt text

Обратите внимание, как мы используем Z-буфер рендерер и отключили свойство Backingstore .


EDIT:

Если я правильно понял, вы пытаетесь записать скринкаст (используя стороннее приложение), в то время как вы поворачиваете фигуру вручную, но в вашем случае эти ручные повороты «нервные». С другой стороны, анимация вашей фигуры с помощью CAMORBIT / VIEW в цикле while работает плавно ...

Я предлагаю альтернативное решение: начните с поворота фигуры с помощью мыши и запишите эти конфигурации вида на каждом шаге (азимут, высота). Затем вы можете воспроизвести их с помощью функции VIEW во время записи видео, например:

v = [...];   %# matrix where each row specify Az/El of view
for i=1:size(v,1)
    view( v(i,:) )
    drawnow
end

Недостатком является то, что вам придется нажимать / поворачивать / отпускать с помощью мыши небольшими шагами (объект ROTATE3D не отображает событие движения мыши)

Я написал простую функцию, чтобы помочь вам в этом процессе. Он загружает сохраненную фигуру, включает 3d-вращение и отслеживает промежуточное положение на каждом шаге. После завершения нажмите кнопку «Готово», чтобы вернуться к списку просмотров ...

function v = rotationDemo(figFileName)
    views = [];                     %# list of views (Az,El)

    hFig = hgload(figFileName);     %# load the saved figure

    views(1,:) = get(gca,'View');   %# store initial view

    %# add a button, used to terminate the process
    hButton = uicontrol('Style','pushbutton', 'Position',[400 1 80 20], ...
                        'String','Done?', 'Callback',@buttonCallback);
    set(hFig, 'Toolbar','figure')   %# restore toolbar

    %# start 3d rotation, and handle post-callback to record intermediate views
    h = rotate3d(hFig);             %# get rotation object
    set(h, 'ActionPostCallback',@rotateCallback)
    set(h, 'Enable','on')           %# enable rotation

    msgbox('Rotate the view step-by-step', 'rotate3d', 'warn', 'modal')

    uiwait(hFig)                    %# wait for user to click button
    delete(hButton)                 %# delete button on finish
    set(h, 'Enable','off')          %# disable rotation
    v = round(views);               %# return the list of views

    %# callback functions
    function rotateCallback(o,e)
        views(end+1,:) = get(e.Axes,'View');  %# add current view to list
    end
    function buttonCallback(o,e)
        uiresume(gcbf)                        %# uiresume(hFig)
    end
end

alt text

Вы можете вызвать вышеуказанную функцию, а затем воспроизвести анимацию:

v = rotationDemo('smooth_rotation.fig');
for i=1:size(v,1)
    view(v(i,:))
    drawnow
end

Мы можем сгладить переходы простой интерполяцией:

v = rotationDemo('smooth_rotation.fig');
n = size(v,1);
nn = linspace(1,n,100)';     %'# use 100 steps
vv = round( [interp1(v(:,1),nn) interp1(v(:,2),nn)] );
for i=1:size(vv,1)
    view(vv(i,:))
    DRAWNOW                  %# or PAUSE(..) to slow it down
end

В качестве примечания следует отметить, что ROTATE3D и CAMORBIT имеют разные эффекты. ROTATE3D изменяет свойство View текущей оси, в то время как CAMORBIT управляет свойствами камеры CameraTarget / CameraPosition / CameraUpVector текущей оси.

2 голосов
/ 03 декабря 2010

Я узнаю те же самые рывки, о которых вы говорите на обычном рисунке MATLAB. Но когда я попытался запустить код Amro, создал фильм (* .AVI), он также выглядит гладко на моем ноутбуке Mac.

Код создания фильма, который я использовал, следующий:

% Добавлено свойство «Видимый» фигуры «Выкл» при создании фильма (хотя я не совсем уверен, улучшит ли это ситуацию), например:

hFig = figure ('Backingstore', 'off', 'visible', 'off', 'renderer', 'zbuffer');

% Затем я заменил цикл Amro на простой производственный цикл AVI следующим образом:

aviobj = AVIFile ( 'test.avi'); % создает файл AVI

для I = 1: 360

camorbit (0,9, -0,1); drawnow;

aviobj = ADDFRAME (aviobj, hFig); % добавляет кадры в файл AVI

конец

* * Aviobj тысячи двадцать-три = близко (aviobj); % закрывает AVI файл

близко (hFig); % close hFig

Вопрос: Поможет ли это уменьшить некоторые точки или создать карту плотности перед рендерингом фигуры?

[Ref. на различные параметры рендеринга: http://www.mathworks.com/support/tech-notes/1200/1201.html]

Надеюсь, приведенные выше комментарии будут полезны.

1 голос
/ 02 декабря 2010

Я не знаю, поможет ли это вашей проблеме, но по какой-то причине у меня был больший успех с pause(0.001), чем drawnow, чтобы принудительно обновить графическое окно

Возможно, вытакже посмотрите, быстрее ли rotate3d.

Количество ядер не так важно, как вы думаете, так как многие функции в Matlab не поддерживают многопоточность.


Обходной путьбудет продолжаться, как вы сейчас, но запишите окно рисунка в файл фильма.Затем вы можете воспроизвести фильм.

...