【问题标题】:Text Animation with MATLAB使用 MATLAB 制作文本动画
【发布时间】:2014-12-30 07:37:40
【问题描述】:

我的简化问题是为 3D 绘图上的一些文本设置动画。

我有一个立方体,

vert = [1 1 0;0 1 0;0 1 1;1 1 1;0 0 1;1 0 1;1 0 0;0 0 0];
fac =  [1 2 3 4; 4 3 5 6; 6 7 8 5; 1 2 8 7; 6 7 1 4; 2 3 5 8];
patch('Faces',fac,'Vertices',vert,'FaceColor',[.8 .5 .2]); 
axis([0, 1, 0, 1, 0, 1]);
axis equal
axis off

有没有可能得到这样的东西?

使用text 没有帮助(它看起来很假!),

谢谢,

【问题讨论】:

    标签: image matlab animation text 3d


    【解决方案1】:

    我有一个解决方案,使用texture mapping 可以正常显示。

    这个想法是将图像应用到面部,让 Matlab 处理其他所有事情。最大的好处是matlab会照顾到所有的透视方面,而且渲染效果还不错。小缺点是您只能将纹理应用于surface 对象,并且由于您需要 6 个不同的图像,因此您必须管理 6 个不同的表面。

    下面的代码显示了如何做到这一点的示例:

    %% // read faces images
    idxFaces = [1 2 3 4 5 6] ;
    for iface = idxFaces
        imgface{iface} = imread( ['E:\ICONS\number_blue_' num2str(iface) '-150x150.png'] ) ;
    end
    
    %% // Define cube properties
    cubeLenght = 1 ;
    x = linspace(-cubeLenght/2,cubeLenght/2,21) ;
    [X,Y] = meshgrid(x,x) ;
    Zp = ones(size(X))*cubeLenght/2 ; Zm = Zp-cubeLenght ;
    
    %// draw face surfaces (organised 2 by 2)
    hcubeface(1) = surf(X,Y,Zp ,'CData',imgface{1},'FaceColor','texturemap','LineStyle','none') ; hold on
    hcubeface(6) = surf(X,Y,Zm ,'CData',imgface{6},'FaceColor','texturemap','LineStyle','none') ;
    
    hcubeface(2) = surf(X,Zp,Y ,'CData',imgface{2},'FaceColor','texturemap','LineStyle','none') ;
    hcubeface(5) = surf(X,Zm,Y ,'CData',imgface{5},'FaceColor','texturemap','LineStyle','none') ;
    
    hcubeface(3) = surf(Zp,X,Y ,'CData',imgface{3},'FaceColor','texturemap','LineStyle','none') ;
    hcubeface(4) = surf(Zm,X,Y ,'CData',imgface{4},'FaceColor','texturemap','LineStyle','none') ;
    
    axis square
    axis off
    

    这将呈现下图:

    抱歉,我拍摄了第一张可用的实际图像。您必须生成一个漂亮的立方体面图像,然后如上所示应用它们。

    如果你用图形交互工具旋转你的立方体,你就没有问题。
    如果你想以编程方式旋转它,你有两个选择:

    • 如果对象是唯一显示的对象,那么最简单的方法是只移动视点(使用view 或其他相机操作功能)。

    • 如果您有多个对象并且只想旋转立方体,则必须单独旋转每个表面。在这种情况下,我建议编写一个辅助函数,它会在给定角度和方向的情况下为您旋转 6 个面。 一个更简洁的方法是让你的立方体在一个类中管理,然后添加一个方法来旋转它(在内部它将旋转 6 个面)。


    编辑:只是为了好玩,下面的 sn-p 将为您的骰子设置动画(不是最漂亮的方式,但它向您展示了上面第一个选项的示例)。

    %% // animate by changing point of view
    azi = linspace(-180,180,100) ;
    for iv =1:100
        view(azi(iv),azi(iv)+randi(5))
        pause(0.01)
    end
    view(45,45)
    

    运行这个方块来看看你的骰子跳舞;)


    编辑(再次)
    这是一个关于如何通过旋转对象本身来为立方体对象设置动画的示例

    %% // animate by rotating the object
    
    %// this is necessary because the first rotation reset the axes to shading interp
    rotate(hcubeface , [0 1 1] , 0.5)
    for iface = 1:6 ; set( hcubeface(iface) , 'CData',imgface{iface}, 'FaceColor','texturemap' ) ; end
    
    %// after that, no need to reset the texture map, enjoy as many rotations as you like
    for iv =1:360
        axerot = rand(1,3) ;                % // pick a random axis to rotate around
        rotate(hcubeface , axerot , 0.5)    %// rotate the 6 faces by 0.5 degrees
        pause(0.01)
    end
    

    请注意,我修改了立方体的定义,以便将所有面表面句柄放在一个数组中。这允许通过发送句柄数组作为参数一次性将rotate 命令应用于所有表面。

    【讨论】:

    • 不确定是否值得您努力,但动画 GIF 可能非常适合这些解决方案。一个指针 - mathworks.com/matlabcentral/answers/… 另外,只是好奇为什么数字看起来是倒置的,我猜还是我看的角度不对?
    • @Divakar。是的,如果最终结果是一个始终相同的简单动画,那么动画 GIF 将完美运行。虽然我猜你可能想要 6 个不同的 GIF 来显示最终数字,如果它是用于游戏或动画随机掷骰子。由于默认视角,数字是倒置的,我没有费心旋转它或翻转图像数据。显然,代码需要进行一些调整才能获得更好的最终结果。
    • @Kamtal,我再次编辑。我改进了立方体定义,并使用第二个选项添加了动画解决方案。根据您想要做什么,您可以通过此方法获得更多控制,而不仅仅是改变视角。
    【解决方案2】:

    这个想法是使用纹理映射作为@Hoki showed。我试图最终实现这一点,这就是我想出的。

    首先,我们需要 6 张图像应用到立方体面上。这些可以是任何大小的任何随机图像。例如:

    % just a bunch of demo images from IPT toolbox
    function imgs = get_images()
        imgs = {
            imread('autumn.tif');
            imread('coloredChips.png');
            imread('toysflash.png');
            imread('football.jpg');
            imread('pears.png');
            imread('peppers.png');
        };
    end
    

    更好的是,让我们使用 online service 返回包含数字 1 到 6 的占位符图像:

    % online API for placeholder images
    function imgs = get_images()
        imgs = cell(6,1);
        clr = round(255*brighten(lines(6),0.75));
        for i=1:6
            %bg = randsample(['0':'9' 'a':'f'], 6, true);
            %fg = randsample(['0':'9' 'a':'f'], 6, true);
            bg = strjoin(cellstr(dec2hex(clr(i,:))).', '');
            fg = strjoin(cellstr(dec2hex(clr(7-i,:))).', '');
            [img,map] = imread(sprintf(...
                'http://placehold.it/100x100/%s/%s&text=%d', bg, fg, i));
            imgs{i} = im2uint8(ind2rgb(img,map));
        end
    end
    

    这是生成的图像:

    >> imgs = get_images();
    >> montage(cat(4,imgs{:}))
    

    接下来让我们创建一个函数来渲染一个单位立方体,并将图像纹理映射为面:

    function h = get_unit_cube(imgs)
        % we need a cell array of 6 images, one for each face (they can be any size)
        assert(iscell(imgs) && numel(imgs)==6);
    
        % coordinates for unit cube
        [D1,D2,D3] = meshgrid([-0.5 0.5], [-0.5 0.5], 0.5);
    
        % texture mapped surfaces
        opts = {'FaceColor','texturemap', 'EdgeColor','none'};
        h = zeros(6,1);
        h(6) = surface(D1, flipud(D2), D3, imgs{6}, opts{:});           % Z = +0.5 (top)
        h(5) = surface(D1, D2, -D3, imgs{5}, opts{:});                  % Z = -0.5 (bottom)
        h(4) = surface(fliplr(D1), D3, flipud(D2), imgs{4}, opts{:});   % Y = +0.5 (right)
        h(3) = surface(D1, -D3, flipud(D2), imgs{3}, opts{:});          % Y = -0.5 (left)
        h(2) = surface(D3, D1, flipud(D2), imgs{2}, opts{:});           % X = +0.5 (front)
        h(1) = surface(-D3, fliplr(D1), flipud(D2), imgs{1}, opts{:});  % X = -0.5 (back)
    end
    

    这是它的样子:

    imgs = get_images();
    h = get_unit_cube(imgs);
    view(3), axis vis3d, rotate3d on
    


    现在我们可以通过创建有趣的动画获得一些乐趣。考虑以下几点:

    % create two separate unit cubes
    figure('Renderer','OpenGL')
    h1 = get_unit_cube(get_images());
    h2 = get_unit_cube(get_images());
    set([h1;h2], 'FaceAlpha',0.8)         % semi-transparent
    view(3), axis vis3d off, rotate3d on
    
    % create transformation objects, used as parents of cubes
    t1 = hgtransform('Parent',gca);
    t2 = hgtransform('Parent',gca);
    set(h1, 'Parent',t1)
    set(h2, 'Parent',t2)
    
    % transform the second cube (scaled, rotated, then shifted)
    M = makehgtform('translate', [-0.7 1.2 0.5]) * ...
        makehgtform('yrotate', 15*(pi/180)) * ...
        makehgtform('scale', 0.5);
    set(t2, 'Matrix',M)
    
    drawnow
    axis on, axis([-2 2 -2 2 -0.7 1]), box on
    xlabel x, ylabel y, zlabel z
    
    % create animation by rotating cubes 5 times
    % (1st rotated around z-axis, 2nd around its own z-axis in opposite
    %  direction as well as orbiting the 1st)
    for r = linspace(0,10*pi,90)
        R = makehgtform('zrotate', r);
        set(t1, 'Matrix',R)
        set(t2, 'Matrix',R\(M/R))
        pause(0.1)
    end
    

    我正在使用hgtransform 函数来管理转换,这是much more efficient,而不是不断更改图形对象的 x/y/z 数据点。

    顺便说一句,我在上面的动画中使用了稍微不同的图像。


    编辑:

    让我们用映射到球体上的地球图像替换旋转的立方体。首先这里有两个函数来渲染球体(我从 MATLAB 文档中的 these examples 借用代码):

    get_earth_sphere1.m

    function h = get_earth_sphere1()
        % read images of planet earth
        earth = imread('landOcean.jpg');
        clouds = imread('cloudCombined.jpg');
    
        % unit sphere with 35x35 faces
        [X,Y,Z] = sphere(35);
        Z = flipud(Z);
        a = 1.02;
    
        % render first sphere with earth mapped onto the surface,
        % then a second transparent surface with clouds layer
        if verLessThan('matlab','8.4.0')
            h = zeros(2,1);
        else
            h = gobjects(2,1);
        end
        h(1) = surface(X, Y, Z, earth, ...
            'FaceColor','texturemap', 'EdgeColor','none');
        h(2) = surface(X*a, Y*a, Z*a, clouds, ...
            'FaceColor','texturemap', 'EdgeColor','none', ...
            'FaceAlpha','texturemap', 'AlphaData',max(clouds,[],3));
    end
    

    get_earth_sphere2.m

    function h = get_earth_sphere2()
        % load topographic data
        S = load('topo.mat');
        C = S.topo;
        cmap = S.topomap1;
        n = size(cmap,1);
    
        % convert altitude data and colormap to RGB image
        C = (C - min(C(:))) ./ range(C(:));   % scale to [0,1]
        C = ind2rgb(round(C*(n-1)+1), cmap);  % convert indexed to RGB
    
        % unit sphere with 50x50 faces
        [X,Y,Z] = sphere(50);
    
        % render sphere with earth mapped onto the surface
        h = surface(X, Y, Z, C, ...
            'FaceColor','texturemap', 'EdgeColor','none');
    end
    

    动画脚本与之前类似(略有改动),不再赘述。结果如下:

    (这次我用的是new graphics system in R2014b

    【讨论】:

    • 非常感谢,太好了。
    • gif 就值得+1!
    • 哇哦。灿烂!还有关于hgttransform 的重要提示。 (现在我想要一个完整的太阳系)。
    • @Hoki。谢谢。看我的编辑,希望你喜欢;)在我的宇宙中,地球围绕着一个更大的地球转,谁需要太阳!
    猜你喜欢
    • 2021-07-26
    • 1970-01-01
    • 1970-01-01
    • 2014-12-26
    • 1970-01-01
    • 2022-01-22
    • 2014-09-16
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多