8

If I try to rotate camera around my current figure with plot3 using

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

then the rotation periodically hangs for a while (example) even on 8-core MacPro.

Can I make it smooth?

EDIT1:

While there is no solution for my original question yet, I've managed to make a better movie with getframe function. It doesn't allow recording free-hand rotation, though, and is quite buggy in MATLAB2010b for 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:

I created a similar thread at MATLAB Central.

EDIT3:

You can try it yourself downloading one of my figures.

Andrew Whitaker
  • 124,656
  • 32
  • 289
  • 307
Andrei Fokau
  • 225
  • 1
  • 4
  • 11

3 Answers3

4

I would say it's the large number of points you are drawing that's causing the slowdown. One option is to downsample.. Also you could use lower-level functions to draw (check this related post for a comparison of plot3/scatter3/line performance).

Consider the animation below optimized for speed:

[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

Note how we are using the Z-buffer renderer, and turned off the Backingstore property.


EDIT:

If I understood correctly, what you are trying to do is to record a screencast (using a 3rd-party app), while you manually rotate the figure, but in your case these manual rotations are "jumpy". On the other animating your figure with CAMORBIT/VIEW in a while-loop is running smooth...

I propose an alternative solution: start by rotating the figure using the mouse and write these view configurations at each step (azimuth,elevation). Then you can replay them using the VIEW function while recording the video, something like:

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

The downside is that you will have to press/rotate/release using the mouse in small steps (the ROTATE3D object does not expose a mouse-motion event)

I wrote a simple function to help you in this process. It loads the saved figure, enable 3d-rotation, and keeps track of the intermediate position at each step. Once finished, press the "Done" button to return the list of views...

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

You can call the above function, then replay the animation:

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

We can smooth the transitions by simple interpolation:

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

As a side note, I should mention that ROTATE3D and CAMORBIT have different effects. ROTATE3D changes the View property of the current axis, while CAMORBIT controls the camera properties CameraTarget/CameraPosition/CameraUpVector of the current axis.

Community
  • 1
  • 1
Amro
  • 123,847
  • 25
  • 243
  • 454
  • According to the [documentation](http://www.mathworks.com/help/techdoc/ref/figure_props.html#DoubleBuffer): "Double buffering works only when the figure `Renderer` property is `painters`." – gnovice Dec 02 '10 at 20:31
  • looks like you are right, still OpenGL renderer is faster than painters.. Looks like `zbuffer` renderer is even faster in this case – Amro Dec 02 '10 at 20:38
  • @Amro, thanks for your very detailed answer! May be I am wrong, but it seems that with your suggestions the rotation is more smooth between hangings, however they still happen with the same duration! I cannot downsample the plot - it must be as it is now. – Andrei Fokau Dec 02 '10 at 21:45
  • 1
    @Andrei Fokau: Did you try LINE instead of PLOT3? I am certain it will give you a significant boost.. In the example above we are plotting around 12000 points, and its running very smooth on my 3-years old laptop. – Amro Dec 02 '10 at 22:00
  • @Amro, Yes, I have. The rotation still hangs. – Andrei Fokau Dec 02 '10 at 22:03
  • @Amro, My plot has 30240 points and I actually need a smooth rotation for up to 40k points. (I read your mind :) ) – Andrei Fokau Dec 02 '10 at 22:10
  • 1
    @Andrei Fokau: just to be clear, are you looking at the animation window directly or are you recording it to an AVI file and then experiencing the hangs (if so please comment that section of the code)? Because even with that many points, it was still smooth for me (no sudden jumps), but obviously running slower.. – Amro Dec 02 '10 at 22:37
  • @Amro, It hangs when I just rotate - either by hand, or by `camorbit()`. Making a movie was my initial purpose, and `getframe` allows making such movie with smooth rotation by camorbit. However, it doesn't help for free-hand rotation, which I would like to have. – Andrei Fokau Dec 03 '10 at 06:57
  • @Amro, I think there is a misunderstanding. I get the "jumps" with CAMORBIT as well. But I can record a movie frame-by-frame, so it won't look "freezing". Your last example is great! It allows to do such frame recording after a free-hand rotation. Thank you! I would still like to understand why I get such "jumps" while other guys don't (using the same figure). – Andrei Fokau Dec 04 '10 at 07:30
2

I recognize the same jerking movements that you are talking about on a regular MATLAB Figure. But when I tried running the Amro's code, created a movie (*.AVI), it looks smooth on my Mac notebook also.

The movie making code that I used is the following:

% Added the 'Visible' property of the figure 'off' while making a movie (although I am not exactly certain if this will make the situation better) like so:

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

% Then, I replaced Amro's while-loop with a simple AVI production loop, as follows:

aviobj=avifile('test.avi'); %creates AVI file

for I=1:360

camorbit(0.9,-0.1); drawnow;

aviobj=addframe(aviobj,hFig); %adds frames to the AVI file

end

aviobj=close(aviobj); %closes AVI file

close(hFig); %close hFig

Question: Would it help to decimate some points or to create a density map before rendering the figure?

[Ref. on various Rendering Options: http://www.mathworks.com/support/tech-notes/1200/1201.html ]

I hope the comments above would be of any help.

Y.T.
  • 200
  • 3
  • thanks for your example! I can make a smooth movie. The problem is that I can't record a smooth free-hand rotation (making movie by a third-party app). Could you try to rotate my example? http://goo.gl/LA1Cg – Andrei Fokau Dec 03 '10 at 07:15
  • 1
    Andrei, your example works smoothly on my Mac note. Could you create a movie by specifying the view-path for the entire length of the movie, e.g., by using: a loop, view(az,el), and pause? That way, you can create a smooth movie, hands off (don't forget to turn off the screen-saver while making a movie.) Or, if you had a MATLAB compiler, you would be able to compile the code into a standalone app. and allow user to interactively rotate the image. Lastly, I thought that it might be the 'AspectRatio' of the axes being not fixed, but your figure's fixed so that's not the case. Anyhow, Good Luck – Y.T. Dec 03 '10 at 19:02
1

I don't know if this will help your issue, but for some reason, I've had better success with pause(0.001) than drawnow to force an update of the graphics window

You might also see if rotate3d is faster.

The number of cores doesn't matter as much as you think, as many functions in matlab do not support multi-threading.


A workaround would be to proceed as you are now, but write the figure window to a movie file. Then you can play back the movie.

Marc
  • 5,315
  • 5
  • 30
  • 36
  • Thanks for your suggestions. I have tried them but it didn't change the behavior. – Andrei Fokau Dec 02 '10 at 21:34
  • Yes, I have just added this option to my question. There are some limitations in this approach, but it works. – Andrei Fokau Dec 02 '10 at 22:06
  • @Andrei - one last thing to try is to resize the figure window. I sometimes have pauses when the window is maximized that I don't have when it's the default size. – Marc Dec 02 '10 at 22:12
  • Yes, I have tried this, however nothing really changes until a very tiny figure. – Andrei Fokau Dec 02 '10 at 22:15