双三次插值算法的OpenGL实现
说明
最近写一个图像缩放的接口,考虑到自己有现成的OpenGL图像处理引擎,还是直接写shader用GPU实现方便。为了效果好一些,采用了双三次插值算法。
算法相关公式可参考这篇文章:
http://blog.csdn.net/lichengyu/article/details/8526629
代码
详细实现代码见:
https://github.com/jxt1234/Simple3D/blob/master/src/GL/GLBicubicWork.cpp
测试代码见:
https://github.com/jxt1234/Simple3D/blob/master/gltest/GLBitmapWorkTest.cpp
要集成到其他项目中,只需要 vertex shader 和 fragment shader 两部分的代码,毕竟不同的图像引擎在如何加载shader,如何传参数,如何上传纹理的逻辑都是不同的。
bicubic.vex
attribute vec4 pos;
attribute vec2 tex;
varying vec2 vTex;
void main(void)
{
gl_Position = pos;
vTex = tex;
}
生成的 fragment shader:
bicubic.fra
#ifdef GL_ES
precision mediump float;//用于手机上时需要添加此句
#endif
varying vec2 vTex;//纹理坐标,注意与 vertex shader 中的变量对应
uniform sampler2D buffer;
uniform float uUnit;//传入原图的宽
uniform float vUnit;//传入原图的高
float BiCubicPoly1(float x, float a)
{
x = abs(x);
float res = (a+float(2))*x*x*x - (a+float(3))*x*x + float(1);
return res;
}
float BiCubicPoly2(float x, float a)
{
x = abs(x);
float res = a*x*x*x - float(5)*a*x*x + float(8)*a*x - float(4)*a;
return res;
}
void main()
{
vec2 basic;
vec2 det;
basic = vTex*vec2(uUnit, vUnit) - vec2(0.5,0.5);
det = fract(basic);
gl_FragColor = vec4(0.0,0.0,0.0,0.0)
+BiCubicPoly2(det.x-float(-1), float(-0.5))*BiCubicPoly2(det.y-float(-1), float(-0.5))*texture2D(buffer, vTex + ( - det + vec2(float(-1), float(-1)))/vec2(uUnit, vUnit))
+BiCubicPoly2(det.x-float(-1), float(-0.5))*BiCubicPoly1(det.y-float(0), float(-0.5))*texture2D(buffer, vTex + ( - det + vec2(float(-1), float(0)))/vec2(uUnit, vUnit))
+BiCubicPoly2(det.x-float(-1), float(-0.5))*BiCubicPoly1(det.y-float(1), float(-0.5))*texture2D(buffer, vTex + ( - det + vec2(float(-1), float(1)))/vec2(uUnit, vUnit))
+BiCubicPoly2(det.x-float(-1), float(-0.5))*BiCubicPoly2(det.y-float(2), float(-0.5))*texture2D(buffer, vTex + ( - det + vec2(float(-1), float(2)))/vec2(uUnit, vUnit))
+BiCubicPoly1(det.x-float(0), float(-0.5))*BiCubicPoly2(det.y-float(-1), float(-0.5))*texture2D(buffer, vTex + ( - det + vec2(float(0), float(-1)))/vec2(uUnit, vUnit))
+BiCubicPoly1(det.x-float(0), float(-0.5))*BiCubicPoly1(det.y-float(0), float(-0.5))*texture2D(buffer, vTex + ( - det + vec2(float(0), float(0)))/vec2(uUnit, vUnit))
+BiCubicPoly1(det.x-float(0), float(-0.5))*BiCubicPoly1(det.y-float(1), float(-0.5))*texture2D(buffer, vTex + ( - det + vec2(float(0), float(1)))/vec2(uUnit, vUnit))
+BiCubicPoly1(det.x-float(0), float(-0.5))*BiCubicPoly2(det.y-float(2), float(-0.5))*texture2D(buffer, vTex + ( - det + vec2(float(0), float(2)))/vec2(uUnit, vUnit))
+BiCubicPoly1(det.x-float(1), float(-0.5))*BiCubicPoly2(det.y-float(-1), float(-0.5))*texture2D(buffer, vTex + ( - det + vec2(float(1), float(-1)))/vec2(uUnit, vUnit))
+BiCubicPoly1(det.x-float(1), float(-0.5))*BiCubicPoly1(det.y-float(0), float(-0.5))*texture2D(buffer, vTex + ( - det + vec2(float(1), float(0)))/vec2(uUnit, vUnit))
+BiCubicPoly1(det.x-float(1), float(-0.5))*BiCubicPoly1(det.y-float(1), float(-0.5))*texture2D(buffer, vTex + ( - det + vec2(float(1), float(1)))/vec2(uUnit, vUnit))
+BiCubicPoly1(det.x-float(1), float(-0.5))*BiCubicPoly2(det.y-float(2), float(-0.5))*texture2D(buffer, vTex + ( - det + vec2(float(1), float(2)))/vec2(uUnit, vUnit))
+BiCubicPoly2(det.x-float(2), float(-0.5))*BiCubicPoly2(det.y-float(-1), float(-0.5))*texture2D(buffer, vTex + ( - det + vec2(float(2), float(-1)))/vec2(uUnit, vUnit))
+BiCubicPoly2(det.x-float(2), float(-0.5))*BiCubicPoly1(det.y-float(0), float(-0.5))*texture2D(buffer, vTex + ( - det + vec2(float(2), float(0)))/vec2(uUnit, vUnit))
+BiCubicPoly2(det.x-float(2), float(-0.5))*BiCubicPoly1(det.y-float(1), float(-0.5))*texture2D(buffer, vTex + ( - det + vec2(float(2), float(1)))/vec2(uUnit, vUnit))
+BiCubicPoly2(det.x-float(2), float(-0.5))*BiCubicPoly2(det.y-float(2), float(-0.5))*texture2D(buffer, vTex + ( - det + vec2(float(2), float(2)))/vec2(uUnit, vUnit))
;
}