Java-Gaming.org Hi !
Featured games (91)
games approved by the League of Dukes
Games in Showcase (804)
Games in Android Showcase (239)
games submitted by our members
Games in WIP (868)
games currently in development
News: Read the Java Gaming Resources, or peek at the official Java tutorials
 
    Home     Help   Search   Login   Register   
Pages: [1]
  ignore  |  Print  
  [GLSL] Simple, fast bicubic filtering shader function  (Read 16409 times)
0 Members and 1 Guest are viewing this topic.
Offline theagentd
« Posted 2014-12-17 21:05:33 »

Hello.

I ended up implementing a very simple bicubic texture filtering shader and thought I might as well share it here.



Screenshot comparison of bilinear and bicubic filtering (mouse over to switch to bicubic)
 - Fire particle
 - Noise texture


Code
1  
2  
3  
4  
5  
6  
7  
8  
9  
10  
11  
12  
13  
14  
15  
16  
17  
18  
19  
20  
21  
22  
23  
24  
25  
26  
27  
28  
29  
30  
31  
32  
33  
34  
35  
36  
37  
38  
39  
40  
41  
42  
43  
vec4 cubic(float v){
    vec4 n = vec4(1.0, 2.0, 3.0, 4.0) - v;
    vec4 s = n * n * n;
    float x = s.x;
    float y = s.y - 4.0 * s.x;
    float z = s.z - 4.0 * s.y + 6.0 * s.x;
    float w = 6.0 - x - y - z;
    return vec4(x, y, z, w) * (1.0/6.0);
}

vec4 textureBicubic(sampler2D sampler, vec2 texCoords){

   vec2 texSize = textureSize(tex, 0);
   vec2 invTexSize = 1.0 / texSize;
   
   texCoords = texCoords * texSize - 0.5;

   
    vec2 fxy = fract(texCoords);
    texCoords -= fxy;

    vec4 xcubic = cubic(fxy.x);
    vec4 ycubic = cubic(fxy.y);

    vec4 c = texCoords.xxyy + vec2(-0.5, +1.5).xyxy;
   
    vec4 s = vec4(xcubic.xz + xcubic.yw, ycubic.xz + ycubic.yw);
    vec4 offset = c + vec4(xcubic.yw, ycubic.yw) / s;
   
    offset *= invTexSize.xxyy;
   
    vec4 sample0 = texture(sampler, offset.xz);
    vec4 sample1 = texture(sampler, offset.yz);
    vec4 sample2 = texture(sampler, offset.xw);
    vec4 sample3 = texture(sampler, offset.yw);

    float sx = s.x / (s.x + s.y);
    float sy = s.z / (s.z + s.w);

    return mix(
       mix(sample3, sample2, sx), mix(sample1, sample0, sx)
    , sy);
}


Usage
1.
Simply add the above code into your GLSL shader source code just before your main() function. Alternatively, you can add
#version 130
above it and put it in its own file. Then you attach both that shader and your shader program that contains main() to your shader program. To be able to use the function in your other shader, you need to define it by adding
vec4 textureBicubic(sampler2D texture, vec2 texCoords);
. Note that the code uses textureSize() to retrieve the size of the texture for convenience, which requires GLSL version 130 (OGL 3.0). It's possible to replace this with a uniform variable through which you manually pass in the texture's size which would make the shader work on OGL2 hardware as well.

2.
In your shader, simply replace your calls to
texture(mySampler, myTexCoords)
with
textureBicubic(mySampler, myTexCoords)
. Yep, it's that simple.

3.
Make sure your texture has bilinear filtering enabled (GL_LINEAR or the mipmapped versions of it)! The shader abuses bilinearly filtered samples to improve performance (4 taps instead of 16).


Notes
Because the shader uses texture() calls instead of texelFetch(), the shader obeys any and all texture parameters you set. The shader works with texture coordinate wrapping and clamping as it should and even works with mipmaps, trilinear filtering and even anisotropic filtering, although when using mipmaps the texture size will not be correct when the texture is minified, which if I understand the code correct means that the shader essentially falls back to bilinear filtering, which hopefully should be a bit sharper when you have a large resolution texture.


Technical details
Bicubic filtering is done by basing the result on the 4x4 area of texels around the sample point. This should require 16 texture samples and then some rather complex blending math between them, which would have a noticeable performance cost. This shader is inspired by this post and relies on the fact that bilinear filtering gives us a weighted average of texels in a 2x2 area. By sampling 4 bilinear samples with carefully modified offsets and how we combine these 4 samples, we can get the correct weights for all 16 texels we need. The result is an extremely fast bicubic filtering function that only requires 4 texture samples.

Myomyomyo.
Offline theagentd
« Reply #1 - Posted 2015-01-03 00:13:45 »

In case anyone's wondering, I have a bicubic shader which also does manual (linear) filtering between mipmap levels as well to 100% correctly filter mipmaps as well.

Myomyomyo.
Offline KudoDEV

JGO Ninja


Medals: 79
Exp: 6 years


Game Dev Hobbyist


« Reply #2 - Posted 2015-01-03 00:35:58 »

Ooo thanks for the share!

Pages: [1]
  ignore  |  Print  
 
 

 
Riven (579 views)
2019-09-04 15:33:17

hadezbladez (5501 views)
2018-11-16 13:46:03

hadezbladez (2398 views)
2018-11-16 13:41:33

hadezbladez (5761 views)
2018-11-16 13:35:35

hadezbladez (1220 views)
2018-11-16 13:32:03

EgonOlsen (4660 views)
2018-06-10 19:43:48

EgonOlsen (5681 views)
2018-06-10 19:43:44

EgonOlsen (3196 views)
2018-06-10 19:43:20

DesertCoockie (4094 views)
2018-05-13 18:23:11

nelsongames (5114 views)
2018-04-24 18:15:36
A NON-ideal modular configuration for Eclipse with JavaFX
by philfrei
2019-12-19 19:35:12

Java Gaming Resources
by philfrei
2019-05-14 16:15:13

Deployment and Packaging
by philfrei
2019-05-08 15:15:36

Deployment and Packaging
by philfrei
2019-05-08 15:13:34

Deployment and Packaging
by philfrei
2019-02-17 20:25:53

Deployment and Packaging
by mudlee
2018-08-22 18:09:50

Java Gaming Resources
by gouessej
2018-08-22 08:19:41

Deployment and Packaging
by gouessej
2018-08-22 08:04:08
java-gaming.org is not responsible for the content posted by its members, including references to external websites, and other references that may or may not have a relation with our primarily gaming and game production oriented community. inquiries and complaints can be sent via email to the info‑account of the company managing the website of java‑gaming.org
Powered by MySQL Powered by PHP Powered by SMF 1.1.18 | SMF © 2013, Simple Machines | Managed by Enhanced Four Valid XHTML 1.0! Valid CSS!