变形动画算法——你中有我 我中有你

题目:牛郎织女互变(渐变动画),可以是图形方式,也可以是图像方式


效果

image.png

一、方法

根据变形动画三种:直接变形、间接变形、渐变技术,显然我们需要实现渐变技术
渐变又划分成三种实现方式:坐标网格法、特征值、3d轴向切片,很明显,此类图像渐变采取坐标网格法。
根据课程实例:

渐变

坐标网格法:


坐标网格法
实例

我们最终绘制图像时,所用的方法依然是线性插值。这时候考虑三种插值方法,有两种可以使用:

  1. 基于形状插值
  2. 基于颜色插值
1.基于形状

先说说基于形状插值实现的渐变。最终效果是一个实色的形状变成另一个形状
实现步骤:

  1. 对牛郎、织女分别生成变形工具
    -计算人物(非透明区域)最大x、y
    -计算一个包括人物的矩形
    -均匀划分x、y,形成网格
  2. 每个网格单元记录包含的顶点:网格内,若像素pixel有颜色则为true,透明则为false
  3. 每个网格单元对应一个二位数组:所有有颜色的顶点
    当前拥有2个图像imag[2],分别对应数个grids_A[],且网格单元数量一致,每个网格单元对应数个array[][],二维数组的数量也一致。
  4. 最后对每组二维数组进行插值运算

此法重点在于第2步,找出所有顶点的位置,我们可以做完之后再贴纹理
可能会用到GLSL的内置函数,也没了解这样的函数,所以没采用此法。

此外又不得不提的是,上述坐标网格法提到了五张图片I1、I2、Is、It和If,而这里只用到了三张图片。是因为网格法为了让人物五官对准,渐变的效果更好,而这里并没设计人物的五官,所以用两张图片和生成的中间帧就可以。

2.基于颜色

我们同样可以使用颜色插值的方法,这样最终将是淡入淡出的效果。

而且我们之前已经了解到了在fragment shader中的mix函数便是对纹理进行插值的,所以采用此法!

将整张图片看成一个网格单元,这样不用做繁琐的变形工具约束,也不用记录顶点(记录顶点是为了做插值,我们有mix函数做插值)

  1. 前期需要接着上次实验,再做一张牛郎和织女的png,并且改变方向,调至合理处(为了使用颜色插值)。
  2. 插值计算

二、代码

    glUseProgram(myShaderBack->ID);
    glUniform1i(glGetUniformLocation(myShaderBack->ID, "texture0"), 0);
    glUniform1i(glGetUniformLocation(myShaderBack->ID, "texture1"), 1);

    float max = 0;
    float min = 1;
    bool boo = true;
    float i = 0;
    glm::mat4 tran1,tran2;
    
    //********************************************************************************
    //渲染循环
    for (;!glfwWindowShouldClose(window); i = i + 0.0015)
    {
        //输入
        processInput(window);
        //渲染指令
        //清除颜色缓冲
        glClearColor(0.2f, 0.3f, 0.3f, 1.0f);
        glClear(GL_COLOR_BUFFER_BIT);
    
        glUseProgram(myShaderBack->ID);
        glBindVertexArray(VAO[0]);
        
        //背景
        glUniform1i(glGetUniformLocation(myShaderBack->ID, "flag"), 0);
        glUniform1f(glGetUniformLocation(myShaderBack->ID, "t"), 0.0f);
        glActiveTexture(GL_TEXTURE0);
        glBindTexture(GL_TEXTURE_2D, TexBuffer[2]);
        glDrawArrays(GL_TRIANGLE_FAN, 0, 4);

        if (boo==true) 
        {
            float temp = max * max * 0.64;//0.64
            float x = max * max * 0.14;//0.14

            glUniform1i(glGetUniformLocation(myShaderBack->ID, "flag"), 1);

            //牛郎
            glActiveTexture(GL_TEXTURE0);
            glBindTexture(GL_TEXTURE_2D, TexBuffer[0]);
            glm::mat4 trans;
            trans = glm::translate(trans, glm::vec3(temp, x, 0.0f));
            glUniformMatrix4fv(glGetUniformLocation(myShaderBack->ID, "transform"), 1, GL_FALSE, glm::value_ptr(trans));
            glUniform1f(glGetUniformLocation(myShaderBack->ID, "t"), 0.0f);
            glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
            if (max > sin(i)) { tran1=trans; }
            //织女    
            glActiveTexture(GL_TEXTURE0);
            glBindTexture(GL_TEXTURE_2D, TexBuffer[1]);
            trans = glm::mat4(1.0f);
            trans = glm::translate(trans, glm::vec3(-temp, x, 0.0f));
            glUniformMatrix4fv(glGetUniformLocation(myShaderBack->ID, "transform"), 1, GL_FALSE, glm::value_ptr(trans));
            glUniform1f(glGetUniformLocation(myShaderBack->ID, "t"), 0.0f);
            glDrawArrays(GL_TRIANGLE_FAN, 0, 4);

            if (max <= sin(i)) { max = sin(i); }
            else { boo = false; tran2 = trans; }
        }
         if (boo == false)

        {
            glUniform1i(glGetUniformLocation(myShaderBack->ID, "flag"), 1);
            glActiveTexture(GL_TEXTURE0);
            glBindTexture(GL_TEXTURE_2D, TexBuffer[0]);
            glActiveTexture(GL_TEXTURE1);
            glBindTexture(GL_TEXTURE_2D, TexBuffer[4]);
            glUniformMatrix4fv(glGetUniformLocation(myShaderBack->ID, "transform"), 1, GL_FALSE, glm::value_ptr(tran1));
            glUniform1f(glGetUniformLocation(myShaderBack->ID, "t"), -min*min+1);//这里是二次函数,三角函数也行
            glDrawArrays(GL_TRIANGLE_FAN, 0, 4);

            glActiveTexture(GL_TEXTURE0);
            glBindTexture(GL_TEXTURE_2D, TexBuffer[1]);
            glActiveTexture(GL_TEXTURE1);
            glBindTexture(GL_TEXTURE_2D, TexBuffer[5]);
            glUniformMatrix4fv(glGetUniformLocation(myShaderBack->ID, "transform"), 1, GL_FALSE, glm::value_ptr(tran2));
            glUniform1f(glGetUniformLocation(myShaderBack->ID, "t"), -min * min + 1);
            glDrawArrays(GL_TRIANGLE_FAN, 0, 4);

            if (min >= sin(i)) { min = sin(i); }
            else { boo = true; min = 1; max = -1; }
            
        }
        //检查并调用事件,交换缓冲
        glfwSwapBuffers(window);
        glfwPollEvents();

    }

三、位移->变形->反变形->反位移

我们仍需做一些工作来实现更好的动画效果。
1.每次绘制仅需两张图片,激活两个纹理单元即可。
2.发现glfwgettime()的局限性,第一次绘制时间大约0.9s,不在初始位置,故换成自设值max、min
3.为实现位移和变形的转变,设置布尔值首先判定进行哪种操作。当一种活动完毕,调成另一个模式进行。用max、min和sin函数比较来确立,利用了三角函数的周期性。
4.为实现位移内部和变形内部的往复效果,插值t和位移都使用了二次函数,利用了二次函数的对称性。

二次函数和三角函数都具有对称性。若增加一个判定值,当二次函数到某一点回到其对称位置,则二次函数具有了周期性。

此次实验综合运用了PS、三角函数、矩阵和算法逻辑等知识。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 217,406评论 6 503
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,732评论 3 393
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 163,711评论 0 353
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,380评论 1 293
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,432评论 6 392
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,301评论 1 301
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,145评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,008评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,443评论 1 314
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,649评论 3 334
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,795评论 1 347
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,501评论 5 345
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,119评论 3 328
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,731评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,865评论 1 269
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,899评论 2 370
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,724评论 2 354

推荐阅读更多精彩内容