代码之家  ›  专栏  ›  技术社区  ›  Hojo.Timberwolf

加速动画

  •  3
  • Hojo.Timberwolf  · 技术社区  · 8 年前

    gpuarray parfor 循环,我可以更新图上的许多变量,但显然情况并非如此,当这些函数解析图时,图的句柄会丢失连接。有没有其他方法可以改进和加速动画。我将附上我的代码并简要解释。我还将附上2个礼物,显示我正在努力做什么。

    cellfun 或对位置数据进行其他计算密集型计算,然后覆盖对象的位置数据。

    classdef StimBud<handle
    properties
        Window                                                              % holds figure
        ObjectList                                                          % holds object handles
        ObjectTransformation                                                % holds object transformation
        ObjectLocX
        ObjectLocY
        ObjectRotation
    end
    methods
        function gh = StimBud()  
        end
        function buildobjects(gh,numofObj)
            gh.Window = figure('MenuBar','none', ...                        % Build Window for stimulus
                'Color',[0,0,0]);
    
            for aa = 1:numofObj
            gh.ObjectTransformation{aa} = hgtransform;                   % Add object to end of transformation list
            gh.ObjectList{aa} = patch(...                                   % Add object to end of Object list, bind to transformation list
                    'Parent', gh.ObjectTransformation{aa}, ...   
                    'XData',[0,0,1,1], 'YData',[0,1,1,0],...
                    'Facecolor', [1,1,0], 'EdgeColor', [1,1,0], ...
                    'visible','on');
            end
    
            % define transforamtion and position variables
            parse = 360/numofObj;
            rotationcalculation = 0;
            XData = repmat(10,1,numofObj);
            YData = zeros(1,numofObj); 
    
            TmpXdata = cell(numofObj,1);                                    % container to hold all X location data
            TmpRot = zeros(numofObj,1);                                     % container to hold the Rotation data
            TmpYdata = cell(numofObj,1);                                    % container to hold all Y location data
    
            % Adjust position & rotation of all available objects
    
            for aa = 1:numofObj
                % Rotate objects to change direction of movement
                gh.ObjectTransformation{aa}.Matrix = makehgtform('zrotate',(deg2rad(aa*parse)+rotationcalculation));
    
                % move object to proper position
                gh.ObjectList{aa}.XData = gh.ObjectList{aa}.XData + XData(aa);
                gh.ObjectList{aa}.YData = gh.ObjectList{aa}.YData + YData(aa);
    
                TmpXdata{aa} = gh.ObjectList{aa}.XData;
                TmpYdata{aa} = gh.ObjectList{aa}.YData;
                TmpRot(aa) = (deg2rad(aa*parse)+rotationcalculation);
            end
    
            % store variable out of objects for threading
            gh.ObjectLocX = TmpXdata;
            gh.ObjectLocY = TmpYdata;
            gh.ObjectRotation = TmpRot;
        end
        function RunStim(gh)
            figure(gh.Window);
            TrialLength = 10;                                               % Length of trial to be run
            Framerate = 60; 
            ObjSpeed = 10;
    
            % pull variables into function
            ObjList = gh.ObjectList;
            ObjLocX = gh.ObjectLocX;
            ObjLocY = gh.ObjectLocY;
            ObjRotation = gh.ObjectRotation;
    
            NumofObj = length(ObjList);                                     % Number of Objects in stim system
    
            timer = tic();                                                  % Timer for the stimulus
    
            moveforward = .03*.1*ObjSpeed;                                  % Distance to move in figure
    
            while toc(timer) < TrialLength                                  % Run stimulus through length of project
                NextStepX = cellfun(@(x) x+moveforward,ObjLocX);
                NextStepY = cellfun(@(x) x+moveforward,ObjLocY);
                NextRot = ObjRotation + moveforward;
    
                for aa = 1:NumofObj  %% parfor does not work here %%
                        ObjList{aa}.XData = NextStepX{aa};
                end
    
                ObjLocX = NextStepX;                                        % Update X location matrix for next step
                ObjLocY = NextStepY;                                        % Update Y location matrix for next step
                ObjRotation = NextRot;                                      % Update Rotation matrix for next step
    
                pause(1/Framerate)                                          % Pause window briefly to allow for drawing
            end
        end
    end
    end
    

    要创建动画:

    s = StimBud;
    s.buildobjects(5)
    s.RunStim
    

    这个GIF显示了我用上面的代码构建的一个动画,上面有5个对象。即使我在使用for循环,它在显示和动画方面也很快。

    enter image description here

    下面是当我增加对象数量时会发生的情况(由于for循环,这一点非常明显)。动画的速度会大大减慢,不像平滑的那样慢,并且移动的距离与对象较少的动画不同。

    enter image description here

    我希望使用多线程来纠正这个问题,但这似乎不是一个可行的选择(至少从我所学到的)。如何在MATLAB图形中改进动画?我是不是想错了,不应该用 figure

    1 回复  |  直到 8 年前
        1
  •  3
  •   Dev-iL    8 年前

    您的方法的主要问题是您的代码忽略了以下事实 . 因此,您设置的帧速率不是实际的帧速率,我将使用 profiler :

    Profiler output for n = 100

    8.57 sec和not 350*1/60 = 5.83 ,增加 将近50%

    这就是为什么我认为最好的方法是 适应的

    % same as yours until line 72 including
    
        tmp = [ObjList{:}];
        skipNext = 0;
        while true                                          % Run stimulus through length of project
            t1 = toc(timer);
            if t1 >= TrialLength, break; end
            NextStepX = cellfun(@(x) x+moveforward, ObjLocX, 'UniformOutput', false);
            NextStepY = cellfun(@(x) x+moveforward, ObjLocY, 'UniformOutput', false);
            NextRot = ObjRotation + moveforward;
    
            if ~skipNext
              [tmp.XData] = NextStepX{:};
            end
    
            ObjLocX = NextStepX;                            % Update X location matrix for next step
            ObjLocY = NextStepY;                            % Update Y location matrix for next step
            ObjRotation = NextRot;                          % Update Rotation matrix for next step
            t2 = toc(timer);
            if t2-t1 < max(1,skipNext)/Framerate
              % if we have some time left, update the plot
              drawnow;
              skipNext = 0;
              % if we still have time left, increase the framerate and wait
              t = 1/Framerate - (toc(timer) - t1);
              if t > 0
                Framerate = Framerate * 1.1;
                java.lang.Thread.sleep( 1E3 * t );
              end
            else
              skipNext = skipNext + 1;
              Framerate = Framerate * 0.75;
              disp("Frame skipped!");
            end
            disp("Framerate is now: " + Framerate);
        end
    

    这还包括一些日志记录来显示帧速率的变化。在我的系统上,因为 n=10 最终的结果是 227.85 ,用于 n=50 是的 72.6 ,用于 n=1000 是的 18.98 ,等等。虽然在最后一种情况下动画不平滑,但至少它看起来没有卡住。

    line 或者 scatter 使用一些大的正方形标记(这会模拟正方形块,但速度要快得多)。如果这些不适合你的使用,我只想说这些是MATLAB的局限性,你可能想看看一些专用的图形库,虽然我不是这些方面的专家,所以我不能建议一个不幸的。

    请注意我是如何更新坐标的,而不是你的 for

    [tmp.XData] = NextStepX{:};