首页 文章

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

提问于
浏览
0

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

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

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

2 回答

  • 2

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

    • the easiest way would be encode it yourself

    如果你得到 pixel access 那么它就是2个嵌套for循环复制/组合纹理像素到目标颜色的问题 . 我通常使用 GDIBitmap->ScanLine[] ,但如上所述我不知道你在IOS上有类似的东西 .

    • OpenGL

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

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

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

    effect

    四边形顶点坐标是固定的(取决于屏幕和图像分辨率/纵横比) . 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) . 不要忘记init GLEW 或其他什么来访问 MultiTexturing ...

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

    • init() 只需在gfx卡中为纹理分配空间并将图像加载到它 .

    • ogl_draw() 呈现你的效果......

    • Timer1Timer(TObject *Sender) 在每个计时器事件上被调用,只是强制渲染帧并更新动画......它通过渐变向下然后向下...

    这是结果:

    result

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

    [edit1]

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

  • 0

    你需要的是:

    - drawInRect:blendMode:alpha:
    

相关问题