1
\$\begingroup\$

Right now I am using the following two shaders to render a sprite from a texture used as a sprite atlas onto a canvas that has canvas_size pixels in screen coordinates.

I use a static quad as input vertex coordinates form (0,0) to (1,1) and pass the actual position of the sprite onscreen within the uniform buffer to the shader and call a single glDrawElements for each sprite to draw.

 #version 300 es
 layout(std140) uniform Environment {
    vec2 canvas_size;
 };
 layout(std140) uniform Sprite {
    vec2 sprite_position;
    vec2 sprite_size;
    float sprite_rotation;
 };
 layout(std140) uniform Texture {
    vec2 position_in_texture;
    vec2 size_in_texture;
 };
 layout(location=0) in vec2 vertex;
 out vec2 texture_coordinate;
 void main(){
    /* y is flipped because pictures have their origin at the upper left corner
     * but textures have them at the lower left ... */
    texture_coordinate = vec2(position_in_texture.x + vertex.x * size_in_texture.x,
                         1.0 - (position_in_texture.y + vertex.y * size_in_texture.y));
    vec4 pos = vec4(vertex, -1.0, 1.0);
    /* Rotate sprite around it's center */
    mat4 rotate = mat4( cos(sprite_rotation), -sin(sprite_rotation), 0.0, 0.0,
                        sin(sprite_rotation), cos(sprite_rotation), 0.0, 0.0, 
                        0.0, 0.0, 1.0, 0.0,
                        -0.5*cos(sprite_rotation)-0.5*(sin(sprite_rotation))+0.5, -0.5*cos(sprite_rotation)-0.5*(-sin(sprite_rotation))+0.5, 0.0, 1.0);
    /* Move the "stamp" for the sprite to the desired position onscreen */
    mat4 move = mat4(2.0 * sprite_size.x / canvas_size.x, 0.0, 0.0, 0.0,
                     0.0, -2.0 * sprite_size.y / canvas_size.y, 0.0, 0.0,
                     0.0, 0.0, 1.0, 0.0,
                     2.0 * sprite_position.x / canvas_size.x - 1.0, 1.0 - 2.0 * sprite_position.y / canvas_size.y, 0.0, 1.0);
    gl_Position = move * rotate * pos;
 }

Fragment Shader:

 #version 300 es
 precision highp float;
 uniform sampler2D color_map;
 in vec2 texture_coordinate;
 layout(std140) uniform Color {
    vec4 hue;
    vec4 filter_;
 };
 layout(location = 0) out vec4 out_color;
 void main() {
    vec4 tex_color = texture(color_map, texture_coordinate);
    if(tex_color.a == 0.0) {
        discard; /* For stenciling */
    }
    /* Apply a hue to the sprite */
    vec4 hue_color = vec4(mix(tex_color.rgb, hue.rgb, hue.a), tex_color.a);
    /* Apply a filter to the sprite */
    out_color = vec4(hue_color.r * filter_.r, hue_color.g * filter_.g, hue_color.b * filter_.b, hue_color.a * filter_.a);
 }

Since you always learn more and more about OpenGL and GLSL I just found out there are functions textureSize as well as texelFetch to get the size of the texture currently bound and a pixel of a texture at an exact position.

Now I am wondering if I can improve the semantics of my shader by using these functions instead of what I already use. As I am providing the position_in_texture and size_in_texture still in terms of float values, I'd like to also provide these values in pixel values and let the annoying texture coordinate calculation be done wholly by the shader. That can easily be done with textureSize and simple division I hope.

Also, for other shaders that build upon this basic framework to draw pixel perfect images at a pixel perfect position within my canvas, I'd like to be able to sample pixels around a pixel in a texture for blending and blur purposes.

How are fetchTexel pixels arranged? (0,0) at the bottom or top left?

Is there a performance loss using fetchTexel instead of texture?

Do you have any improvement ideas to what I already do, or implementation samples or ideas upon my existing code?

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Browse other questions tagged or ask your own question.