iOS OpenGL ES 视频 shader模仿抖音缩放、灵魂
2019-07-21 本文已影响0人
如意神王
1.直接上代码,原理与上一篇图片的是完全一致的,只不过视频的是Y和UV两个纹理,preferredRotation这个是纹理旋转的角度,Time依然是CADisplayLink的时间差,本来想获取视频解码后的CMTime,但是,没有取到值,都是0或者1
2.缩放
1.顶点着色器代码
attribute vec4 position;
attribute vec2 texCoord;
varying vec2 varyingTextureCoordinate;
uniform float preferredRotation;
void main () {
mat4 rotationMatrix = mat4(cos(preferredRotation), -sin(preferredRotation),
0.0, 0.0,
sin(preferredRotation), cos(preferredRotation),
0.0, 0.0,
0.0, 0.0, 1.0,0.0,
0.0, 0.0, 0.0, 1.0);
gl_Position = position * rotationMatrix;
varyingTextureCoordinate = texCoord;
}
2.片元着色器代码
uniform sampler2D SamplerY;
uniform sampler2D SamplerUV;
uniform mat3 colorConversionMatrix;
varying vec2 varyingTextureCoordinate;
uniform float Time;
const float PI = 3.1415926;
void main() {
mediump vec3 yuv;
lowp vec3 rgb;
vec2 changeTextureCoordinate = varyingTextureCoordinate;
float duration = 0.6;
float maxAmplitude = 0.3;
float time = mod(Time, duration);
float amplitude = 1.0 - maxAmplitude * abs(sin(time * (PI / duration)));
changeTextureCoordinate = vec2(changeTextureCoordinate.x * amplitude, changeTextureCoordinate.y * amplitude);
yuv.x = texture2D(SamplerY, changeTextureCoordinate).r - (16.0 / 255.0);
yuv.yz = texture2D(SamplerUV, changeTextureCoordinate).rg - vec2(0.5, 0.5);
rgb = colorConversionMatrix * yuv;
gl_FragColor = vec4(rgb, 1.0);
}
3.闪白
1.顶点着色器代码
attribute vec4 position;
attribute vec2 texCoord;
varying vec2 varyingTextureCoordinate;
uniform float preferredRotation;
void main () {
mat4 rotationMatrix = mat4(cos(preferredRotation), -sin(preferredRotation),
0.0, 0.0,
sin(preferredRotation), cos(preferredRotation),
0.0, 0.0,
0.0, 0.0, 1.0,0.0,
0.0, 0.0, 0.0, 1.0);
gl_Position = position * rotationMatrix;
varyingTextureCoordinate = texCoord;
}
2.片元着色器代码
precision highp float;
uniform sampler2D SamplerY;
uniform sampler2D SamplerUV;
uniform mat3 colorConversionMatrix;
varying vec2 varyingTextureCoordinate;
uniform float Time;
const float PI = 3.1415926;
void main() {
highp vec3 yuv;
highp vec3 rgb;
yuv.x = texture2D(SamplerY, varyingTextureCoordinate).r - (16.0 / 255.0);
yuv.yz = texture2D(SamplerUV, varyingTextureCoordinate).rg - vec2(0.5, 0.5);
rgb = colorConversionMatrix * yuv;
float duration = 0.6;
float time = mod(Time, duration);
vec3 whiteMask = vec3(1.0, 1.0, 1.0);
float amplitude = abs(sin(time * (PI / duration)));
rgb = rgb * (1.0 - amplitude) + whiteMask * amplitude;
gl_FragColor = vec4(rgb, 1.0);
}
3.抖动
1.顶点着色器代码
attribute vec4 position;
attribute vec2 texCoord;
varying vec2 varyingTextureCoordinate;
uniform float preferredRotation;
void main () {
mat4 rotationMatrix = mat4(cos(preferredRotation), -sin(preferredRotation),
0.0, 0.0,
sin(preferredRotation), cos(preferredRotation),
0.0, 0.0,
0.0, 0.0, 1.0,0.0,
0.0, 0.0, 0.0, 1.0);
gl_Position = position * rotationMatrix;
varyingTextureCoordinate = texCoord;
}
2.片元着色器代码
precision highp float;
uniform sampler2D SamplerY;
uniform sampler2D SamplerUV;
uniform mat3 colorConversionMatrix;
varying vec2 varyingTextureCoordinate;
uniform float Time;
void main() {
highp vec3 yuv;
highp vec3 rgb;
highp vec3 yuvR;
highp vec3 rgbR;
highp vec3 yuvB;
highp vec3 rgbB;
//一次抖动滤镜的时长 0.7
float duration = 0.7;
//放大图片上限
float maxScale = 1.1;
//颜色偏移步长
float offset = 0.02;
//进度[0,1]
float progress = mod(Time, duration) / duration; // 0~1
//颜色偏移值范围[0,0.02]
vec2 offsetCoords = vec2(offset, offset) * progress;
//缩放范围[1.0-1.1];
float scale = 1.0 + (maxScale - 1.0) * progress;
//放大纹理坐标.
vec2 ScaleTextureCoords = vec2(0.5, 0.5) + (varyingTextureCoordinate - vec2(0.5, 0.5)) / scale;
//获取3组颜色rgb
//从3组来获取颜色:
//maskR.r,mask.g,maskB.b 注意这3种颜色取值可以打乱或者随意发挥.不一定写死.只是效果会有不一样.大家可以试试.
//mask.a 获取原图的透明度
//原始颜色+offsetCoords
yuvR.x = texture2D(SamplerY, ScaleTextureCoords + offsetCoords).r - (16.0 / 255.0);
yuvR.yz = texture2D(SamplerUV, ScaleTextureCoords + offsetCoords).rg - vec2(0.5, 0.5);
rgbR = colorConversionMatrix * yuvR;
//原始颜色
yuv.x = texture2D(SamplerY, ScaleTextureCoords).r - (16.0 / 255.0);
yuv.yz = texture2D(SamplerUV, ScaleTextureCoords).rg - vec2(0.5, 0.5);
rgb = colorConversionMatrix * yuv;
//原始颜色-offsetCoords
yuvB.x = texture2D(SamplerY, ScaleTextureCoords - offsetCoords).r - (16.0 / 255.0);
yuvB.yz = texture2D(SamplerUV, ScaleTextureCoords - offsetCoords).rg - vec2(0.5, 0.5);
rgbB = colorConversionMatrix * yuvB;
gl_FragColor = vec4(rgbR.r, rgb.g, rgbB.b, 1.0);
}
4.毛刺
1.顶点着色器代码
attribute vec4 position;
attribute vec2 texCoord;
varying vec2 varyingTextureCoordinate;
uniform float preferredRotation;
void main () {
mat4 rotationMatrix = mat4(cos(preferredRotation), -sin(preferredRotation),
0.0, 0.0,
sin(preferredRotation), cos(preferredRotation),
0.0, 0.0,
0.0, 0.0, 1.0,0.0,
0.0, 0.0, 0.0, 1.0);
gl_Position = position * rotationMatrix;
varyingTextureCoordinate = texCoord;
}
2.片元着色器代码
precision highp float;
uniform sampler2D SamplerY;
uniform sampler2D SamplerUV;
uniform mat3 colorConversionMatrix;
varying vec2 varyingTextureCoordinate;
uniform float Time;
const float PI = 3.1415926;
float rand(float n) {
return fract(sin(n) * 43758.5453123);
}
void main() {
highp vec3 yuv;
highp vec3 rgb;
highp vec3 yuvR;
highp vec3 rgbR;
highp vec3 yuvB;
highp vec3 rgbB;
//最大抖动
float maxJitter = 0.06;
//一次毛刺滤镜的时长
float duration = 0.3;
//红色颜色偏移量
float colorROffset = 0.01;
//绿色颜色偏移量
float colorBOffset = -0.025;
//时间周期[0.0,0.6];
float time = mod(Time, duration * 2.0);
//振幅:[0,1];
float amplitude = max(sin(time * (PI / duration)), 0.0);
//像素随机偏移[-1,1]
float jitter = rand(varyingTextureCoordinate.y) * 2.0 - 1.0; // -1~1
//是否要做偏移.
bool needOffset = abs(jitter) < maxJitter * amplitude;
//获取纹理X值.根据needOffset,来计算它X撕裂.
//needOffset = YES ,撕裂较大;
//needOffset = NO,撕裂较小.
float textureX = varyingTextureCoordinate.x + (needOffset ? jitter : (jitter * amplitude * 0.006));
//撕裂后的纹理坐标x,y
vec2 textureCoords = vec2(textureX, varyingTextureCoordinate.y);
//撕裂后的纹理颜色偏移
yuvR.x = texture2D(SamplerY, textureCoords + vec2(colorROffset * amplitude, 0.0)).r - (16.0 / 255.0);
yuvR.yz = texture2D(SamplerUV, textureCoords + vec2(colorROffset * amplitude, 0.0)).rg - vec2(0.5, 0.5);
rgbR = colorConversionMatrix * yuvR;
//根据撕裂后获取的纹理颜色值
yuv.x = texture2D(SamplerY, textureCoords).r - (16.0 / 255.0);
yuv.yz = texture2D(SamplerUV, textureCoords).rg - vec2(0.5, 0.5);
rgb = colorConversionMatrix * yuv;
//撕裂后的纹理颜色偏移
yuvB.x = texture2D(SamplerY, textureCoords + vec2(colorBOffset * amplitude, 0.0)).r - (16.0 / 255.0);
yuvB.yz = texture2D(SamplerUV, textureCoords + vec2(colorBOffset * amplitude, 0.0)).rg - vec2(0.5, 0.5);
rgbB = colorConversionMatrix * yuvB;
//红色/蓝色部分发生撕裂.
gl_FragColor = vec4(rgbR.r, rgb.g, rgbB.b, 1.0);
}
5.灵魂出窍
1.顶点着色器代码
attribute vec4 position;
attribute vec2 texCoord;
varying vec2 varyingTextureCoordinate;
uniform float preferredRotation;
void main () {
mat4 rotationMatrix = mat4(cos(preferredRotation), -sin(preferredRotation),
0.0, 0.0,
sin(preferredRotation), cos(preferredRotation),
0.0, 0.0,
0.0, 0.0, 1.0,0.0,
0.0, 0.0, 0.0, 1.0);
gl_Position = position * rotationMatrix;
varyingTextureCoordinate = texCoord;
}
2.片元着色器代码
precision highp float;
uniform sampler2D SamplerY;
uniform sampler2D SamplerUV;
uniform mat3 colorConversionMatrix;
varying vec2 varyingTextureCoordinate;
uniform float Time;
void main() {
highp vec3 yuv;
highp vec3 rgb;
highp vec3 yuvWeak;
highp vec3 rgbWeak;
float duration = 0.7;
float maxAlpha = 0.4;
float maxScale = 1.8;
float progress = mod(Time, duration) / duration; // 0~1
float alpha = maxAlpha * (1.0 - progress);
float scale = 1.0 + (maxScale - 1.0) * progress;
float weakX = 0.5 + (varyingTextureCoordinate.x - 0.5) / scale;
float weakY = 0.5 + (varyingTextureCoordinate.y - 0.5) / scale;
vec2 weakTextureCoords = vec2(weakX, weakY);
yuv.x = texture2D(SamplerY, varyingTextureCoordinate).r - (16.0 / 255.0);
yuv.yz = texture2D(SamplerUV, varyingTextureCoordinate).rg - vec2(0.5, 0.5);
rgb = colorConversionMatrix * yuv;
yuvWeak.x = texture2D(SamplerY, weakTextureCoords).r - (16.0 / 255.0);
yuvWeak.yz = texture2D(SamplerUV, weakTextureCoords).rg - vec2(0.5, 0.5);
rgbWeak = colorConversionMatrix * yuvWeak;
vec3 blendColor = rgb * (1.0 - alpha) + rgbWeak * rgbWeak;
gl_FragColor = vec4(blendColor, 1.0);
}
5.幻觉
1.顶点着色器代码
attribute vec4 position;
attribute vec2 texCoord;
varying vec2 varyingTextureCoordinate;
uniform float preferredRotation;
void main () {
mat4 rotationMatrix = mat4(cos(preferredRotation), -sin(preferredRotation),
0.0, 0.0,
sin(preferredRotation), cos(preferredRotation),
0.0, 0.0,
0.0, 0.0, 1.0,0.0,
0.0, 0.0, 0.0, 1.0);
gl_Position = position * rotationMatrix;
varyingTextureCoordinate = texCoord;
}
2.片元着色器代码
precision highp float;
uniform sampler2D SamplerY;
uniform sampler2D SamplerUV;
uniform mat3 colorConversionMatrix;
varying vec2 varyingTextureCoordinate;
uniform float Time;
const float PI = 3.1415926;
const float duration = 2.0;
vec4 getMask(float time, vec2 textureCoords, float padding) {
vec2 translation = vec2(sin(time * (PI * 2.0 / duration)),
cos(time * (PI * 2.0 / duration)));
vec2 translationTextureCoords = textureCoords + padding * translation;
highp vec3 yuv;
highp vec3 rgb;
//根据撕裂后获取的纹理颜色值
yuv.x = texture2D(SamplerY, translationTextureCoords).r - (16.0 / 255.0);
yuv.yz = texture2D(SamplerUV, translationTextureCoords).rg - vec2(0.5, 0.5);
rgb = colorConversionMatrix * yuv;
return vec4(rgb, 1.0);
}
float maskAlphaProgress(float currentTime, float hideTime, float startTime) {
float time = mod(duration + currentTime - startTime, duration);
return min(time, hideTime);
}
void main (void) {
float time = mod(Time, duration);
float scale = 1.2;
float padding = 0.5 * (1.0 - 1.0 / scale);
vec2 textureCoords = vec2(0.5, 0.5) + (varyingTextureCoordinate - vec2(0.5, 0.5)) / scale;
float hideTime = 0.9;
float timeGap = 0.2;
float maxAlphaR = 0.5; // max R
float maxAlphaG = 0.05; // max G
float maxAlphaB = 0.05; // max B
vec4 mask = getMask(time, textureCoords, padding);
float alphaR = 1.0; // R
float alphaG = 1.0; // G
float alphaB = 1.0; // B
vec4 resultMask = vec4(0, 0, 0, 0);
for (float f = 0.0; f < duration; f += timeGap) {
float tmpTime = f;
vec4 tmpMask = getMask(tmpTime, textureCoords, padding);
float tmpAlphaR = maxAlphaR - maxAlphaR * maskAlphaProgress(time, hideTime, tmpTime) / hideTime;
float tmpAlphaG = maxAlphaG - maxAlphaG * maskAlphaProgress(time, hideTime, tmpTime) / hideTime;
float tmpAlphaB = maxAlphaB - maxAlphaB * maskAlphaProgress(time, hideTime, tmpTime) / hideTime;
resultMask += vec4(tmpMask.r * tmpAlphaR,
tmpMask.g * tmpAlphaG,
tmpMask.b * tmpAlphaB,
1.0);
alphaR -= tmpAlphaR;
alphaG -= tmpAlphaG;
alphaB -= tmpAlphaB;
}
resultMask += vec4(mask.r * alphaR, mask.g * alphaG, mask.b * alphaB, 1.0);
gl_FragColor = resultMask;
}
6.补充
前置摄像头的时候图像是左右相反的,需要在顶点着色器里面对position.x 取反后再赋值,且不能直接对position值进行修改,且还需要一个标志位传递到顶点着色器里面去, uniform属性即可
// OK
vec4 newPosition = vec4(-position.x, position.y, position.z, position.w);
gl_Position = newPosition * rotationMatrix;
// Error
position = vec4(-position.x, position.y, position.z, position.w);
gl_Position = position * rotationMatrix;