两个图像的多重融合动画

阿图尔杰夫

我有两个图像:
bg Image1和overlay Image2(其高度大于bg image1)

现在,我需要使用混合模式乘法将[Image2]放在[Image1]上。但是之后,我需要为Image2的Y位置设置动画,但保持混合模式,以便获得如下所示的动画:https : //www.youtube.com/watch?v=D4Gqm9_Eo68

那么我该如何实现呢?
可能我应该使用OpenGL吗?如果是,那又如何呢?

光谱

我没有为IOS编写代码,也没有为您正在编写的平台提供任何线索(内存,速度,gfx功能)。从您的问题中我得到的印象是您没有渲染的线索,也没有动画部分...

  1. 最简单的方法是自己编码

    如果您可以访问像素,则仅需要2个嵌套的循环就可以将纹理的像素复制/合并到目标颜色。我通常使用GDIBitmap->ScanLine[]但是如上所述,如果您在IOS上有类似的东西,我不知道。

  2. 的OpenGL

    因为您没有OpenGL经验,所以我不建议您使用GLSL,因为从一开始它就太多了。甚至对于我来说,设置OpenGL环境和解释OpenGL程序如何工作之类的东西都太长了(而且我习惯于冗长的回答)。因此,无论如何,我都会跳过该步骤(您需要为其添加一些教程),请参见:

    因为这需要MultiTexturing,所以您还需要该扩展名(至少我认为这些扩展本机不在OpenGL 1.0中)。我建议对它使用GLEW之类的lib或其他工具。

    这个想法是一次渲染具有2个纹理的四边形(矩形),如下所示:

    影响

    The Quad Vertex coordinates are fixed (dependend on screen and image resolution/aspect ratio). Texture0 is also fixed And Texture1 has fixed one axis and the second is changing... where:

    • t is the animation parameter t=<0,1>
    • T is used gradient chunk size T<1.0

    The animation is done by changing t by some small step each frame for example increment and wrap around or use sinus...

    You need to remember that standard OpenGL knows only power of 2 textures so you need to resize/crop/resample your textures to match this criteria. I do this like this:

    Also you need to handle aspect ratio difference between your App OpenGL screen and image ... I used a short cut so the OpenGL view is square and the image is resized to square too.

    Now when using MultiTexturing you need to properly set up the Texture combiners to match your needs. It has been ages I used that so I do not remember it at all and too lazy to study that again as I use GLSL now ...

    Luckily it looks like that default OpenGL settings of this do just what you want. So here some C++/VCL based code (without the OpenGL environment setup which is platform dependent):

    //---------------------------------------------------------------------------
    const int _txrs=2;              // max number of textures
    GLuint  txrid[_txrs],txrids=0;  // texture ids
    GLfloat t=0.0,T=0.1,dt=0.1;     // animation texture coordinates
    
    void init()
        {
        glGenTextures(_txrs,txrid);
    
        // textures
        Byte q;
        unsigned int *pp;
        int xs,ys,x,y,adr,*txr;
        union { unsigned int c32; Byte db[4]; } c;
        Graphics::TBitmap *bmp=new Graphics::TBitmap;   // new bmp
    
        // image texture
        bmp->LoadFromFile("effect_image.bmp");  // load from file
        bmp->HandleType=bmDIB;      // allow direct access to pixels
        bmp->PixelFormat=pf32bit;   // set pixel to 32bit so int is the same size as pixel
        xs=bmp->Width;              // resolution should be power of 2
        ys=bmp->Height;
        txr=new int[xs*ys];         // create linear framebuffer
        for(adr=0,y=0;y<ys;y++)
            {
            pp=(unsigned int*)bmp->ScanLine[y];
            for(x=0;x<xs;x++,adr++)
                {
                // rgb2bgr and copy bmp -> txr[]
                c.c32=pp[x];
                q      =c.db[2];
                c.db[2]=c.db[0];
                c.db[0]=q;
                txr[adr]=c.c32;
                }
            }
        glEnable(GL_TEXTURE_2D);    // copy it to gfx card
        glBindTexture(GL_TEXTURE_2D,txrid[txrids]); txrids++;
        glPixelStorei(GL_UNPACK_ALIGNMENT, 4);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S,GL_CLAMP);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T,GL_CLAMP);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER,GL_LINEAR);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER,GL_LINEAR);
        glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE,GL_MODULATE);
        glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, xs, ys, 0, GL_RGBA, GL_UNSIGNED_BYTE, txr);
        glDisable(GL_TEXTURE_2D);
        delete[] txr;
    
        // gradient texture
        bmp->LoadFromFile("effect_mask.bmp");   // load from file
        bmp->HandleType=bmDIB;      // allow direct access to pixels
        bmp->PixelFormat=pf32bit;   // set pixel to 32bit so int is the same size as pixel
        xs=bmp->Width;              // resolution should be power of 2
        ys=bmp->Height;
        txr=new int[xs*ys];         // create linear framebuffer
        for(adr=0,y=0;y<ys;y++)
            {
            pp=(unsigned int*)bmp->ScanLine[y];
            for(x=0;x<xs;x++,adr++)
                {
                // rgb2bgr and copy bmp -> txr[]
                c.c32=pp[x];
                q      =c.db[2];
                c.db[2]=c.db[0];
                c.db[0]=q;
                txr[adr]=c.c32;
                }
            }
        glEnable(GL_TEXTURE_2D);    // copy it to gfx card
        glBindTexture(GL_TEXTURE_2D,txrid[txrids]); txrids++;
        glPixelStorei(GL_UNPACK_ALIGNMENT, 4);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S,GL_CLAMP);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T,GL_CLAMP);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER,GL_LINEAR);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER,GL_LINEAR);
        glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE,GL_MODULATE);
        glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, xs, ys, 0, GL_RGBA, GL_UNSIGNED_BYTE, txr);
        glDisable(GL_TEXTURE_2D);
        delete[] txr;
        T=0.4;                      // 40% of gradient height cover the whole image
        dt=0.015*T;                 // animation step 1.5% of image
    
        delete bmp;
        }
    //---------------------------------------------------------------------------
    void TForm1::ogl_draw()
        {
        // clear buffers
        glClearColor(0.0,0.0,0.0,0.0);
        glClear(GL_COLOR_BUFFER_BIT);
    
        // unit matrices ... no projections ... so view is just <-1,+1>
        glMatrixMode(GL_PROJECTION);
        glLoadIdentity();
        glMatrixMode(GL_MODELVIEW);
        glLoadIdentity();
        glMatrixMode(GL_TEXTURE);
        glLoadIdentity();
    
        glDisable(GL_DEPTH_TEST);   // no Z-buffer for 2D
        glDisable(GL_CULL_FACE);    // no strict polygon winding
        glDisable(GL_TEXTURE_2D);
        // bind textures
        glActiveTexture(GL_TEXTURE1); glEnable(GL_TEXTURE_2D); glBindTexture(GL_TEXTURE_2D,txrid[1]);
        glActiveTexture(GL_TEXTURE0); glEnable(GL_TEXTURE_2D); glBindTexture(GL_TEXTURE_2D,txrid[0]);
        glColor3f(1.0,0.0,1.0);
        // render QUAD
        glColor3f(1.0,1.0,1.0);
        GLfloat t0=t,t1=t+T;
    
        glBegin(GL_QUADS);
        glMultiTexCoord2f(GL_TEXTURE0,0.0,0.0);
        glMultiTexCoord2f(GL_TEXTURE1,0.0,t0);
        glVertex3f(-1.0,+1.0,0.0);
        glMultiTexCoord2f(GL_TEXTURE0,0.0,1.0);
        glMultiTexCoord2f(GL_TEXTURE1,0.0,t1);
        glVertex2f(-1.0,-1.0);
        glMultiTexCoord2f(GL_TEXTURE0,1.0,1.0);
        glMultiTexCoord2f(GL_TEXTURE1,1.0,t1);
        glVertex2f(+1.0,-1.0);
        glMultiTexCoord2f(GL_TEXTURE0,1.0,0.0);
        glMultiTexCoord2f(GL_TEXTURE1,1.0,t0);
        glVertex2f(+1.0,+1.0);
        glEnd();
    
        // unbind textures so it does not mess any rendering after this (texture unit 0 at the end !!!)
        glActiveTexture(GL_TEXTURE1); glDisable(GL_TEXTURE_2D); glBindTexture(GL_TEXTURE_2D,0);
        glActiveTexture(GL_TEXTURE0); glDisable(GL_TEXTURE_2D); glBindTexture(GL_TEXTURE_2D,0);
    
        // force to render qued OpenGL rendering and swap double buffers
        glFlush();
        SwapBuffers(hdc);   // this is platform dependend !!!
        }
    //---------------------------------------------------------------------------
    void __fastcall TForm1::Timer1Timer(TObject *Sender)
        {
        ogl_draw();
        t+=dt;  // step the animation
        if ((dt>0.0)&&(t+T>1.0)) { t=1.0-T; dt=-dt; } // handle if hit top
        if ((dt<0.0)&&(t  <0.0)) { t=0.0; dt=-dt; }  // handle if hit bottom
        }
    //---------------------------------------------------------------------------
    

    As you can see it is quite a bit of code. If you use some lib to load textures and handle stuff most of it will go away (I use mine engine for this so it took mi while to get the pieces together again so it is usable standalone without lib). Do not forget to init GLEW or whatever to get access to MultiTexturing ...

This is simple VCL single form app with single timer in it (interval=20ms).

  • init() just allocates space for textures in gfx card and load the images to it.
  • ogl_draw() renders the effect of yours ...
  • Timer1Timer(TObject *Sender) is called on each timer event and just force to render frame and update animation ... it goes up through the gradient and then down ...

    This is the result:

    结果

    Of coarse it is animated but I am to lazy to catch a video of this...

[edit1]

这里链接下载整个BDS2006项目下载

本文收集自互联网,转载请注明来源。

如有侵权,请联系 [email protected] 删除。

编辑于
0

我来说两句

0 条评论
登录 后参与评论

相关文章