抖音灵魂出窍效果实现原理解析

目前实现视频特效都是用的opengles,不了解opengles的同学请自行学习,opengles在2.0以后出了着色器语言,顶点着色器和片元着色器,可以让开发者在Gpu渲染的时候实现对图形的颜色和形体的控制。

不管是在录屏还是在播放视频,都可以通过EGL和Gpu产生关系将像素显示到屏幕上组成一张张绚丽的图像,或者直接用GLSurfaceView(封装好的EGL)。

opengles顶点着色器支持的颜色是rgba的,而解析的视频手机端常用NV21 / YV12格式,所以在传到着色器处理的时候应该转换一下。

在恐怖电影或电视剧中,常常有灵魂出窍的桥段,一般可以看见都是透明的形体慢慢从身体里飘出。那么想实现灵魂离体的效果的话,只要将原来的人物画到屏幕上,然后再画灵魂,复制形体的每一个像素采用opengles的混合效果,不断的动态改变灵魂的透明度,并用模型矩阵不断的放大形体产生飘出的效果。这个就是实现抖音灵魂出窍的原理。

下面来看一下主要代码的实现:

    //画灵魂
        GLES20.glEnable(GLES20.GL_BLEND);
        //1:源 灵魂  GL_ONE:画灵魂自己
        //2: 肉体  也是肉体自己
        //两个都是用自己原本的颜色去混合
//        GLES20.glBlendFunc(GLES20.GL_ONE,GLES20.GL_ONE);
        //让灵魂整体颜色变淡
        // GL_SRC_ALPHA: 取源(灵魂)的alpha 作为因子
        // 假设alpha是0.2 rgb都是1 -> 混合就是用 rgb都是 0.2*1 整体变淡
        GLES20.glBlendFunc(GLES20.GL_SRC_ALPHA,GLES20.GL_ONE);

        //初始化矩阵 不进行任何缩放平移
        Matrix.setIdentityM(matrix,0);
    //设置缩放大小 本次放大为 1+当前灵魂次数占总次数*2的比例
        //不一次放太大 为了达到较好的表现效果 fps*2
        //所以这里值为 1+1/60 ---> 1+20/40 1.025... ---> 1.5
        float scale = 1.0f + interval / (mFps * 2.f);
        Matrix.scaleM(matrix,0,scale,scale,0);
        //给肉体的 无变化矩阵
        GLES20.glUniformMatrix4fv(vMatrix,1,false,matrix,0);


        //传递透明度 透明度值为0-1 渐渐降低 0.1+x/100 x为fps-[0~fps]
        //这里值为0.29 ---> 0.1
        GLES20.glUniform1f(mAlpha, 0.1f + (mFps - interval) / 100.f);

实现不断的形体放大和透明度越来越淡,代码还容易懂,下面是片元着色器代码

precision mediump float;

varying vec2 aCoord;
//byte[] -》 分离出yuv ?

uniform sampler2D sampler_y; //yuv
uniform sampler2D sampler_u;
uniform sampler2D sampler_v;

//透明度
uniform float alpha;

void main(){
    //4个float数据 y、u、v保存在向量中的第一个
    float y = texture2D(sampler_y,aCoord).r;
    float u = texture2D(sampler_u,aCoord).r - 0.5;
    float v = texture2D(sampler_v,aCoord).r - 0.5;
    // yuv转rgb的公式
    //R = Y + 1.402 (v-128)
    //G = Y - 0.34414 (u - 128) - 0.71414 (v-128)
    //B = Y + 1.772 (u- 128)
    vec3 rgb;
    //u - 128
    //1、glsl中 不能直接将int与float进行计算
    //2、rgba取值都是:0-1 (128是0-255 归一化为0-1 128就是0.5)
    rgb.r = y + 1.402 * v;
    rgb.g = y - 0.34414 * u - 0.71414* v;
    rgb.b = y + 1.772 * u;
    //rgba
    gl_FragColor = vec4(rgb,alpha);
}

将yuv12转化为rgb,并合成透明度,下面是顶点着色器:

//画肉体 base_vertex就可以了
//还要画灵魂
attribute vec4 vPosition;
attribute vec2 vCoord;
varying vec2 aCoord;

uniform mat4 vMatrix;

void main(){
     gl_Position = vMatrix * vPosition;
       // 进过测试 和设备有关(有些设备直接就采集不到图像,有些呢则会镜像)
     aCoord =  vCoord;
}

很简单总变换矩阵和顶点作用改变形体的大小、位置、角度等等。

想要完整代码的朋友请留言联系。

 

 

 

 

 

 

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值