两个图像的多次混合的动画

时间:2015-11-26 11:46:04

标签: ios opengl image-processing textures blending

我有两张图片:
bg Image1和叠加Image2(高度大于bg image1)

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

那我怎么能实现呢? 可能我应该使用OpenGL?如果是,那究竟是怎么回事?

2 个答案:

答案 0 :(得分:2)

我不编码 IOS ,并且不知道您编写的平台(内存,速度,gfx功能)。从你的问题我得到的印象是你不知道渲染和动画部分......

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

    如果你有像素访问那么只需要2个嵌套for循环复制/组合纹理像素到目标颜色。我通常使用 GDI Bitmap->ScanLine[],但如上所述,如果您在IOS上有类似内容,我不知道。

  2. <强>的OpenGL

    由于您没有 OpenGL 经验,因此我不建议使用 GLSL ,因为从一开始就可能太多了。设置 OpenGL 环境和解释 OpenGL 程序如何工作的事情对我来说太长了(我习惯了很长的答案)。所以我会跳过它(你需要谷歌一些教程),无论如何看看:

    由于这需要MultiTexturing,您还需要该扩展(至少我认为那些不在 OpenGL 1.0 本机)。我建议使用lib作为 GLEW 或其他任何东西。

    这个想法是一次渲染带有2个纹理的四边形(矩形):

    effect

    Quad Vertex坐标是固定的(取决于屏幕和图像分辨率/宽高比)。 Texture0也是固定的,而Texture1固定了一个轴,第二个正在改变......其中:

    • t是动画参数t=<0,1>
    • T使用渐变块大小T<1.0

    动画是通过每帧改变t一小步来完成的,例如增量和环绕或使用正弦......

    您需要记住,标准OpenGL只知道2个纹理的强大功能,因此您需要调整/裁剪/重新采样纹理以符合此条件。我是这样做的:

    此外,您需要处理App OpenGL 屏幕和图像之间的宽高比差异...我使用了快捷方式,因此 OpenGL 视图是正方形,图像也调整为正方形。

    现在使用 MultiTexturing 时,您需要正确设置纹理合并器以满足您的需求。这已经是我用过的年龄了,所以我根本不记得它,而且因为我现在使用GLSL而再懒得研究......

    幸运的是,它的默认 OpenGL 设置看起来就像你想要的那样。所以这里有一些基于 C ++ / VCL 的代码(没有依赖于平台的 OpenGL 环境设置):

    //---------------------------------------------------------------------------
    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
        }
    //---------------------------------------------------------------------------
    

    正如您所看到的,它是相当多的代码。如果你使用一些lib来加载纹理并处理其中的大部分内容都会消失(我使用我的引擎就这样,所以需要花费几分钟才能将这些部分再次组合在一起,所以它可以单独使用而不用lib)。不要忘记初始化 GLEW 或其他什么来访问 MultiTexturing ......

  3. 这是一个简单的VCL单一表单应用程序,其中包含单个计时器(interval=20ms)。

    • init()只需在gfx卡中为纹理分配空间并将图像加载到它。
    • ogl_draw()会影响你的效果......
    • Timer1Timer(TObject *Sender)在每个计时器事件上被调用,只是强制渲染帧并更新动画......它通过渐变然后向上...

      结果如下:

      result

      粗略的它是动画但我懒得看到这个视频...

    <强> [EDIT1]

    此处链接下载整个BDS2006项目download

答案 1 :(得分:0)

您需要的是:

- drawInRect:blendMode:alpha: