Search code examples
opengl-esglslfragment-shadervertex-shader

GLSL Shader - Coverflow Reflection of a 2D object


I want to write a shader that creates a reflection of an image similiar to the ones used for coverflows.

// Vertex Shader
uniform highp mat4 u_modelViewMatrix;
uniform highp mat4 u_projectionMatrix;
attribute highp vec4 a_position;
attribute lowp vec4 a_color;
attribute highp vec2 a_texcoord;
varying lowp vec4 v_color;
varying highp vec2 v_texCoord;
mat4 rot = mat4( -1.0, 0.0, 0.0, 0.0,
                  0.0, -1.0, 0.0, 0.0,
                  0.0, 0.0, 1.0, 0.0,
                  0.0, 0.0, 0.0, 1.0 );
void main()
{
  gl_Position = (u_projectionMatrix * u_modelViewMatrix) * a_position * rot;
  v_color = a_color;
  v_texCoord = a_texcoord;
}

// Fragment Shader
varying highp vec2 v_texCoord;
uniform sampler2D u_texture0;
uniform int slices;
void main()
{
  lowp vec3 w = vec3(1.0,1.0,1.0);
  lowp vec3 b = vec3(0.0,0.0,0.0);
  lowp vec3 mix = mix(b, w, (v_texCoord.y-(float(slices)/10.0)));
  gl_FragColor = texture2D(u_texture0,v_texCoord) * vec4(mix, 1.0);
}

But this shader is creating the following: current result And I dont know how to "flip" the image horizontally and I tried so many different parameters in the rotation matrix (I even tried to use a so called "mirror matrix") but I dont know how to reflect the image on the bottom of original image.


Solution

  • If you're talking about what images.google.com returns for "coverflow" result, then you don't need rotation matrix at all.

    void main()
    {
      gl_Position = (u_projectionMatrix * u_modelViewMatrix) * a_position;
      v_color = a_color;
      v_texCoord = vec2(a_texcoord.x, 1.0 - a_texcoord.y);
    }
    

    Simply flip it vertically.

    If you insist on using matrix and want to make a "mirror" shader (the one that takes it object, and puts it under "floor" to make reflection) then you need mirror matrix (don't forget to adjust frontface/backface culling):

    mat4(1.0, 0.0, 0.0, 0.0,
        0.0, -1.0, 0.0, 0.0,
        0.0, 0.0, 1.0, 0.0,
        0.0, 0.0, 0.0, 1.0 );
    

    AND you must know where the floor is.

    gl_Position = (u_projectionMatrix * u_modelViewMatrix) * (a_position * mirrorMatrix - floor);
    

    Alternatively you could put floor translation into same matrix. Basically, to mirror against arbitrary height, you need to combine three transforms (pseudocode).

    translate(0, -floorHeight, 0) * scale(1, -1, 1) * translate(0, floorHeight, 0).

    and put them into your matrix.

    Also it might make sense to split modelView matrix into "model"(object/world) and "view" matrices. This way it'll be easier to perform transformations like these.